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 }
1.2.11.1 written by Dimitri van Heesch,
© 1997-2001