/* ========================================================================= */ int shm_read(ShmLink *cont, void *dptr, unsigned int offset, unsigned int size) { int res; if (cont == NULL) return -1; if (semtimedop(cont->sem_id, lock, 2, &timeout) < 0) { (void)snprintf(cont->err_msg, SHMCI_EMSG_SIZE, "[%s:%d] Error locking semaphore. %s", _FILE_, __LINE__, strerror(errno)); return -3; } res = shm_read_generic(dptr, offset, size, cont); if (semctl(cont->sem_id, 0, SETVAL, 0) < 0) { (void)snprintf(cont->err_msg, SHMCI_EMSG_SIZE, "[%s:%d] Error unlocking semaphore. %s", _FILE_, __LINE__, strerror(errno)); return -4; } if (res < 0) return -5; /* error description has been already written */ else return 0; }
/* block when semid[index] is negative and ms has not timeout. */ int try_lock_sem(int semid, int index, int ms) { int ret; struct sembuf op; op.sem_num= index; op.sem_op= -1; if(ms< 1){ op.sem_flg= IPC_NOWAIT; ret= semop(semid, &op, 1); if(-1== ret){ printf("try_lock_sem error: %s\n",strerror(errno)); } } else { /* to avoid unwanted exited */ op.sem_flg= SEM_UNDO; struct timespec timeout; timeout.tv_sec= ms/ 1000; timeout.tv_nsec= (ms% 1000L)* 1000000L; ret= semtimedop(semid, &op, 1, &timeout); if(-1== ret){ printf("try_lock_sem error: %s\n",strerror(errno)); } } // if(-1== ret){ // if(errno== EAGAIN) return EAGAIN; // } return ret; }
void * PassLockCode::Get(nat32 timeout) { if (timeout==0xFFFFFFFF) { sembuf op; op.sem_num = 0; op.sem_op = -1; op.sem_flg = 0; if (semop(id,&op,1)!=0) return null<void*>(); } else { sembuf op; op.sem_num = 0; op.sem_op = -1; op.sem_flg = 0; timespec to; to.tv_sec = timeout/1000; to.tv_nsec = (timeout%1000)*1000000; if (semtimedop(id,&op,1,&to)!=0) return null<void*>(); } void * ret = ptr; ptr = null<void*>(); return ret; }
/* 如sem[index]为负且不超时,则阻塞,超时则返回EAGAIN,否则将信号量减1,返回0*/ int TryLockSemaphore(int semid, int index, int milliseconds) { int ret; struct sembuf operation; operation.sem_num = index; operation.sem_op = -1; if(milliseconds<1) { operation.sem_flg = IPC_NOWAIT; ret= semop (semid, &operation, 1); } else { operation.sem_flg = SEM_UNDO; struct timespec timeout; timeout.tv_sec = (milliseconds / 1000); timeout.tv_nsec = (milliseconds - timeout.tv_sec*1000L)*1000000L; ret= semtimedop(semid, &operation, 1, &timeout); } if(ret == -1) { if(errno == EAGAIN) return EAGAIN; } return (ret == -1)? WhenError("Wait(semop)", errno):ret; }
/** * Increase or decrease the value of a semaphore, or wait the it to become 0 * * @param bus Bus information * @param semaphore The index of the semaphore, `S`, `W`, `X` or `Q` * @param delta The adjustment to make to the semaphore's value, 0 to wait for it to become 0 * @param flags `SEM_UNDO` if the action should be undone when the program exits * @param timeout The amount of time to wait before failing * @return 0 on success, -1 on error */ static int semaphore_op_timed(const bus_t *bus, int semaphore, int delta, int flags, const struct timespec *timeout) { struct sembuf op; op.sem_num = (unsigned short)semaphore; op.sem_op = (short)delta; op.sem_flg = (short)flags; return semtimedop(bus->sem_id, &op, (size_t)1, timeout); }
XnStatus XnLinuxSysVNamedEvent::Wait(XnUInt32 nMilliseconds) { XnStatus nRetVal = XN_STATUS_OK; struct timespec time = {0}; if (nMilliseconds != XN_WAIT_INFINITE) { nRetVal = xnOSGetTimeout(&time, nMilliseconds); if (nRetVal != XN_STATUS_OK) { return XN_STATUS_OS_EVENT_WAIT_FAILED; } } struct sembuf op[2]; // wait for it to be 1 op[0].sem_num = XN_EVENT_SEM_SIGNALED; op[0].sem_op = -1; op[0].sem_flg = 0; // re set it (if manual reset) op[1].sem_num = XN_EVENT_SEM_SIGNALED; op[1].sem_op = 1; op[1].sem_flg = 0; XnInt32 nOpsCount = m_bManualReset ? 2 : 1; if (XN_WAIT_INFINITE != nMilliseconds) { #if _GNU_SOURCE if (0 != semtimedop(m_hSem, op, nOpsCount, &time)) #else if (0 != semop(m_hSem, op, nOpsCount)) #endif { if(EAGAIN == errno) { return XN_STATUS_OS_EVENT_TIMEOUT; } return XN_STATUS_OS_EVENT_WAIT_FAILED; } } else { if (0 != semop(m_hSem, op, nOpsCount)) { return XN_STATUS_OS_EVENT_WAIT_FAILED; } } return (XN_STATUS_OK); }
long lx_semtimedop(int semid, void *p1, size_t nsops, struct timespec *timeout) { int r; struct sembuf *sops = (struct sembuf *)p1; lx_debug("\nsemtimedop(%d, 0x%p, %u, 0x%p)\n", semid, sops, nsops, timeout); if (nsops == 0) return (-EINVAL); r = semtimedop(semid, sops, nsops, timeout); return ((r < 0) ? -errno : r); }
int ipc_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) { int i; int ret; struct lockinfo *l; int found = 0; for (i = 0; i < num_semids; i++) { wi[i].wakeup_count = 0; } while(num > 0) { struct sembuf *sb; l = worklist_rm(); if (!l) break; if (l->data != 1) fprintf(stderr, "warning, lockinfo data was %d\n", l->data); l->data = 0; sb = wi[l->id].sb + wi[l->id].wakeup_count; sb->sem_num = l->index; sb->sem_op = 1; sb->sem_flg = IPC_NOWAIT; wi[l->id].wakeup_count++; found++; num--; } if (!found) return 0; for (i = 0; i < num_semids; i++) { int wakeup_total; int cur; int offset = 0; if (!wi[i].wakeup_count) continue; wakeup_total = wi[i].wakeup_count; while(wakeup_total > 0) { cur = wakeup_total > 64 ? 64 : wakeup_total; ret = semtimedop(semid_lookup[i], wi[i].sb + offset, cur, NULL); if (ret) { perror("semtimedop"); exit(1); } offset += cur; wakeup_total -= cur; } } return found; }
void *thread_waiter() { // when we wake up // refilling the rt_waiter thread_waiter_tid = syscall(__NR_gettid); int semid,i; struct sembuf sops[32]; timeout.tv_sec = 0; timeout.tv_nsec = 0; // init sops struct for(i = 0; i < 32; i++) { sops[i].sem_num = 0x0; sops[i].sem_op = 0x0; sops[i].sem_flg = 0x0; } sops[27].sem_op = 0xffff; sops[27].sem_flg = 0xffff; sops[28].sem_num = 0x4141; sops[28].sem_op = 0x4141; sops[28].sem_flg = 0x4444; sops[29].sem_num = 0x3333; sops[29].sem_op = 0x0000; sops[29].sem_flg = 0x4141; sops[30].sem_num = 0x0000; sops[30].sem_op = 0x4141; semid = semget(IPC_PRIVATE,200,IPC_CREAT | 0660); if (semid < 0) { printf("semget error\n"); die(); } setpriority(PRIO_PROCESS, 0, 12); printf("this is thread_waiter %d\n",thread_waiter_tid); // block on lock 1 , wait for lock2 syscall(__NR_futex, &lock1, FUTEX_WAIT_REQUEUE_PI, 0, NULL, &lock2, 0); printf("thread waiter wake up....\n"); /* refilling the rt_waiter */ semtimedop(semid,sops,32,&timeout); die(); }
bit GateLock::Queue(nat32 timeout) { sembuf op; op.sem_num = 0; op.sem_op = 0; op.sem_flg = 0; if (timeout==0xFFFFFFFF) { return semop(id,&op,1)==0; } else { timespec to; to.tv_sec = timeout/1000; to.tv_nsec = (timeout%1000)*1000000; return semtimedop(id,&op,1,&to)==0; } }
//--------------------------------------------------------------- // svipc_semtake //--------------------------------------------------------------- int svipc_semtake(key_t key, int id, int count, float wait) { int sempoolid, status; Debug(5, "svipc_semtake %f\n", wait); struct timespec timeout, *pto = NULL; if (wait >= 0.0) { timeout.tv_sec = (time_t) wait; timeout.tv_nsec = (long int)((wait - timeout.tv_sec) * 1e9); pto = &timeout; } sempoolid = semget(key, 0, 0666); if (sempoolid == -1) { perror("sempoolid semget failed"); return -1; } // take the semaphore struct sembuf sops; sops.sem_num = id; sops.sem_op = -count; // sops.sem_flg = 0; // fixme - undo if interrupted? status = semtimedop(sempoolid, &sops, 1, pto); if (status == -1) { if (errno != EAGAIN) { perror("semop failed"); } return -1; } return 0; }
/* ========================================================================= */ int shm_clean(ShmLink *cont) { if (cont == NULL) return -1; if (semtimedop(cont->sem_id, lock, 2, &timeout) < 0) { (void)snprintf(cont->err_msg, SHMCI_EMSG_SIZE, "[%s:%d] Error locking semaphore. %s", _FILE_, __LINE__, strerror(errno)); return -2; } memset(cont->ptr,0,cont->shm_size); if (semctl(cont->sem_id, 0, SETVAL, 0) < 0) { (void)snprintf(cont->err_msg, SHMCI_EMSG_SIZE, "[%s:%d] Error unlocking semaphore. %s", _FILE_, __LINE__, strerror(errno)); return -3; } return 0; }
/** * Decrements the client's semaphor (to read the next available chunk) */ static int decrement_client (xmmsc_vis_unixshm_t *t, unsigned int blocking) { /* alter semaphore 1 by -1, no flags */ struct sembuf op = { 1, -1, 0 }; struct timespec time; time.tv_sec = blocking / 1000; time.tv_nsec = (blocking % 1000) * 1000000; if (semtimedop (t->semid, &op, 1, &time) == -1) { switch (errno) { case EAGAIN: case EINTR: return 0; case EINVAL: case EIDRM: return -1; default: perror ("Unexpected semaphore problem"); return -1; } } return 1; }
static int absem_wait(void) { int absem; struct sembuf sops; long now; long start_wait; struct timespec timeout; if((absem = absem_get(0)) < 0) { perror(__FUNCTION__); return absem; } sops.sem_num = 0; sops.sem_op = -1; sops.sem_flg = 0; start_wait = time(NULL); timeout.tv_sec = timeout_seconds; timeout.tv_nsec = 0; if(semtimedop(absem, &sops, 1, &timeout) < 0) { switch(errno) { case EIDRM: /* Removed -- OK */ break; case EAGAIN: /* Timeout -- Report */ fprintf(stderr, "Astribanks waiting timed out\n"); return -errno; default: /* Unexpected errors */ perror("semop"); return -errno; } /* fall-thgough */ } now = time(NULL); if(debug) fprintf(stderr, "%s: waited on absem %ld seconds\n", progname, now - start_wait); if(verbose) printf("Finished after %ld seconds\n", now - start_wait); return 0; }
bool CSem::TryWait(struct timespec *ts) { struct sembuf sb; sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO | IPC_NOWAIT; /// no wait if (ts == NULL) { if (semop(m_semid, &sb, 1) == -1) { if (errno != EAGAIN) { fprintf(stderr, "semop wait error![%s:%d][%s]\n", __FILE__, __LINE__,strerror(errno)); } return false; } return true; } ///wait time for (int i = 0;i < 5; i++) { if (semtimedop(m_semid, &sb, 1, ts) == -1) { if (errno != EAGAIN) { fprintf(stderr, "semtimedop wait error![%s:%d][%s]\n", __FILE__, __LINE__,strerror(errno)); return false; } else if (errno == EINTR) { continue; } else { return false; } } else { return true; } } return false; }
/* ipc semaphore post& wait */ void wait_ipc_sem(struct lockinfo *l) { struct sembuf sb; int ret; struct timespec *tvp = NULL; struct timespec tv = { 0, 1 }; sb.sem_num = l->index; sb.sem_flg = 0; sb.sem_op = -1; l->data = 1; if (timeout_test && (l->id % 5) == 0) tvp = &tv; worklist_add(l); ret = semtimedop(semid_lookup[l->id], &sb, 1, tvp); while(l->data != 0 && tvp) { struct timespec tv2 = { 0, 500 }; nanosleep(&tv2, NULL); } if (l->data != 0) { if (tvp) return; fprintf(stderr, "wakeup without data update\n"); exit(1); } if (ret) { if (errno == EAGAIN && tvp) return; perror("semtimed op"); exit(1); } }
bit EventLock::Get(nat32 timeout) { if (timeout==0xFFFFFFFF) { sembuf op; op.sem_num = 0; op.sem_op = -1; op.sem_flg = 0; return semop(id,&op,1)==0; } else { sembuf op; op.sem_num = 0; op.sem_op = -1; op.sem_flg = 0; timespec to; to.tv_sec = timeout/1000; to.tv_nsec = (timeout%1000)*1000000; return semtimedop(id,&op,1,&to)==0; } }
static int run_child(void) { int child2; int status; struct sembuf ops[2]; struct timespec ts = { 0, 20000000 }; struct timespec ts_short = { 0, 10000000 }; struct timespec ts_long = { 10000, 0 }; union semun un_arg; struct semid_ds* ds; struct seminfo* si; unsigned short* array; ops[0].sem_num = 0; ops[0].sem_op = 1; ops[0].sem_flg = SEM_UNDO; ops[1].sem_num = 1; ops[1].sem_op = 1; ops[1].sem_flg = SEM_UNDO; test_assert(0 == semop(semid, ops, 2)); *shmem = 0; ALLOCATE_GUARD(ds, 'd'); un_arg.buf = ds; test_assert(0 == semctl(semid, 0, IPC_STAT, un_arg)); VERIFY_GUARD(ds); test_assert(ds->sem_perm.mode == 0666); test_assert(ds->sem_nsems == COUNT); ds->sem_perm.mode = 0660; test_assert(0 == semctl(semid, 0, IPC_SET, un_arg)); ALLOCATE_GUARD(si, 'i'); un_arg.__buf = si; /* The following syscall should always return >= 1, but sometimes it returns 0. I don't know why. */ test_assert(0 <= semctl(semid, 0, IPC_INFO, un_arg)); VERIFY_GUARD(si); test_assert(si->semvmx > 0); test_assert(si->semusz < 100000); /* The following syscall should always return >= 1, but sometimes it returns 0. I don't know why. */ test_assert(0 <= semctl(semid, 0, SEM_INFO, un_arg)); VERIFY_GUARD(si); test_assert(si->semusz > 0); test_assert(si->semusz < 100000); array = allocate_guard(COUNT * sizeof(*array), 'a'); un_arg.array = array; test_assert(0 == semctl(semid, 0, GETALL, un_arg)); verify_guard(COUNT * sizeof(*array), array); test_assert(array[0] == 1); test_assert(array[1] == 1); test_assert(array[2] == 0); test_assert(array[3] == 0); array[2] = 2; test_assert(0 == semctl(semid, 0, SETALL, un_arg)); test_assert(0 == semctl(semid, 1, GETNCNT, NULL)); test_assert(getpid() == semctl(semid, 1, GETPID, NULL)); test_assert(2 == semctl(semid, 2, GETVAL, NULL)); test_assert(0 == semctl(semid, 0, GETZCNT, NULL)); un_arg.val = 0; test_assert(0 == semctl(semid, 2, SETVAL, un_arg)); if ((child2 = fork()) == 0) { ops[0].sem_op = -1; ops[1].sem_op = -1; /* The semtimedop timeout is irrelevant. We're just checking that the syscall works. */ test_assert(0 == semtimedop(semid, ops, 2, &ts_long)); *shmem = 1; test_assert(0 == nanosleep(&ts, NULL)); *shmem = 0; ops[0].sem_op = 1; ops[1].sem_op = 1; test_assert(0 == semtimedop(semid, ops, 2, &ts)); return 0; } test_assert(0 == nanosleep(&ts_short, NULL)); ops[0].sem_op = -1; ops[1].sem_op = -1; test_assert(0 == semop(semid, ops, 2)); test_assert(*shmem == 0); ops[0].sem_op = 1; ops[1].sem_op = 1; test_assert(0 == semop(semid, ops, 2)); test_assert(child2 == waitpid(child2, &status, __WALL)); test_assert(0 == status); return 0; }
int main(void) { static const int bogus_semid = 0xfdb97531; static void * const bogus_sops = (void *) -1L; static const size_t bogus_nsops = (size_t) 0xdefaceddeadbeefULL; TAIL_ALLOC_OBJECT_CONST_PTR(struct timespec, ts); int rc; id = semget(IPC_PRIVATE, 1, 0600); if (id < 0) perror_msg_and_skip("semget"); atexit(cleanup); union semun sem_union = { .val = 0 }; if (semctl(id, 0, SETVAL, sem_union) == -1) perror_msg_and_skip("semctl"); TAIL_ALLOC_OBJECT_CONST_PTR(struct sembuf, sem_b); TAIL_ALLOC_OBJECT_CONST_PTR(struct sembuf, sem_b2); rc = semop(bogus_semid, NULL, bogus_nsops); printf("semop(%d, NULL, %u) = %s\n", bogus_semid, (unsigned) bogus_nsops, sprintrc(rc)); rc = semop(bogus_semid, bogus_sops, 1); printf("semop(%d, %p, %u) = %s\n", bogus_semid, bogus_sops, 1, sprintrc(rc)); sem_b->sem_num = 0; sem_b->sem_op = 1; sem_b->sem_flg = SEM_UNDO; sem_b2->sem_num = 0xface; sem_b2->sem_op = 0xf00d; sem_b2->sem_flg = 0xbeef; rc = semop(bogus_semid, sem_b2, 2); printf("semop(%d, [{%hu, %hd, %s%s%#hx}, ... /* %p */], %u) = %s\n", bogus_semid, sem_b2->sem_num, sem_b2->sem_op, sem_b2->sem_flg & SEM_UNDO ? "SEM_UNDO|" : "", sem_b2->sem_flg & IPC_NOWAIT ? "IPC_NOWAIT|" : "", (short) (sem_b2->sem_flg & ~(SEM_UNDO | IPC_NOWAIT)), sem_b2 + 1, 2, sprintrc(rc)); if (semop(id, sem_b, 1)) perror_msg_and_skip("semop, 1"); printf("semop(%d, [{0, 1, SEM_UNDO}], 1) = 0\n", id); sem_b->sem_op = -1; if (semop(id, sem_b, 1)) perror_msg_and_skip("semop, -1"); printf("semop(%d, [{0, -1, SEM_UNDO}], 1) = 0\n", id); rc = semtimedop(bogus_semid, NULL, bogus_nsops, NULL); printf("semtimedop(%d, NULL, %u, NULL) = %s\n", bogus_semid, (unsigned) bogus_nsops, sprintrc(rc)); rc = semtimedop(id, sem_b + 1, 1, ts + 1); printf("semtimedop(%d, %p, 1, %p) = %s\n", id, sem_b + 1, ts + 1, sprintrc(rc)); ts->tv_sec = 1; ts->tv_nsec = 123456789; rc = semtimedop(bogus_semid, sem_b2, 2, ts); printf("semtimedop(%d, [{%hu, %hd, %s%s%#hx}, ... /* %p */], %u" ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n", bogus_semid, sem_b2->sem_num, sem_b2->sem_op, sem_b2->sem_flg & SEM_UNDO ? "SEM_UNDO|" : "", sem_b2->sem_flg & IPC_NOWAIT ? "IPC_NOWAIT|" : "", (short) (sem_b2->sem_flg & ~(SEM_UNDO | IPC_NOWAIT)), sem_b2 + 1, 2, (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec), sprintrc(rc)); sem_b->sem_op = 1; if (semtimedop(id, sem_b, 1, NULL)) perror_msg_and_skip("semtimedop, 1"); printf("semtimedop(%d, [{0, 1, SEM_UNDO}], 1, NULL) = 0\n", id); sem_b->sem_op = -1; if (semtimedop(id, sem_b, 1, ts)) perror_msg_and_skip("semtimedop, -1"); printf("semtimedop(%d, [{0, -1, SEM_UNDO}], 1" ", {tv_sec=%lld, tv_nsec=%llu}) = 0\n", id, (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec)); sem_b->sem_op = 1; ts->tv_sec = 0xdeadbeefU; ts->tv_nsec = 0xfacefeedU; rc = semtimedop(id, sem_b, 1, ts); printf("semtimedop(%d, [{0, 1, SEM_UNDO}], 1" ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n", id, (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec), sprintrc(rc)); sem_b->sem_op = -1; ts->tv_sec = (time_t) 0xcafef00ddeadbeefLL; ts->tv_nsec = (long) 0xbadc0dedfacefeedLL; rc = semtimedop(id, sem_b, 1, ts); printf("semtimedop(%d, [{0, -1, SEM_UNDO}], 1" ", {tv_sec=%lld, tv_nsec=%llu}) = %s\n", id, (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec), sprintrc(rc)); puts("+++ exited with 0 +++"); return 0; }
XN_C_API XnStatus xnOSLockMutex(const XN_MUTEX_HANDLE MutexHandle, XnUInt32 nMilliseconds) { // Local function variables XnStatus nRetVal = XN_STATUS_OK; int rc = 0; // Make sure the actual mutex handle isn't NULL XN_RET_IF_NULL(MutexHandle, XN_STATUS_OS_INVALID_MUTEX); #ifndef XN_PLATFORM_LINUX_NO_SYSV struct sembuf op; // try to decrease it by 1 (if it's 0, we'll wait) op.sem_num = 0; op.sem_op = -1; op.sem_flg = SEM_UNDO; #endif if (nMilliseconds == XN_WAIT_INFINITE) { // lock via the OS if (MutexHandle->bIsNamed) { #ifndef XN_PLATFORM_LINUX_NO_SYSV if (0 != semop(MutexHandle->NamedSem, &op, 1)) { rc = errno; } #endif } else { rc = pthread_mutex_lock(&MutexHandle->ThreadMutex); } } else { struct timespec time; // lock via the OS if (MutexHandle->bIsNamed) { #ifndef XN_PLATFORM_LINUX_NO_SYSV nRetVal = xnOSGetTimeout(&time, nMilliseconds); if (nRetVal != XN_STATUS_OK) { return XN_STATUS_OS_MUTEX_LOCK_FAILED; } #ifndef XN_PLATFORM_HAS_NO_TIMED_OPS if (0 != semtimedop(MutexHandle->NamedSem, &op, 1, &time)) #else if (0 != semop(MutexHandle->NamedSem, &op, 1)) #endif { rc = errno; } #endif } else { // calculate timeout absolute time. First we take current time nRetVal = xnOSGetAbsTimeout(&time, nMilliseconds); if (nRetVal != XN_STATUS_OK) { return XN_STATUS_OS_MUTEX_LOCK_FAILED; } #ifndef XN_PLATFORM_HAS_NO_TIMED_OPS rc = pthread_mutex_timedlock(&MutexHandle->ThreadMutex, &time); #else rc = pthread_mutex_lock(&MutexHandle->ThreadMutex); #endif } } // check for failures if (rc == ETIMEDOUT) { return (XN_STATUS_OS_MUTEX_TIMEOUT); } else if (rc != 0) { return (XN_STATUS_OS_MUTEX_LOCK_FAILED); } // All is good... return (XN_STATUS_OK); }
void initialize_semaphore_set(semian_resource_t* res, const char* id_str, long permissions, int tickets, double quota) { res->key = generate_key(id_str); res->strkey = (char*) malloc((2 /*for 0x*/+ sizeof(uint64_t) /*actual key*/+ 1 /*null*/) * sizeof(char)); sprintf(res->strkey, "0x%08x", (unsigned int) res->key); res->sem_id = semget(res->key, SI_NUM_SEMAPHORES, IPC_CREAT | IPC_EXCL | permissions); /* This approach is based on http://man7.org/tlpi/code/online/dist/svsem/svsem_good_init.c.html which avoids race conditions when initializing semaphore sets. */ if (res->sem_id != -1) { // Happy path - we are the first worker, initialize the semaphore set. initialize_new_semaphore_values(res->sem_id, permissions); } else { // Something went wrong if (errno != EEXIST) { raise_semian_syscall_error("semget() failed to initialize semaphore values", errno); } else { // The semaphore set already exists, ensure it is initialized res->sem_id = wait_for_new_semaphore_set(res->key, permissions); } } set_semaphore_permissions(res->sem_id, permissions); /* Ensure that a worker for this process is registered. Note that from ruby we ensure that at most one worker may be registered per process. */ if (perform_semop(res->sem_id, SI_SEM_REGISTERED_WORKERS, 1, SEM_UNDO, NULL) == -1) { rb_raise(eInternal, "error incrementing registered workers, errno: %d (%s)", errno, strerror(errno)); } int state = 0; sem_meta_lock(res->sem_id); // Sets otime for the first time by acquiring the sem lock configure_tickets_args_t configure_tickets_args = (configure_tickets_args_t){ .sem_id = res->sem_id, .tickets = tickets, .quota = quota, }; rb_protect( configure_tickets, (VALUE)&configure_tickets_args, &state); sem_meta_unlock(res->sem_id); if (state) { rb_jump_tag(state); } } void set_semaphore_permissions(int sem_id, long permissions) { union semun sem_opts; struct semid_ds stat_buf; sem_opts.buf = &stat_buf; semctl(sem_id, 0, IPC_STAT, sem_opts); if ((stat_buf.sem_perm.mode & 0xfff) != permissions) { stat_buf.sem_perm.mode &= ~0xfff; stat_buf.sem_perm.mode |= permissions; semctl(sem_id, 0, IPC_SET, sem_opts); } } int perform_semop(int sem_id, short index, short op, short flags, struct timespec *ts) { struct sembuf buf = { 0 }; buf.sem_num = index; buf.sem_op = op; buf.sem_flg = flags; if (ts) { return semtimedop(sem_id, &buf, 1, ts); } else { return semop(sem_id, &buf, 1); } } int get_sem_val(int sem_id, int sem_index) { int ret = semctl(sem_id, sem_index, GETVAL); if (ret == -1) { rb_raise(eInternal, "error getting value of %s for sem %d, errno: %d (%s)", SEMINDEX_STRING[sem_index], sem_id, errno, strerror(errno)); } return ret; }
memset(&ds, 0, sizeof(ds)); ASSERT_EQ(0, semctl(id, 0, IPC_STAT, &ds)); ASSERT_EQ(1U, ds.sem_nsems); ASSERT_EQ(0, semctl(id, 0, GETVAL)); // Increment. sembuf ops[] = {{ .sem_num = 0, .sem_op = 1, .sem_flg = 0 }}; ASSERT_EQ(0, semop(id, ops, 1)); ASSERT_EQ(1, semctl(id, 0, GETVAL)); // Test timeouts. timespec ts = { .tv_sec = 0, .tv_nsec = 100 }; ops[0] = { .sem_num = 0, .sem_op = 0, .sem_flg = 0 }; errno = 0; ASSERT_EQ(-1, semtimedop(id, ops, 1, &ts)); ASSERT_EQ(EAGAIN, errno); ASSERT_EQ(1, semctl(id, 0, GETVAL)); // Decrement. ops[0] = { .sem_num = 0, .sem_op = -1, .sem_flg = 0 }; ASSERT_EQ(0, semop(id, ops, 1)); ASSERT_EQ(0, semctl(id, 0, GETVAL)); // Destroy the semaphore. ASSERT_EQ(0, semctl(id, 0, IPC_RMID)); } TEST(sys_sem, semget_failure) { errno = 0; ASSERT_EQ(-1, semget(-1, -1, 0));
int main(int argc, char **argv) { int semid; struct sembuf sop; #ifdef HAVE_SEMTIMEDOP struct timespec ts; #endif if ((semid = semget(IPC_PRIVATE, 1, 0600)) < 0) { perror("semget"); exit(1); } sop.sem_num = 0; sop.sem_op = 1; sop.sem_flg = 0; if (semop(semid, &sop, 1) < 0) { perror("semop"); semctl(semid, 0, IPC_RMID); exit(1); } if (semctl(semid, 0, GETVAL) != 1) { perror("semctl GETVAL"); semctl(semid, 0, IPC_RMID); exit(1); } if (semctl(semid, 0, GETPID) != getpid()) { perror("semctl GETPID"); semctl(semid, 0, IPC_RMID); exit(1); } /* The next call to semtimedop causes the program to hang on ppc32-linux (Yellow Dog 4.0). I don't know why. Hence the extended ifdef. */ #if defined(HAVE_SEMTIMEDOP) && !defined(__powerpc__) sop.sem_num = 0; sop.sem_op = 0; sop.sem_flg = 0; ts.tv_sec = 0; ts.tv_nsec = 1000000; if (semtimedop(semid, &sop, 1, &ts) < 0 && errno != EAGAIN) { perror("semtimedop"); semctl(semid, 0, IPC_RMID); exit(1); } #endif sop.sem_num = 0; sop.sem_op = -1; sop.sem_flg = 0; if (semop(semid, &sop, 1) < 0) { perror("semop"); semctl(semid, 0, IPC_RMID); exit(1); } #ifdef HAVE_SEMTIMEDOP sop.sem_num = 0; sop.sem_op = 0; sop.sem_flg = 0; ts.tv_sec = 0; ts.tv_nsec = 1000; if (semtimedop(semid, &sop, 1, &ts) < 0) { perror("semtimedop"); semctl(semid, 0, IPC_RMID); exit(1); } #endif if (semctl(semid, 0, IPC_RMID) < 0) { perror("semctl(IPC_RMID)"); exit(1); } exit(0); }
XN_C_API XnStatus xnOSLockMutex(const XN_MUTEX_HANDLE MutexHandle, XnUInt32 nMilliseconds) { // Local function variables XnStatus nRetVal = XN_STATUS_OK; int rc = 0; // Make sure the actual mutex handle isn't NULL XN_RET_IF_NULL(MutexHandle, XN_STATUS_OS_INVALID_MUTEX); struct sembuf op; // try to decrease it by 1 (if it's 0, we'll wait) op.sem_num = 0; op.sem_op = -1; op.sem_flg = SEM_UNDO; if (nMilliseconds == XN_WAIT_INFINITE) { // lock via the OS if (MutexHandle->bIsNamed) { if (0 != semop(MutexHandle->NamedSem, &op, 1)) { rc = errno; } } else { rc = pthread_mutex_lock(&MutexHandle->ThreadMutex); } } else { // calculate timeout absolute time. First we take current time struct timespec time; time.tv_sec = (nMilliseconds / 1000); time.tv_nsec = ((nMilliseconds % 1000) * 1000000); // lock via the OS if (MutexHandle->bIsNamed) { if (0 != semtimedop(MutexHandle->NamedSem, &op, 1, &time)) { rc = errno; } } else { rc = pthread_mutex_timedlock(&MutexHandle->ThreadMutex, &time); } } // check for failures if (rc == ETIMEDOUT) { return (XN_STATUS_OS_MUTEX_TIMEOUT); } else if (rc != 0) { return (XN_STATUS_OS_MUTEX_LOCK_FAILED); } // All is good... return (XN_STATUS_OK); }
int main(void) { key_t key; int sem; semun_t arg; int ret; struct sembuf semwait, semsignal; struct timespec timeout; /* * This is not meant to be functionally * correct, it is just used to check we * can build minimal POSIX semaphore * based code */ key = (key_t)getpid(); sem = semget(key, 1, IPC_CREAT | S_IRUSR | S_IWUSR); arg.val = 1; ret = semctl(sem, 0, SETVAL, arg); (void)ret; semwait.sem_num = 0; semwait.sem_op = -1; semwait.sem_flg = SEM_UNDO; (void)semwait; (void)clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec++; #if defined(__linux__) ret = semtimedop(sem, &semwait, 1, &timeout); (void)ret; #endif semsignal.sem_num = 0; semsignal.sem_op = 1; semsignal.sem_flg = SEM_UNDO; ret = semop(sem, &semsignal, 1); (void)ret; #if defined(IPC_STAT) { struct semid_ds ds; semun_t s; s.buf = &ds; ret = semctl(sem, 0, IPC_STAT, &s); (void)ret; } #endif #if defined(SEM_STAT) { struct semid_ds ds; semun_t s; s.buf = &ds; ret = semctl(sem, 0, SEM_STAT, &s); (void)ret; } #endif #if defined(IPC_INFO) && defined(__linux__) { struct seminfo si; semun_t s; s.__buf = &si; ret = semctl(sem, 0, IPC_INFO, &s); (void)ret; } #endif #if defined(SEM_INFO) && defined(__linux__) { struct seminfo si; semun_t s; s.__buf = &si; ret = semctl(sem, 0, SEM_INFO, &s); (void)ret; } #endif #if defined(GETVAL) ret = semctl(sem, 0, GETVAL); (void)ret; #endif #if defined(GETPID) ret = semctl(sem, 0, GETPID); (void)ret; #endif #if defined(GETNCNT) ret = semctl(sem, 0, GETNCNT); (void)ret; #endif #if defined(GEZCNT) ret = semctl(sem, 0, GETZCNT); (void)ret; #endif ret = semctl(sem, 0, IPC_RMID); (void)ret; return 0; }