static int _svcond_signal(svcond_t *cond, int broadcast) { int signals_to_issue; if (svsem_wait(cond->unblock_lock) == -1) { AMSG(""); return -1; } if (cond->waiters_to_unblock) { if (cond->waiters_blocked == 0) { if (svsem_post(cond->unblock_lock) == -1) { AMSG(""); return -1; } return 0; } if (broadcast) { cond->waiters_to_unblock += signals_to_issue = cond->waiters_blocked; cond->waiters_blocked = 0; } else { signals_to_issue = 1; cond->waiters_to_unblock++; cond->waiters_blocked--; } } else if (cond->waiters_blocked) { if (svsem_wait(cond->blocked_lock) == -1) { AMSG(""); return -1; } if (broadcast) { signals_to_issue = cond->waiters_to_unblock = cond->waiters_blocked; cond->waiters_blocked = 0; } else { signals_to_issue = cond->waiters_to_unblock = 1; cond->waiters_blocked--; } } else { if (svsem_post(cond->unblock_lock) == -1) { AMSG(""); return -1; } return 0; } if (svsem_post(cond->unblock_lock) == -1 || svsem_post_multiple(cond->block_queue, signals_to_issue) == -1) { AMSG(""); return -1; } return 0; }
int svcond_wait(svcond_t *cond, svsem_t *sem) { int signals_left = 0; if (svsem_wait(cond->blocked_lock) == -1) { AMSG(""); return -1; } cond->waiters_blocked++; svsem_post(cond->blocked_lock); svsem_post(sem); if (svsem_wait(cond->block_queue) == -1) { int err = errno; AMSG(""); cond->waiters_blocked--; while (svsem_wait(sem) == -1 && errno == EINTR) { ; } errno = err; return -1; } if (svsem_wait(cond->unblock_lock) == -1) { int err = errno; AMSG(""); while (svsem_wait(sem) == -1 && errno == EINTR) { ; } errno = err; return -1; } if ((signals_left = cond->waiters_to_unblock)) { cond->waiters_to_unblock--; } svsem_post(cond->unblock_lock); if (signals_left == 1) { svsem_post(cond->blocked_lock); } while (svsem_wait(sem) == -1) { if (errno != EINTR) { AMSG(""); return -1; } } return 0; }
int run(void) { int fd, *ptr, i; svsem_t sem; if ((fd = open("/tmp/SvsemCounter.shm", O_RDWR | O_CREAT, 0600)) == -1 || ftruncate(fd, sizeof *ptr) == -1 || (ptr = (int *)mmap(NULL, sizeof *ptr, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == NULL) { return -1; } close(fd); if (svsem_open(&sem, "/tmp/SvsemCounter.sem", SEM_UNDO) == -1) { return -1; } for (i = 0; i < count; i++) { svsem_wait(&sem); (*ptr)++; svsem_post(&sem); } svsem_close(&sem); munmap((void *)ptr, sizeof *ptr); return 0; }
int svcond_destroy(svcond_t *cond) { int ret = 0; if (svsem_wait(cond->blocked_lock) == -1) { AMSG(""); return -1; } if (svsem_trywait(cond->unblock_lock) != 0) { AMSG(""); svsem_post(cond->blocked_lock); return -1; } if (cond) { if (cond->blocked_lock) { ret += pool_release(cond->sempool, cond->blocked_lock); if (cond->block_queue) { ret += pool_release(cond->sempool, cond->block_queue); if (cond->unblock_lock) { ret += pool_release(cond->sempool, cond->unblock_lock); cond->unblock_lock = NULL; } cond->block_queue = NULL; } cond->blocked_lock = NULL; } } return ret ? -1 : 0; }