Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

bbd.c

Go to the documentation of this file.
00001 /**************************************************************************
00002 
00003 This is a collection of routines designed to provide a simple
00004 communications mechanism between multiple processes running under VxWorks.
00005 They provide the user with a flexible and sometimes reliable means of passing
00006 data between, and synchronizing, independently spawned processes.  At the
00007 same time the routines take care of the bookkeeping associated with
00008 maintaining the timers and semiphores necessary to ensure reliablility
00009 and mutually exclusive access to the data being exchanged.
00010 
00011 
00012 History:
00013 03/20/98  murphy:  clean up code
00014 07/28/92  murphy:  free data buffer in bbdDeleteWriterStruct()
00015 03/30/92  murphy:  change bbdShow to print task names.  Added task Id to
00016                    readrer struct.
00017 03/21/92  murphy:  Added NULL id check on user routines.  Change type to
00018                    BBD_NULL in bbdDelete().  Added bbdName().  Gave
00019                    bbdWrite() a variable arg list.
00020 03/10/92  murphy:  Added bbdHelpHelpStr.
00021 03/05/92  murphy:  Created.
00022 
00023 
00024 The major routines are bbdConnect, bbdRead, bbdWrite, bbdClear, and bbdDelete.
00025 Shell help routines are bbdHelp and bbdShow.
00026 
00027 BBD
00028 bbdConnect(name, type, size)
00029   This connects to a bbd with the given name, creating it if it doesn't
00030   exist, and returns a bbd id.  The id is used in subsequent calls of read,
00031   write, etc.  The size of the data buffer (in bytes) must be the same for
00032   all tasks that use the named bbd.  bbd's with different names can have
00033   different sizes.  The type must be one of the following
00034 
00035   BBD_SOLE_READER only this task can read from the bbd (not implemented)
00036   BBD_MULT_READER one of many possible readers.  Each task should connect
00037                   with its own BBD.
00038   BBD_SOLE_WRITER only this task can write to the bbd.  If other tasks had
00039                   previously connected as writers, then bbdWrite() will
00040                   return ERROR when those tasks try to write to the bbd.
00041                   Each task can have its own BBD or multiple tasks can use
00042                   the same BBD if each task reconnects after another task
00043                   used the BBD.
00044   BBD_MULT_WRITER one of many possible writers.  Any other tasks that
00045                   connected as a writer can now write to the bbd.  Each task
00046                   can have its own BBD or multiple tasks can use the same BBD.
00047 
00048   Normally, a task connects once at initialization, uses the id for either
00049   reads or writes, and may then delete a reader bbd when the task is ending.
00050 -----------------------
00051 
00052 STATUS
00053 bbdRead(id, dataPt, readType, timeout)
00054   This copies the data from the bbd into the data buffer pointed to by
00055   dataPt.  The bbd must have been opened as a reader.  The read type must
00056   be one of the following
00057 
00058   BBD_PLAIN_READ copies data, fresh or not.  If no data has ever been
00059                  written to the bbd, this will block (up to timeout) for
00060                  another task to write.
00061   BBD_FRESH_READ waits (up to timeout) until new data has been writen to
00062                  the bbd.  If the data is fresh, bbdRead() returns without
00063                  blocking.  This option insures that another task has written
00064                  to the bbd at least once since the current task last read
00065                  from the bbd.  This option does NOT insure that no other
00066                  task has read the data as each reader maintains its own
00067                  "freshness" flags.  Timeout can be a value, NO_WAIT, or
00068                  WAIT_FOREVER.
00069   BBD_SPY_READ   like a BBD_PLAIN_READ but does not set any flags used for
00070                  synchronization.  This allows a monitoring program to
00071                  read a snapshot of the data without disturbing the tasks
00072                  that are using the bbd for synchronization.
00073 
00074   Returns OK or ERROR if bad id or it waited more than timeout for fresh
00075   data or for the first data (if the bbd was originally empty).
00076 -----------------------
00077 
00078 STATUS
00079 bbdWrite(id, dataPt, writeType [,timeout])
00080   This writes data to the bbd.  The bbd must have been opened as a writer.
00081   The writeType can be one of the following
00082 
00083   BBD_PLAIN_WRITE writes to the bbd regardless if the old data has been read
00084                   or not.  "timeout" is not needed.
00085   BBD_WAIT_WRITE  waits (up to timeout) until the data last writen to the
00086                   bbd has been read by at least one reader.  Currently,
00087                   there is no means to ensure that all readers have read
00088                   the old data.  Timeout can be a value, NO_WAIT, or
00089                   WAIT_FOREVER.
00090 
00091   Returns OK or ERROR if bad id, it waited more than timeout, or if the
00092   bbd is of type BBD_SOLE_WRITER and the task is not the owner.
00093 -----------------------
00094 
00095 STATUS
00096 bbdClear(id)
00097   This clears the bbd for both reader bbds and writer bbds.
00098 
00099   For readers, it is like a read with no wait and no data transfer. This
00100   would be used to make sure subsequent reads with the fresh option get data
00101   writen after the flush.
00102 
00103   For writers: If sole_writer: flush old buffer and make it look like no one
00104   has ever writen to the bbd.   All readers (plain, fresh, or spy) will
00105   block or return ERROR until the writer puts data into the buffer.  If
00106   multi_writer:  make it look like someone just read.
00107 
00108   Returns OK or ERROR if bad id;
00109 -----------------------
00110 
00111 STATUS
00112 bbdDelete(id)
00113   Deletes a reader bbd and frees memory.  Currently, there is no way to
00114   delete a writer bbd.
00115   New memory (16 bytes) is allocated every time a reader connects to a bbd.
00116   This is a small amount of memory, but if a task continuously connects as
00117   a reader it will eventually run out of memory unless it calls bbdDelete.
00118   When a writer connects to a bbd, the old data structure is used and no
00119   new memmory is allocated.
00120 
00121   Returns OK or ERROR if bad id;
00122 -----------------------
00123 
00124 char   *
00125 bbdName(BBD id)
00126   returns pointer to the name of the bbd.  NO NOT change the name.
00127 
00128   Returns pointer or NULL if bad id;
00129 -----------------------
00130 
00131 BBD
00132 bbdNameToId(char   *name)
00133   returns BBD writer id that matches the given name.
00134 
00135   Returns bbd or NULL if bad name;
00136 -----------------------
00137 
00138 bbdHelp
00139   Prints help info to the screen.
00140 -----------------------
00141 
00142 bbdShow [id, name]
00143   This a diagnostic routine called from the shell that prints info on the
00144   given bbd.  if id = 0, the name is used.  If the name is 0, a list of all
00145   the bbds is displayed.
00146 -----------------------
00147 
00148 
00149 Function Declarations:
00150 
00151 BBD    bbdConnect(char *bbdName, BBD_TYPE bbdType, int bbdSize);
00152 STATUS bbdRead(BBD id, void *data, BBD_READ_TYPE readType, int timeout);
00153 STATUS bbdClear(BBD id);
00154 STATUS bbdWrite(BBD id, void *data, BBD_WRITE_TYPE writeType, ...);
00155 STATUS bbdDelete(BBD id);
00156 char * bbdName(BBD id);
00157 BBD    bbdNameToId(char *name);
00158 int    bbdShow(BBD id, char *name);
00159 ------------------------
00160 
00161 Examples:
00162 Send command to retro;
00163 
00164 retroSendCmd(RET_COMMAND *cmdBuf)
00165 {
00166   static BBD id = NULL;
00167 
00168   if(ERROR == bbdWrite(id, cmdBuf, BBD_PLAIN_WRITE))
00169   {
00170     id = bbdConnect("retroCommand", BBD_SOLE_WRITER, sizeof(RET_COMMAND));
00171     if(ERROR == bbdWrite(id, cmdBuf, BBD_PLAIN_WRITE))
00172     {
00173       logMsg("ERROR:  Can't write to retroCommand BBD\n",
00174       0,0,0,
00175       0,0,0);
00176       return ERROR;
00177     }
00178   }
00179   return OK;
00180 }
00181 
00182 Read retro command;
00183 
00184 ***************************************************************************
00185 ***************************************************************************/
00186 
00187 
00188 #include "vxWorks.h"
00189 #include "semLib.h"
00190 #include "memLib.h"
00191 #include "taskLib.h"
00192 #include "stdarg.h"
00193 #include "fioLib.h"
00194 #include "stdio.h"
00195 #include "logLib.h"
00196 #include "string.h"
00197 
00198 #include "bbd.h"
00199 #include "dbg_mem.h"            /* DEBUG_MALLOC,DEBUG_FREE,DEBUG_CALLOC */
00200 
00201 /* typedef struct bbdWriter{ . . . } BBD_WRITER and
00202  * typedef struct bbdReader{ . . . } BBD_READER moved from here to
00203  * bbd.h so they could be used by bbdmem.cc  on 27-Oct-1997 by WPS
00204  */
00205 
00206 
00207 
00208 #define BBD_MASTER (BBD_WRITER *) NULL
00209 
00210 
00211 /* Declarations for LOCAL functions */
00212 LOCAL void bbdLock (BBD_WRITER * id);
00213 LOCAL void bbdUnlock (BBD_WRITER * id);
00214 LOCAL BBD_WRITER *bbdCreateWriterStruct (char *bbdName, BBD_TYPE bbdType,
00215                                          int bufSize);
00216 LOCAL BOOL bbdDeleteWriterStruct (BBD_WRITER * id);
00217 LOCAL BBD_READER *bbdCreateReaderStruct (char *name, BBD_TYPE type,
00218                                          int bufSize, BBD_WRITER * bbd);
00219 LOCAL BBD_WRITER *bbdFindWriter (char *name);
00220 LOCAL BBD_WRITER *bbdLinkWriter (BBD_WRITER * id);
00221 LOCAL BBD_WRITER *bbdConnectWriter (BBD_WRITER * id, BBD_TYPE type,
00222                                     int bufSize);
00223 STATUS bbdDelete (BBD id);
00224 
00225 
00226 LOCAL BBD_WRITER *bbdList = NULL;
00227 LOCAL SEM_ID bbdMasterSem = NULL;       /* master bulletin board semaphore */
00228 
00229 
00230 /*************************************************************************/
00231 LOCAL void
00232 bbdSuspend (char *format, ...)
00233 {
00234   char st[300];
00235 
00236   va_list args;
00237   va_start (args, format);
00238 
00239   vsprintf (st, format, args);
00240   logMsg (st, 0, 0, 0, 0, 0, 0);
00241   logMsg ("Suspending task\n", 0, 0, 0, 0, 0, 0);
00242   taskSuspend (0);
00243 
00244   va_end (args);
00245 }
00246 
00247 
00248 /*************************************************************************/
00249 /* These routines take and give the semaphores that prevents two different
00250 tasks from accessing or modifying the data structure at the same time.
00251 bbdLock(BBD_WRITER *id) takes the semaphore and bbdUnlock(BBD_WRITER *id)
00252 gives the semaphore back to the system.  If id == BBD_MASTER, then bbdMasterSem
00253 is used.  If bbdMasterSem does not exist, it is created. */
00254 
00255 LOCAL void
00256 bbdLock (BBD_WRITER * id)
00257 {
00258   char st[100 + BBD_NAME_SIZE];
00259 
00260   if (id == BBD_MASTER)
00261     {
00262       if (bbdMasterSem == NULL)
00263         {
00264           if (NULL == (bbdMasterSem = semMCreate (SEM_Q_PRIORITY |
00265                                                   SEM_DELETE_SAFE |
00266                                                   SEM_INVERSION_SAFE)))
00267             {
00268               bbdSuspend ("Can't create BBD master semaphore!\n");
00269             }
00270         }
00271       if (semTake (bbdMasterSem, 100) == ERROR)
00272         {
00273           bbdSuspend ("Bulletin Board master semaphore timed out!\n");
00274 
00275         }
00276     }
00277   else
00278     {
00279       if (semTake (id->sem, 100) == ERROR)
00280         {
00281           sprintf (st, "BBD >%s< semaphore timed out!\n", id->name);
00282           bbdSuspend (st);
00283         }
00284     }
00285 }
00286 
00287 LOCAL void
00288 bbdUnlock (BBD_WRITER * id)
00289 {
00290   if (id == BBD_MASTER)
00291     semGive (bbdMasterSem);
00292   else
00293     semGive (id->sem);
00294 }
00295 
00296 
00297 /*************************************************************************/
00298 /* This routine connects a writer to the named bulletin board and
00299 returns the id that the program will use to identify the bulletin
00300 board in future calls to bulletin board routines.  If it cannot find
00301 the bulletin board it will create one with the given name.  The size
00302 must be equal to that of an existing buffer of that name.
00303 */
00304 
00305 /* Create a new bulletin board structure. */
00306 
00307 LOCAL BBD_WRITER *
00308 bbdCreateWriterStruct (char *bbdName, BBD_TYPE bbdType, int bufSize)
00309 {
00310   BBD_WRITER *id;
00311   /* create bbd */
00312   if (NULL == (id = (BBD_WRITER *) DEBUG_MALLOC (sizeof (BBD_WRITER))))
00313     bbdSuspend ("Can't allocate memory for BBD!\n");
00314   id->type = bbdType;
00315   id->sem =
00316     semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
00317   strncpy (id->name, bbdName, BBD_NAME_SIZE);
00318   id->name[BBD_NAME_SIZE] = 0;  /* make sure it ends */
00319   if (NULL == (id->buf = (char *) DEBUG_MALLOC (bufSize)))
00320     bbdSuspend ("Can't allocate memory for BBD data buffer!\n");
00321 
00322   id->size = bufSize;
00323   id->writeCnt = 0;
00324   id->readCnt = 0;
00325   id->waitingToWriteSem = semBCreate (SEM_Q_FIFO, SEM_FULL);
00326   id->waitingToReadSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
00327   id->taskId = taskIdSelf ();
00328   id->readers = NULL;           /* no readers yet */
00329   /* id->next is set when bbd is added to the list */
00330 
00331   /* check semaphores */
00332   if (NULL == id->sem ||
00333       NULL == id->waitingToWriteSem || NULL == id->waitingToReadSem)
00334     {
00335       bbdSuspend ("Can't create BBD semaphores!\n");
00336     }
00337 
00338   return id;
00339 }
00340 
00341 /*------------------------------------------------------------------------*/
00342 /* Delete a writer struct NOT on the list of bbd's. */
00343 LOCAL BOOL
00344 bbdDeleteWriterStruct (BBD_WRITER * id)
00345 {
00346   BOOL stat;
00347   if (id == NULL)
00348     return ERROR;
00349   DEBUG_FREE ((char *) id->buf);
00350   stat = semDelete (id->sem) &&
00351     semDelete (id->waitingToWriteSem) && semDelete (id->waitingToReadSem);
00352 
00353   DEBUG_FREE ((char *) id);     /* do this last */
00354   return stat;
00355 }
00356 
00357 
00358 /*------------------------------------------------------------------------*/
00359 LOCAL BBD_READER *
00360 bbdCreateReaderStruct (char *bbdName, BBD_TYPE bbdType, int bufSize,
00361                        BBD_WRITER * bbd)
00362 {
00363   BBD_READER *id;
00364   /* check that reader's buffer is same size */
00365   if (bufSize != bbd->size)
00366     bbdSuspend ("Can't attach bbd reader to \"%s\".\n"
00367                 "Wrong buffer size %d. Must be %d\n",
00368                 bbd->name, bufSize, bbd->size);
00369 
00370   /* Create reader struct */
00371   if (NULL == (id = (BBD_READER *) DEBUG_MALLOC (sizeof (BBD_READER))))
00372     bbdSuspend ("Can't allocate memory for reader BBD!\n");
00373 
00374   id->type = bbdType;
00375   id->bbd = bbd;
00376   id->readCnt = 0;
00377   id->taskId = taskIdSelf ();
00378 
00379   bbdLock (bbd);
00380   {
00381     /* add reader to start of reader list */
00382     id->next = bbd->readers;
00383     bbd->readers = id;
00384   }
00385   bbdUnlock (bbd);
00386   return id;
00387 }
00388 
00389 /*------------------------------------------------------------------------*/
00390 /* returns writer id of BBD with matching name, NULL if no match */
00391 LOCAL BBD_WRITER *
00392 bbdFindWriter (char *name)
00393 {
00394   BBD_WRITER *tId;
00395   for (tId = bbdList; tId != NULL; tId = tId->next)
00396     {
00397       if (0 == strncmp (tId->name, name, BBD_NAME_SIZE - 1))
00398         break;                  /* we have a match */
00399     }
00400   return tId;
00401 }
00402 
00403 /*----------------------------------------------------------------------*/
00404 /* Links BBD to the bbdList.  This first checks to make sure another task
00405  * has not linked another BBD with the same name.  If this has happened,
00406  * the routine connects to the existing BBD.  Returns the id of the final
00407  * bbd.
00408  */
00409 LOCAL BBD_WRITER *
00410 bbdLinkWriter (BBD_WRITER * id)
00411 {
00412   BBD_WRITER *tId;
00413   /* add bbd to start of list */
00414   bbdLock (BBD_MASTER);
00415   {
00416     /*
00417      * make sure no one added a bbd with the same name while we weren't
00418      * locked
00419      */
00420     if (NULL == (tId = bbdFindWriter (id->name)))
00421       {
00422         id->next = bbdList;     /* None there, add ours to the list */
00423         bbdList = id;
00424       }
00425   }
00426   bbdUnlock (BBD_MASTER);
00427   if (tId != NULL)
00428     {
00429       /* Another task created the BBD, connect to it, and delete our BBD */
00430       bbdConnectWriter (tId, id->type, id->size);
00431       (void) bbdDeleteWriterStruct (id);
00432       id = tId;
00433     }
00434   return id;
00435 }
00436 
00437 /*------------------------------------------------------------------------*/
00438 /* Connect to an existing BBD. */
00439 LOCAL BBD_WRITER *
00440 bbdConnectWriter (BBD_WRITER * id, BBD_TYPE type, int bufSize)
00441 {
00442   BBD_READER *readId;
00443   /* Make sure bbd exists. */
00444   if (NULL == id)
00445     bbdSuspend ("Cannot connect to NULL bbd.\n");
00446 
00447   /* can't change type to multiwriter.  No way to inform original task */
00448   /*
00449    * So ??  I don't know why I protected against this.
00450    *
00451    * if (id->type == BBD_SOLE_WRITER && type == BBD_MULT_WRITER)
00452    * bbdSuspend("Can't change BBD type to multiwriter.\n");
00453    */
00454 
00455   /* Don't change size */
00456   if (id->size != bufSize)
00457     bbdSuspend ("Can't attach bbd writter to \"%s\".\n"
00458                 "Wrong buffer size %d. Must be %d\n",
00459                 id->name, bufSize, id->size);
00460 
00461   /* Looks good, update bbd for new writer */
00462   bbdLock (id);
00463   {
00464     id->type = type;
00465     id->taskId = taskIdSelf ();
00466     if (type == BBD_SOLE_WRITER)
00467       {
00468         /*
00469          * New sole_writer.  Make readers that want to wait for fresh data wait
00470          * on the new writer.  Flush all read buffers and reset semaphores
00471          */
00472         for (readId = id->readers; readId != NULL; readId = readId->next)
00473           {
00474             /* make reader think he has already read the existing data buf */
00475             readId->readCnt = id->writeCnt;
00476           }
00477         id->readCnt = id->writeCnt;
00478         /*
00479          * Free all that want to write so that they can see that a new
00480          * sole_writer has control.
00481          */
00482         semFlush (id->waitingToWriteSem);
00483       }
00484   }
00485   bbdUnlock (id);
00486   return id;
00487 }
00488 
00489 /*------------------------------------------------------------------------*/
00490 /* returns id of BBD, read or write.  Creates one if it doesn't exist */
00491 BBD bbdConnect (char *bbdName, BBD_TYPE bbdType, int bufSize)
00492 {
00493   BBD id;
00494   BBD_WRITER *wId;
00495   switch (bbdType)
00496     {
00497     case BBD_SOLE_WRITER:
00498     case BBD_MULT_WRITER:
00499       if (NULL == (wId = bbdFindWriter (bbdName)))
00500         {
00501           /* write bbd does not exist, create one and attach it to list. */
00502           wId = bbdCreateWriterStruct (bbdName, bbdType, bufSize);
00503           wId = bbdLinkWriter (wId);
00504         }
00505       else
00506         {
00507           /* Connect to BBD */
00508           bbdConnectWriter (wId, bbdType, bufSize);
00509         }
00510       id = (BBD) wId;
00511       break;
00512     case BBD_MULT_READER:
00513       if (NULL == (wId = bbdFindWriter (bbdName)))
00514         {
00515           /* bbd writer does not exist, create one and attach it to list.
00516              The following comment is old thinking:
00517              Type BBD_MULT_WRITER can be changed to BBD_SOLE_WRITER
00518              by writer if needed.  But can't go the other way. */
00519           wId = bbdCreateWriterStruct (bbdName, BBD_MULT_WRITER, bufSize);
00520           wId = bbdLinkWriter (wId);
00521         }
00522       id = (BBD) bbdCreateReaderStruct (bbdName, bbdType, bufSize, wId);
00523       break;
00524     default:
00525       bbdSuspend ("Can't connect.  Unknown BBD type.\n");
00526     }
00527   return id;
00528 }
00529 
00530 /*------------------------------------------------------------------------*/
00531 /* deleat bbd reader */
00532 STATUS bbdDelete (BBD id)
00533 {
00534   STATUS stat;
00535   BBD_WRITER *wId;
00536   BBD_READER *rId;
00537 
00538   if (NULL == id)
00539     return ERROR;
00540 
00541   switch (*(BBD_TYPE *) id)     /* bbd type */
00542     {
00543     case BBD_MULT_READER:
00544       stat = ERROR;
00545       wId = ((BBD_READER *) id)->bbd;
00546       /* Try to remove id from reader list */
00547       bbdLock (wId);
00548       {
00549         /* Is it the first reader on the list */
00550         if (wId->readers == (BBD_READER *) id)
00551           {
00552             wId->readers = wId->readers->next;  /* remove it */
00553             stat = OK;
00554           }
00555         else
00556           {
00557             /* is id on the list */
00558             for (rId = wId->readers; rId != NULL; rId = rId->next)
00559               {
00560                 if (rId->next == (BBD_READER *) id)
00561                   {
00562                     /* found reader one up on the reader list.  Remove id */
00563                     rId->next = ((BBD_READER *) id)->next;
00564                     stat = OK;
00565                     break;
00566                   }
00567               }
00568           }
00569       }
00570       bbdUnlock (wId);
00571       if (OK == stat)
00572         {
00573           /* clear the type */
00574           (*(BBD_TYPE *) id) = BBD_NULL;
00575           /* try to free memory */
00576           DEBUG_FREE ((char *) id);
00577         }
00578       break;
00579     default:
00580       stat = ERROR;
00581       break;
00582     }
00583   return stat;
00584 }
00585 
00586 
00587 /**************************************************************************/
00588 /* READ and WRITE functions. */
00589 
00590 /*-----------------------------------------------------------------------*/
00591 /*
00592  * bbdClear.
00593  *
00594  * For readers, like a read with no wait and no data transfer. Used to make sure
00595  * subsequent read with the fresh option get data writen after the flush.
00596  *
00597  * For writers: If sole_writer: flush old buffer and make it look like no one
00598  * has ever writen to the bbd.   All readers (plain, fresh, or spy) will
00599  * block or return ERROR until the writer puts data into the buffer.  If
00600  * multi_writer:  make it look like someone just read.
00601  *
00602  * Returns OK or ERROR if bad id;
00603  */
00604 
00605 STATUS bbdClear (BBD id)
00606 {
00607   STATUS stat;
00608   BBD_WRITER *wId;
00609   BBD_READER *rId;
00610 
00611   if (NULL == id)
00612     return ERROR;
00613 
00614   switch (*(BBD_TYPE *) id)     /* bbd type */
00615     {
00616     case BBD_MULT_READER:
00617       stat = OK;
00618       wId = ((BBD_READER *) id)->bbd;
00619       bbdLock (wId);
00620       {
00621         /* Update message cnt to LOOK like we read the current data */
00622         ((BBD_READER *) id)->readCnt = wId->readCnt = wId->writeCnt;
00623         semGive (wId->waitingToWriteSem);
00624       }
00625       bbdUnlock (wId);
00626       break;
00627     case BBD_MULT_WRITER:
00628       stat = OK;
00629       wId = (BBD_WRITER *) id;
00630       bbdLock (wId);
00631       {
00632         /* Update message cnt to LOOK like someone just read the current data */
00633         wId->readCnt = wId->writeCnt;
00634         semGive (wId->waitingToWriteSem);
00635       }
00636       bbdUnlock (wId);
00637       break;
00638 
00639     case BBD_SOLE_WRITER:
00640       stat = OK;
00641       wId = (BBD_WRITER *) id;
00642       bbdLock (wId);
00643       {
00644         if (wId->taskId != taskIdSelf ())
00645           {
00646             /* can't flush someone else's bbd */
00647             stat = ERROR;
00648           }
00649         else
00650           {
00651             /* Update bbd to look like no data has ever been writen */
00652             wId->readCnt = wId->writeCnt = 0;
00653             for (rId = wId->readers; rId != NULL; rId = rId->next)
00654               {
00655                 rId->readCnt = 0;
00656               }
00657             semGive (wId->waitingToWriteSem);
00658           }
00659       }
00660       bbdUnlock (wId);
00661       break;
00662 
00663     default:
00664       stat = ERROR;
00665       break;
00666     }
00667   return stat;
00668 }
00669 
00670 /*-----------------------------------------------------------------------*/
00671 /*
00672  * Read buffer.
00673  *
00674  * If no data in buf, wait timeout for data
00675  *
00676  * Returns OK or ERROR if timeout or bad id type;
00677  */
00678 
00679 STATUS bbdRead (BBD id, void *buf, BBD_READ_TYPE type, int timeout)
00680 {
00681   STATUS stat;
00682   BBD_WRITER *wId;
00683   BBD_READER *rId;
00684 
00685   if (NULL == id)
00686     return ERROR;
00687 
00688   switch (*(BBD_TYPE *) id)     /* bbd type */
00689     {
00690     case BBD_MULT_READER:
00691       rId = (BBD_READER *) id;
00692       wId = rId->bbd;
00693       stat = OK;
00694       /*
00695        * Is data available?  TaskLock to prevent a writer from writing after I
00696        * check the counters but before I do a semTake.  If a writer writes after
00697        * the taskUnlock but before the bbdLock, that's ok I'll get even fresher
00698        * data. The writer MUST first copy the data, then set the counters and
00699        * then do a semFlush.
00700        */
00701       taskLock ();              /* Be carefull with this. */
00702       {
00703         if (wId->writeCnt == 0)
00704           {
00705             /* Wait till there is some data in the buffer */
00706             stat = semTake (wId->waitingToReadSem, timeout);
00707           }
00708         else if (type == BBD_FRESH_READ && wId->writeCnt <= rId->readCnt)
00709           {
00710             /* Wait till someone writes new data */
00711             stat = semTake (wId->waitingToReadSem, timeout);
00712           }
00713       }
00714       taskUnlock ();
00715       if (stat == OK)
00716         {
00717           bbdLock (wId);
00718           {
00719             bcopy (wId->buf, buf, wId->size);   /* Copy data */
00720             /* If not spying, update message cnt */
00721             if (type != BBD_SPY_READ)
00722               {
00723                 wId->readCnt = wId->writeCnt;
00724                 rId->readCnt = wId->writeCnt;
00725                 semGive (wId->waitingToWriteSem);       /* don't flush */
00726               }
00727           }
00728           bbdUnlock (wId);
00729         }
00730       break;
00731     default:
00732       stat = ERROR;
00733       break;
00734     }
00735   return stat;
00736 }
00737 
00738 
00739 
00740 /*-----------------------------------------------------------------------*/
00741 /*
00742  * Write buffer.
00743  * Returns OK or ERROR if sole writer and not the current owner.
00744  */
00745 
00746 LOCAL STATUS
00747 bbdPlainWrite (BBD_WRITER * id, void *buf)
00748 {
00749   STATUS stat;
00750 
00751   stat = OK;
00752   bbdLock (id);
00753   {
00754     if (BBD_SOLE_WRITER == id->type && taskIdSelf () != id->taskId)
00755       {
00756         /* Not the owner. */
00757         stat = ERROR;
00758         if (id->writeCnt <= id->readCnt)
00759           {
00760             /*
00761              * I am not the owner and can't write.  I may have taken the
00762              * semaphore that the real owner needs.  Give it back.
00763              */
00764             semGive (id->waitingToWriteSem);
00765 
00766           }
00767       }
00768     else
00769       {
00770         /*
00771          * The writer MUST first copy the data, then set the counters and
00772          * then do a semFlush.  This is so the blocking read will work
00773          * correctly.
00774          */
00775         bcopy (buf, id->buf, id->size); /* Copy data */
00776         /* Update message cnt */
00777         id->writeCnt++;
00778         semTake (id->waitingToWriteSem, NO_WAIT);
00779         semFlush (id->waitingToReadSem);        /* Flush so all can read */
00780       }
00781     bbdUnlock (id);
00782 
00783     return stat;
00784   }
00785 }
00786 
00787 STATUS bbdWrite (BBD id, void *buf, BBD_WRITE_TYPE type,...)
00788 {
00789   STATUS stat;
00790   BBD_WRITER *wId;
00791   int timeout;
00792   va_list ap;                   /* timout included on blocking write */
00793 
00794   if (NULL == id)
00795     return ERROR;
00796 
00797   switch (*(BBD_TYPE *) id)     /* bbd type */
00798     {
00799     case BBD_SOLE_WRITER:
00800     case BBD_MULT_WRITER:
00801       wId = (BBD_WRITER *) id;
00802       if (BBD_WAIT_WRITE == type)
00803         {
00804           va_start (ap, type);
00805           timeout = va_arg (ap, int);   /* get timeout from argument list */
00806           /* wait till someone reads the buffer so we can write */
00807           stat = semTake (wId->waitingToWriteSem, timeout);
00808           if (ERROR != stat)
00809             {
00810               bbdLock (wId);
00811               {
00812                 if (wId->writeCnt > wId->readCnt)
00813                   {
00814                     /*
00815                      * someone wrote before we could bbdLock.  The code should be
00816                      * changed to wait for another reader to read the data.  The code
00817                      * would need to keep track of how long the semTake took, then
00818                      * bbdUnlock and continue waiting until all of timeout has been
00819                      * used before reporting an error.
00820                      */
00821                     stat = ERROR;
00822                   }
00823                 else
00824                   {
00825                     stat = bbdPlainWrite (wId, buf);
00826                   }
00827               }
00828               bbdUnlock (wId);
00829             }
00830           va_end (ap);
00831         }
00832       else                      /* type == BBD_PLAIN_WRITE */
00833         {
00834           stat = bbdPlainWrite (wId, buf);
00835         }
00836 
00837       break;
00838     default:
00839       stat = ERROR;
00840       break;
00841     }
00842   return stat;
00843 }
00844 
00845 /************************************************************************/
00846 /* BBD help commands
00847    void bbdHelp()         prints command summary
00848    void bbdShow(id,name)  prints status of bbd.  If id = 0, overall status
00849 *************************************************************************/
00850 char bbdHelpHelpStr[] = "\
00851 bbdHelp                         Msg passing between tasks on one cpu\n";
00852 
00853 LOCAL char bbdHelpString[] = "\
00854 bbdConnect name,type,size       Connects to a bbd \n\
00855 bbdClear   id                   Flush data buffer \n\
00856 bbdRead    id,buf,type,timeout  Read from bbd \n\
00857 bbdWrite   id,buf,type[,timeout]Write to bbd \n\
00858 bbdName    id                   Returns name of bbd \n\
00859 bbdNameToId name                Returns id of writer\n\
00860 bbdShow    [id [,name]]         Show info on bbds. If id=0, uses name\n\
00861 \n\
00862 bbd types:   multi-reader = 2, sole_writer = 3, multi-writer = 4 \n\
00863 read types:  plain = 1, only fresh data = 2, spy = 3 \n\
00864 write types: plain = 1, blocking = 2 \n\
00865 ";
00866 
00867 /*----------------------------------------------------------------------*/
00868 int
00869 bbdHelp ()
00870 {
00871   printf (bbdHelpString);
00872   return 0;
00873 }
00874 
00875 /*----------------------------------------------------------------------*/
00876 char *
00877 bbdName (BBD id)
00878 {
00879   if (NULL == id)
00880     return NULL;
00881 
00882   switch (*(BBD_TYPE *) id)     /* bbd type */
00883     {
00884     case BBD_SOLE_WRITER:
00885     case BBD_MULT_WRITER:
00886       return ((BBD_WRITER *) id)->name;
00887     case BBD_MULT_READER:
00888       return ((BBD_READER *) id)->bbd->name;
00889     default:
00890       break;
00891     }
00892   return NULL;
00893 }
00894 
00895 /*----------------------------------------------------------------------*/
00896 BBD bbdNameToId (char *name)
00897 {
00898   return (BBD) bbdFindWriter (name);
00899 }
00900 
00901 /*----------------------------------------------------------------------*/
00902 LOCAL void
00903 bbdPrintTaskName (int taskId, int maxChars)
00904 {
00905   int len, i;
00906   char *name;
00907   name = taskName (taskId);
00908   if (NULL != name)
00909     len = strlen (name);
00910   else
00911     {
00912       name = "***";             /* task does not exist */
00913       len = 3;
00914     }
00915   for (i = maxChars - len; i > 0; i--)
00916     printf (" ");
00917   if (maxChars < len)
00918     for (i = 0; i < maxChars; i++)
00919       printf ("%c", name[i]);   /* print spaces */
00920   else
00921     for (i = 0; i < len; i++)
00922       printf ("%c", name[i]);   /* print name */
00923 }
00924 
00925 /*----------------------------------------------------------------------*/
00926 LOCAL STATUS
00927 bbdShowReaders (BBD_WRITER * wId)
00928 {
00929   int cnt;
00930   BBD_READER *rId, *r;
00931 
00932   if (BBD_SOLE_WRITER != wId->type && BBD_MULT_WRITER != wId->type)
00933     return ERROR;
00934   if (NULL == wId->readers)
00935     printf ("no readers\n----------\n");
00936   for (rId = wId->readers; NULL != rId;)
00937     {
00938       /* print readers */
00939     /** printing format:
00940       id   0xffff0000 0xffff0000 0xffff0000 0xffff0000 0xffff0000 0xffff0000
00941       task tttttttttt aaaaaaaaaa ssssssssss kkkkkkkkkk task names 1234567890
00942       cnt          23         23         23         23         23         23
00943     */
00944       printf ("id   ");
00945       for (cnt = 0, r = rId; NULL != r && cnt != 6; cnt++, r = r->next)
00946         printf ("%10p ", r);
00947       printf ("\ntask ");
00948       for (cnt = 0, r = rId; NULL != r && cnt != 6; cnt++, r = r->next)
00949         {
00950           bbdPrintTaskName (r->taskId, 10);
00951           printf (" ");
00952         }
00953       printf ("\ncnt  ");
00954       for (cnt = 0, r = rId; NULL != r && cnt != 6; cnt++, r = r->next)
00955         printf ("%10d ", r->readCnt);
00956 
00957       for (printf ("\n-----"); cnt--; printf ("-----------"));
00958       printf ("\n");
00959       rId = r;
00960     }
00961   return OK;
00962 }
00963 
00964 /*----------------------------------------------------------------------*/
00965 LOCAL STATUS
00966 bbdShowWriter (BBD_WRITER * wId)
00967 {
00968   char *name, st[61];
00969 
00970   if (BBD_SOLE_WRITER != wId->type && BBD_MULT_WRITER != wId->type)
00971     return ERROR;
00972 
00973   if (BBD_SOLE_WRITER == wId->type)
00974     printf ("Sole writer:  ");
00975   else
00976     printf ("Mult writer:  ");
00977   strncpy (st, wId->name, 60);
00978   st[60] = 0;
00979   printf ("\"%s\"\n", st);
00980   printf ("bbd semaphore     (%p) is ", wId->sem);
00981   if (ERROR == semTake (wId->sem, NO_WAIT))
00982     printf ("blocked\n");
00983   else
00984     {
00985       printf ("clear\n");
00986       semGive (wId->sem);
00987     }
00988   printf ("waitingToWriteSem (%p) is ", wId->waitingToWriteSem);
00989   if (ERROR == semTake (wId->waitingToWriteSem, NO_WAIT))
00990     printf ("blocked\n");
00991   else
00992     {
00993       printf ("clear\n");
00994       semGive (wId->waitingToWriteSem);
00995     }
00996   printf ("waitingToReadSem  (%p)\n", wId->waitingToReadSem);
00997   printf ("Buffer:        %p\n", wId->buf);
00998   printf ("Size:          %d\n", wId->size);
00999   printf ("Owner Task:    0x%x: ", wId->taskId);
01000   if (NULL != (name = taskName (wId->taskId)))
01001     {
01002       printf (name);
01003       printf ("\n");
01004     }
01005   printf ("Write Cnt:     %d\n", wId->writeCnt);
01006   printf ("Read Cnt:      %d\n", wId->readCnt);
01007   return OK;
01008 }
01009 
01010 
01011 /*----------------------------------------------------------------------*/
01012 int
01013 bbdShow (BBD id, char *name)
01014 {
01015   char st[100];
01016   BBD_WRITER *wId, *wId2;
01017   BBD_READER *rId;
01018 
01019   if (NULL == id && NULL != name)
01020     {
01021       id = bbdFindWriter (name);
01022       if (NULL == id)
01023         {
01024           printf ("Bad name or id\n");
01025           name = NULL;
01026         }
01027     }
01028 
01029   if (id == NULL)
01030     {
01031       printf ("Master semaphore (%p) is ", bbdMasterSem);
01032       if (NULL != bbdMasterSem)
01033         {
01034           if (ERROR == semTake (bbdMasterSem, NO_WAIT))
01035             printf ("blocked\n");
01036           else
01037             {
01038               printf ("clear\n");
01039               semGive (bbdMasterSem);
01040             }
01041         }
01042       else
01043         printf ("NOT initialized\n");
01044 
01045       /* print bbd list backwards (in order of creation) */
01046       printf ("  write id|write task|name  => read tasks\n");
01047       for (wId = NULL; wId != bbdList; wId = wId2)
01048         {
01049           for (wId2 = bbdList; wId2->next != wId; wId2 = wId2->next);
01050           strncpy (st, wId2->name, 60);
01051           st[60] = 0;
01052           printf ("%10p ", wId2);
01053           bbdPrintTaskName (wId2->taskId, 10);
01054           printf (" | \"%s\"\n        => ", st);
01055 
01056           /* print reader list forward */
01057           rId = wId2->readers;
01058           if (NULL == rId)
01059             printf ("0");
01060           else
01061             {
01062               for (; rId != NULL; rId = rId->next)
01063                 {
01064                   if (NULL == (name = taskName (rId->taskId)))
01065                     printf ("*** ");
01066                   else
01067                     printf ("%s ", name);
01068                 }
01069             }
01070           printf ("\n");
01071 
01072         }
01073       return 0;
01074     }
01075 
01076   switch (*(BBD_TYPE *) id)     /* bbd type */
01077     {
01078     case BBD_SOLE_WRITER:
01079     case BBD_MULT_WRITER:
01080       bbdShowWriter ((BBD_WRITER *) id);
01081       printf ("\n");
01082       bbdShowReaders ((BBD_WRITER *) id);
01083       break;
01084     case BBD_MULT_READER:
01085       rId = (BBD_READER *) id;
01086       wId = rId->bbd;
01087       printf ("Mult Reader:  ");
01088       strncpy (st, wId->name, 60);
01089       st[60] = 0;
01090       printf ("\"%s\"\n", st);
01091       printf ("bbd semaphore (%p) is ", wId->sem);
01092       if (ERROR == semTake (wId->sem, NO_WAIT))
01093         printf ("blocked\n");
01094       else
01095         {
01096           printf ("clear\n");
01097           semGive (wId->sem);
01098         }
01099       printf ("Writer id:  %p\n", wId);
01100       printf ("Write Cnt:  %d\n", wId->writeCnt);
01101       printf ("Read Cnt:   %d\n", rId->readCnt);
01102       if (NULL == (name = taskName (rId->taskId)))
01103         printf ("Task name: ***\nTask Id: 0x%x\n", rId->taskId);
01104       else
01105         printf ("Task name: %s\n", name);
01106 
01107       break;
01108     default:
01109       if (NULL == name)
01110         bbdShow (NULL, (char *) id);    /* maybe the id is a name: bbdShow "mybbd" */
01111       else
01112         bbdShow (NULL, name);
01113       break;
01114     }
01115   return 0;
01116 }

Generated on Sun Dec 2 15:56:48 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001