"Fossies" - the Fresh Open Source Software Archive

Member "FunctionCheck-3.2.0/src/share/fc_fifo.c" (26 May 2012, 13019 Bytes) of package /linux/privat/old/FunctionCheck-3.2.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * FunctionCheck profiler
    3  * (C) Copyright 2000-2012 Yannick Perret
    4  *
    5  *  This program is free software; you can redistribute it and/or
    6  *  modify it under the terms of the GNU General Public License as
    7  *  published by the Free Software Foundation; either version 2 of the
    8  *  License, or (at your option) any later version.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  *  General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19 
   20 /* fc_fifo: manage IPC buffer
   21 */
   22 
   23 /** general includes */
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #include <sys/ipc.h>
   27 #include <sys/shm.h>
   28 #include <string.h>
   29 #include <signal.h>
   30 #include <sys/types.h>
   31 #include <sys/time.h>
   32 #include <unistd.h>
   33 #include <errno.h>
   34 
   35 /** personnal includes **/
   36 #include "fc_fifo.h"
   37 #include "fc_semaphore.h"
   38 #include "fc_tools.h"
   39 
   40 /** For FC_INIT and FC_LDYN added into FC_FIFO structure. */
   41 /** Both are big-sized structures so they are not passed in
   42  *  fifo communication buffer, which has fixed-size elements,
   43  *  but embedded directly into the FC_FIFO control. */
   44 #include "fc_com.h"
   45 
   46 /** access for users **/
   47 #define FC_USER_ALL  ((1<<6)&(1<<7)&(1<<8))
   48 #define FC_GROUP_ALL ((1<<3)&(1<<4)&(1<<5))
   49 #define FC_OTHER_ALL ((1<<0)&(1<<1)&(1<<2))
   50 #define FC_ALL_ALL (FC_USER_ALL&FC_GROUP_ALL&FC_OTHER_ALL)
   51 
   52 #define MAX_LDYN    256
   53 
   54 #define ACQUIRE_LOCK()     {    if (!fifo->singleMode) \
   55                                       { \
   56                                             fc_semaphore_get((FC_Semaphore volatile*)(&(fifo->sem)), pid); \
   57                                       } \
   58                                   }
   59 
   60 #define RELEASE_LOCK()      {   if (!fifo->singleMode) \
   61                                       { \
   62                                             fc_semaphore_put((FC_Semaphore volatile*)(&(fifo->sem)), pid); \
   63                                       } \
   64                                   }
   65 
   66 #define SLEEP()               { \
   67                                       struct timeval tv; \
   68                                       tv.tv_sec = 0; \
   69                                       tv.tv_usec = 10000; \
   70                                       select(0, NULL, NULL, NULL, &tv); \
   71                                   }
   72 
   73 typedef struct
   74 {
   75     FC_INIT init;
   76     FC_LDYN ldyn[MAX_LDYN];
   77     FC_LDYN *lastLdynPtr;       // pointer to last ldyn[] structure read
   78     unsigned int numEntry;      // number of entries in data
   79     unsigned int entrySize;     // size of each entry in data
   80     unsigned int numData;       // number of available data
   81     unsigned int readIdx;       // index in data
   82     unsigned int writeIdx;      // index in data
   83     unsigned int singleMode;
   84     unsigned int refCount;      // reference count
   85     FC_Semaphore sem;
   86     unsigned char data[0];      // size is numEntry * entrySize
   87 } _fifo_control;
   88 
   89 /* create a shared memory buffer */
   90 static int fc_fifo_create_buffer(unsigned int size)
   91 {
   92     int ret;
   93 
   94     /* try to get a shared memory buffer with the given size */
   95     ret = shmget(IPC_PRIVATE, size, 0777);
   96 
   97     /* cannot process */
   98     if (ret < 0)
   99     {
  100         fc_message("cannot create shared buffer with size '%d'", size);
  101         fc_message("error returned: %s", strerror(errno));
  102         return (ret);
  103     }
  104 
  105     /* ok */
  106     fc_debug("shared buffer of size '%d' created (id=%d)", size, ret);
  107     return (ret);
  108 }
  109 
  110 /* connect to an existing FIFO. returns the FIFO or FC_FIFO_NDEF.
  111    the 'id' is the ID given by 'fc_fifo_create' */
  112 FC_FIFO fc_fifo_connect(unsigned int id)
  113 {
  114     void *ret;
  115 
  116     /* invalid argument */
  117     if ((int) id < 0)
  118     {
  119         fc_message("invalid shared buffer Id (%d)", id);
  120         return (NULL);
  121     }
  122 
  123     /* try to attach the buffer */
  124     ret = shmat(id, NULL, 0700);
  125     if ((ret == NULL) || (ret == (void*) - 1))
  126     {/* cannot process */
  127         fc_message("cannot attach shared buffer '%d'", id);
  128         fc_message("error returned: %s", strerror(errno));
  129         return (NULL);
  130     }
  131 
  132     /* ok */
  133     fc_debug("shared buffer '%d' mapped at %p", id, ret);
  134 
  135     /* reference ourself as client */
  136     ((_fifo_control*)ret)->refCount++;
  137 
  138     return (ret);
  139 }
  140 
  141 /* create a new FIFO. returns the FIFO or 'FC_FIFO_NDEF' on error
  142    'esize' is the size of each element in the buffer, and 'id' is set to
  143    the ID of the shared buffer, for connections. 'single' is TRUE
  144    if the FIFO will be used with only one writer, and FALSE if
  145    many writers can access the FIFO (with fc_fifo_write_single) */
  146 FC_FIFO fc_fifo_create(unsigned int elements, unsigned int esize, unsigned int *id, unsigned int single)
  147 {
  148     int ret;
  149     FC_FIFO mem;
  150 
  151     if (elements <= 4)
  152     {
  153         /* default size */
  154         elements = 32 * 1024;
  155     }
  156 
  157     /* get a shared buffer */
  158     ret = fc_fifo_create_buffer(elements * esize + sizeof (_fifo_control));
  159     *id = ret;
  160     /* error */
  161     if (ret < 0)
  162     {
  163         return (NULL);
  164     }
  165 
  166     /* attach the buffer */
  167     mem = fc_fifo_connect(ret);
  168     /* error */
  169     if (mem == NULL)
  170     {
  171         return (NULL);
  172     }
  173 
  174     memset(&((_fifo_control*)mem)->init, 0, sizeof(((_fifo_control*)mem)->init));
  175     memset(&((_fifo_control*)mem)->ldyn, 0, sizeof(((_fifo_control*)mem)->ldyn));
  176 
  177     /* initialize the control part of the buffer */
  178     ((_fifo_control*) mem)->numEntry = elements;
  179     ((_fifo_control*) mem)->entrySize = esize;
  180     ((_fifo_control*) mem)->numData = 0;
  181     ((_fifo_control*) mem)->readIdx = 0;
  182     ((_fifo_control*) mem)->writeIdx = 0;
  183     ((_fifo_control*) mem)->singleMode = single;
  184     ((_fifo_control*)mem)->refCount = 1;
  185     fc_semaphore_init(&(((_fifo_control*) mem)->sem));
  186 
  187     /* ok */
  188     return (mem);
  189 }
  190 
  191 /* deconnect the given FIFO. once done, no more access to the FIFO
  192    is possible.
  193    delete flag if shm has no more reference. */
  194 int fc_fifo_close(FC_FIFO buffer, unsigned int shmid, unsigned int delete)
  195 {
  196     unsigned int ref;
  197     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  198 
  199     ref = fifo->refCount;
  200     if (ref == 0)
  201     {
  202         fc_message("Closing fifo with reference count of 0! (must be 1 minimum).\n");
  203     }
  204     else
  205     {
  206         /* remove our reference */
  207         ref = --fifo->refCount;
  208     }
  209 
  210     /* detach the buffer */
  211     shmdt((const void*)fifo);
  212 
  213     /* delete shared memory */
  214     if (delete && ref == 0)
  215         shmctl(shmid, IPC_RMID, NULL);
  216 
  217     return (1);
  218 }
  219 
  220 /* Return direct pointer to data instead of copying to user buffer.
  221    Returns FALSE if EOF is reached before the end of the read.
  222    No lock is being acquired when modifying FIFO state.
  223    This function is not thread-safe. */
  224 void* fc_fifo_read_single(FC_FIFO buffer, unsigned int size, unsigned int pid)
  225 {
  226     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  227 
  228     /* check buffer size */
  229     if (size > fifo->entrySize)
  230     {
  231         fc_message("read %d bytes from buffer is greater than FIFO element size (%d bytes).\n", size, fifo->entrySize);
  232         return (0);
  233     }
  234 
  235     for(;;)
  236     {
  237         ACQUIRE_LOCK();
  238 
  239         /* check if data is available for reading */
  240         if ( fifo->numData == 0 )
  241         {
  242             /* alone already */
  243             if (fifo->refCount <= 1)
  244             {
  245                 // There is a race condition in the check above: fifo->numData == 0.
  246                 // Since the read and compare to zero operation is not atomic,
  247                 // it is possible after we read the value and during compare,
  248                 // then fc_fifo_write_single_done() increment it (e.g., write data to fifo)
  249                 // then process writing to fifo exit causing refCount to be 1.
  250                 // Here we do a second check to make sure there is really no more data left.
  251 
  252                 SLEEP();
  253 
  254                 if (fifo->numData > 0)
  255                 {
  256                     break;
  257                 }
  258 
  259                 // Really no more data,
  260                 // return NULL.
  261                 RELEASE_LOCK();
  262                 return 0;
  263             }
  264 
  265             RELEASE_LOCK();
  266 
  267             SLEEP();
  268         }
  269         else
  270         {
  271             break;
  272         }
  273     }
  274 
  275     return (void*)( fifo->data + fifo->readIdx * fifo->entrySize );
  276 }
  277 
  278 /* Return direct pointer to data instead of copying to user buffer.
  279    This function is not thread-safe. */
  280 void fc_fifo_read_single_done(FC_FIFO buffer, unsigned int pid)
  281 {
  282     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  283 
  284     // operation to numData must be atomic since it
  285     // is incremented and decremented by at least 2 separate process
  286     // (fcmanager and process using libfc.so) even in single mode.
  287     //fifo->numData--;
  288     __sync_fetch_and_sub(&fifo->numData, 1);
  289 
  290     if ( fifo->readIdx >= (fifo->numEntry-1) )
  291     {
  292         fifo->readIdx = 0;
  293     }
  294     else
  295     {
  296         fifo->readIdx++;
  297     }
  298 
  299     RELEASE_LOCK();
  300 }
  301 
  302 /* write 'size' bytes to 'fifo', from 'buffer', for the process 'ID' */
  303 void* fc_fifo_write_single(FC_FIFO buffer, unsigned int size, unsigned int pid)
  304 {
  305     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  306 
  307     /* check buffer size */
  308     if (size > fifo->entrySize)
  309     {
  310         fc_message("write %d bytes to buffer is greater than FIFO element size (%d bytes).\n", size, fifo->entrySize);
  311         return (0);
  312     }
  313 
  314     for(;;)
  315     {
  316         ACQUIRE_LOCK();
  317 
  318         /* check if data is available for reading */
  319         if ( fifo->numData == fifo->numEntry )
  320         {
  321             /* alone already */
  322             if (fifo->refCount <= 1)
  323             {
  324                 RELEASE_LOCK();
  325                 return 0;
  326             }
  327 
  328             RELEASE_LOCK();
  329 
  330             SLEEP();
  331         }
  332         else
  333         {
  334             break;
  335         }
  336     }
  337 
  338     return (void*)( fifo->data + fifo->writeIdx * fifo->entrySize );
  339 }
  340 
  341 void fc_fifo_write_single_done(FC_FIFO buffer, unsigned int pid)
  342 {
  343     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  344 
  345     // operation to numData must be atomic since it
  346     // is incremented and decremented by at least 2 separate process
  347     // (fcmanager and process using libfc.so) even in single mode.
  348     //fifo->numData++;
  349     __sync_fetch_and_add(&fifo->numData, 1);
  350 
  351     if ( fifo->writeIdx >= (fifo->numEntry-1) )
  352     {
  353         fifo->writeIdx = 0;
  354     }
  355     else
  356     {
  357         fifo->writeIdx++;
  358     }
  359 
  360     RELEASE_LOCK();
  361 }
  362 
  363 int fc_fifo_read_init(FC_FIFO buffer, void* init, unsigned int size, unsigned int pid)
  364 {
  365     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  366 
  367     if (size != sizeof(FC_INIT))
  368     {
  369         fc_message("invalid read FC_INIT structure size\n");
  370         return 0;
  371     }
  372 
  373     ACQUIRE_LOCK();
  374 
  375     memcpy(init, (void*)&(fifo->init), sizeof(fifo->init));
  376 
  377     RELEASE_LOCK();
  378 
  379     return 1;
  380 }
  381 
  382 int fc_fifo_write_init(FC_FIFO buffer, void* init, unsigned int size, unsigned int pid)
  383 {
  384     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  385 
  386     if (size != sizeof(FC_INIT))
  387     {
  388         fc_message("invalid write FC_INIT structure size\n");
  389         return 0;
  390     }
  391 
  392     ACQUIRE_LOCK();
  393 
  394     memcpy((void*)&(fifo->init), init, sizeof(fifo->init));
  395 
  396     RELEASE_LOCK();
  397 
  398     return 1;
  399 }
  400 
  401 int fc_fifo_read_ldyn(FC_FIFO buffer, void* ldyn, unsigned int size, unsigned int pid)
  402 {
  403     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  404 
  405     if (size != sizeof(FC_LDYN))
  406     {
  407         fc_message("invalid FC_LDYN structure size\n");
  408         return 0;
  409     }
  410 
  411     ACQUIRE_LOCK();
  412 
  413     if ( fifo->lastLdynPtr == 0 )
  414     {
  415         fifo->lastLdynPtr = (FC_LDYN*)&(fifo->ldyn);
  416     }
  417 
  418     if ( fifo->lastLdynPtr == &(fifo->lastLdynPtr[MAX_LDYN-1]) )
  419     {
  420         fc_message("all FC_LDYN structures are read already.\n");
  421     }
  422 
  423     if ( (*(fifo->lastLdynPtr)).addr == 0 &&
  424           (*(fifo->lastLdynPtr)).name[0] == '\0' )
  425     {
  426         memset(ldyn, 0, sizeof(FC_LDYN));
  427     }
  428     else
  429     {
  430         memcpy(ldyn, fifo->lastLdynPtr, sizeof(FC_LDYN));
  431         fifo->lastLdynPtr++;
  432     }
  433 
  434     RELEASE_LOCK();
  435 
  436     return 1;
  437 }
  438 
  439 int fc_fifo_write_ldyn(FC_FIFO buffer, void* ldyn, unsigned int size, unsigned int pid)
  440 {
  441     volatile _fifo_control *fifo = (volatile _fifo_control *)buffer;
  442 
  443     int ctr;
  444 
  445     if (size != sizeof(FC_LDYN))
  446     {
  447         fc_message("invalid FC_LDYN structure size\n");
  448         return 0;
  449     }
  450 
  451     ACQUIRE_LOCK();
  452 
  453     /* find available empty slot */
  454     for (ctr = 0; ctr < (MAX_LDYN-1); ctr++)
  455     {
  456         if ( fifo->ldyn[ctr].addr     == 0 &&
  457               fifo->ldyn[ctr].name[0] == '\0' )
  458         {
  459             memcpy((void*)&(fifo->ldyn[ctr]), ldyn, sizeof(fifo->ldyn[0]));
  460             break;
  461         }
  462     }
  463 
  464     if (ctr == (MAX_LDYN-1))
  465     {
  466         fc_message("maximum FC_LDYN structures (%d) reached!\n", MAX_LDYN-1);
  467     }
  468 
  469     RELEASE_LOCK();
  470 
  471     return 1;
  472 }
  473