void shmfifo_getpriv (struct shmhandle *shm, void *priv) { (void)shmfifo_lock (shm); memcpy (priv, (char *) shm->mem + sizeof (struct shmprefix), shm->privsz); (void)shmfifo_unlock (shm); }
/* * Waits for a shared-memory FIFO to be notified. The shared-memory FIFO must * be locked. * * Arguments: * shm Pointer to the shared-memory FIFO. * semIndex The index of the semaphore to wait upon. One of * SI_READER or SI_WRITER. * Returns: * 0 Success. Another thread of control has locked and * released the FIFO. Upon return, the shared-memory FIFO * shall be locked. * EINVAL "shm" uninitialized. Error-message logged. * EINVAL The FIFO isn't locked by the current process. * Error-message logged. * EINVAL "semIndex" isn't SI_READER or SI_WRITER. * ECANCELED Operating-system failure. Error-message logged. * Raises: * SIGSEGV if "shm" is NULL. */ static int shmfifo_wait( const struct shmhandle* const shm, const SemIndex semIndex) { int status = vetSemIndex(semIndex); if (0 == status) { /* Release the lock */ if ((status = shmfifo_unlock(shm)) == 0) { struct sembuf op[1]; /* Wait for a notification from the other process */ op[0].sem_num = semIndex; op[0].sem_op = -1; op[0].sem_flg = 0; if (semop(shm->semid, op, 1) == -1) { log_syserr("semop() failure"); status = ECANCELED; } /* Reacquire the lock */ if (shmfifo_lock(shm) != 0) { status = ECANCELED; } /* lock reacquired */ } /* lock released */ } /* valid "semIndex" */ return status; }
static int shmfifo_ll_get (const struct shmhandle* const shm, void *data, int sz) { struct shmprefix *p; int copysz; p = (struct shmprefix *) shm->mem; p->counter++; if (sz <= 0) { log_error ("sanity check failed in ll_get. sz is %d", sz); (void)shmfifo_unlock (shm); abort (); } if (shmfifo_ll_memused (shm) < sz) return -1; if (p->write > p->read) { /* normal */ copysz = p->write - p->read; if (copysz > sz) copysz = sz; } else { copysz = shm->sz - p->read; if (copysz > sz) copysz = sz; } memcpy (data, (char *) shm->mem + p->read, copysz); p->read += copysz; if (p->read == shm->sz) p->read = shm->privsz + sizeof (struct shmprefix); if (copysz < sz) { memcpy (&((char *) data)[copysz], (char *) shm->mem + p->read, sz - copysz); p->read += sz - copysz; } return sz; }
static void shmfifo_printmemstatus (const struct shmhandle* const shm) { struct shmprefix *p; if (ulogIsDebug ()) { (void)shmfifo_lock (shm); p = (struct shmprefix *) shm->mem; nplDebug ("<%d> c: %d sz: %d, r: %d, w: %d, used: %d, free: %d, maxblock: %d", getpid (), p->counter, shm->sz, p->read, p->write, shmfifo_ll_memused (shm), shmfifo_ll_memfree (shm), shmfifo_ll_memfree (shm) - sizeof (struct shmbh)); (void)shmfifo_unlock (shm); } return; }
/* * Reads one record's worth of data from the FIFO and writes it to a * client-supplied buffer. Blocks until data is available. * * Arguments: * shm Pointer to the shared-memory FIFO data-structure. The * FIFO must be unlocked. * data Pointer to the buffer into which to put data from the * FIFO. * sz The size of the buffer in bytes. * nbytes Pointer to the memory location to be set to the number * of bytes read. * Returns: * 0 Success. "*nbytes" is set to the number of bytes read. * ECANCELED Operating-system failure. Error-message logged. * EINVAL "shm" uninitialized. Error-message logged. * EINVAL "sz" is non-positive. Error-message logged. * EINVAL The buffer is too small for the record's data. No data * is read. Error-message logged. * EIO FIFO is corrupt. Error-message logged. * Raises: * SIGSEGV if "shm" is NULL * SIGSEGV if "data" is NULL * SIGSEGV if "nbytes" is NULL * SIGABRT if "shm" is uninitialized */ int shmfifo_get( const struct shmhandle* const shm, void* const data, const int sz, int* const nbytes) { int status; if (sz <= 0) { log_error("Non-positive number of bytes to read: %d", sz); status = EINVAL; } else { int loggedEmptyFifo = 0; if ((status = shmfifo_lock(shm)) == 0) { shmfifo_printmemstatus(shm); for (status = 0; shmfifo_ll_memused(shm) == 0; ) { if (!loggedEmptyFifo) { log_info("shmfifo_get(): FIFO is empty"); loggedEmptyFifo = 1; } if ((status = shmfifo_wait_reader(shm)) != 0) { break; } } if (0 == status) { struct shmbh header; if (shmfifo_ll_memused(shm) < (int)sizeof(header)) { log_error("Insufficient data for a record: " "should be at least %d bytes; was %d bytes", sizeof(header), shmfifo_ll_memused(shm)); shmfifo_print(shm); status = EINVAL; } else { shmfifo_ll_get(shm, &header, sizeof(header)); if (header.canary != 0xDEADBEEF) { log_error("Invalid header sentinel: 0x%X", header.canary); status = EIO; } else if (shmfifo_ll_memused(shm) < header.sz) { log_error("Inconsistent data-length of record: " "expected %d bytes; encountered %d bytes", header.sz, shmfifo_ll_memused(shm)); shmfifo_print(shm); status = EIO; } else if (header.sz > sz) { log_error("Client-supplied buffer too small: " "need %d bytes; %d bytes supplied", header.sz, sz); shmfifo_ll_hrewind(shm); status = EINVAL; } else { shmfifo_ll_get(shm, data, header.sz); if (loggedEmptyFifo) { log_info("shmfifo_get(): " "Got %d bytes of data from FIFO", header.sz); } shmfifo_printmemstatus(shm); if ((status = shmfifo_notify_writer(shm)) == 0) { *nbytes = header.sz; } } } } /* FIFO has data */ int tmpStatus = shmfifo_unlock(shm); if (status == 0) status = tmpStatus; } /* shared-memory FIFO locked */ } return status; }
/* * Writes data to the shared-memory FIFO. * * Arguments: * shm Pointer to the shared-memory FIFO data-structure. * data Pointer to the data to be written. * sz The amount of data to be written in bytes. * Returns: * 0 Success. * E2BIG "sz" is larger than the FIFO can handle. Error-message * logged. * ECANCELED Operating-system failure. Error-message logged. * EIO I/O error. Error-message logged. * EINVAL "sz" is negative. Error-message logged. * EINVAL "shm" uninitialized. Error-message logged. */ int shmfifo_put( const struct shmhandle* const shm, void* const data, const int sz) { int status; if (0 > sz) { log_error("Invalid size argument: %d", sz); status = EINVAL; } else { if ((status = shmfifo_lock(shm)) == 0) { struct shmbh header; const size_t totalBytesToWrite = sz + sizeof(header); size_t maxSize; shmfifo_printmemstatus(shm); maxSize = shmfifo_ll_memused(shm) + shmfifo_ll_memfree(shm); if (maxSize < totalBytesToWrite) { log_error("Record bigger than entire FIFO: " "record is %lu bytes; FIFO capacity is %lu bytes", totalBytesToWrite, maxSize); status = E2BIG; } else { int loggedNoRoom = 0; int freeSpace; status = 0; /* * Wait for the FIFO to have room for the data. */ while ((freeSpace = shmfifo_ll_memfree(shm)) <= totalBytesToWrite) { if (!loggedNoRoom) { log_error("No room in FIFO: " "need %d bytes; only %d bytes available. " "Waiting...", totalBytesToWrite, freeSpace); loggedNoRoom = 1; } if ((status = shmfifo_wait_writer(shm)) != 0) { break; } } if (0 == status) { header.sz = sz; header.canary = 0xDEADBEEF; shmfifo_ll_put(shm, &header, sizeof(header)); shmfifo_ll_put(shm, data, sz); if (loggedNoRoom) { log_info("shmfifo_put(): Wrote %d bytes to FIFO", totalBytesToWrite); } status = shmfifo_notify_reader(shm); } } int tmpStatus = shmfifo_unlock(shm); if (status == 0) status = tmpStatus; } /* shared-memory FIFO locked */ } // `sz` is valid return status; }