void plat_try_sem_post(sem_t* sem, vogl::uint32 release_count) { if (1 == release_count) sem_post(sem); else sem_post_multiple(sem, release_count); }
void semaphore::release(uint32 releaseCount) { VOGL_ASSERT(releaseCount >= 1); int status = 0; #ifdef WIN32 if (1 == releaseCount) status = sem_post(&m_sem); else status = sem_post_multiple(&m_sem, releaseCount); #else while (releaseCount > 0) { status = sem_post(&m_sem); if (status) break; releaseCount--; } #endif if (status) { VOGL_FAIL("semaphore: sem_post() or sem_post_multiple() failed"); } }
int plat_sem_post(sem_t* sem, vogl::uint32 release_count) { if (1 == release_count) return sem_post(sem); return sem_post_multiple(sem, release_count); }
int pthread_barrier_wait(pthread_barrier_t *b_) { long sel; int r, e, rslt; barrier_t *b; r = barrier_ref(b_); if(r) return r; b = (barrier_t *)*b_; if ((r = pthread_mutex_lock(&b->m))) return barrier_unref(b_,EINVAL); sel = b->sel; InterlockedDecrement((long*)&b->total); if (b->total == 0) { b->total = b->count; b->sel = (sel != 0 ? 0 : 1); e = 1; rslt = PTHREAD_BARRIER_SERIAL_THREAD; r = (b->count > 1 ? sem_post_multiple (&b->sems[sel], b->count - 1) : 0); } else { e = 0; rslt= 0; } pthread_mutex_unlock(&b->m); if (!e) r = sem_wait(&b->sems[sel]); if (!r) r = rslt; return barrier_unref(b_,r); }
int pthread_barrier_wait (pthread_barrier_t * barrier) { int result; int step; pthread_barrier_t b; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } b = *barrier; step = b->iStep; if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) { /* Must be done before posting the semaphore. */ b->nCurrentBarrierHeight = b->nInitialBarrierHeight; /* * There is no race condition between the semaphore wait and post * because we are using two alternating semas and all threads have * entered barrier_wait and checked nCurrentBarrierHeight before this * barrier's sema can be posted. Any threads that have not quite * entered sem_wait below when the multiple_post has completed * will nevertheless continue through the semaphore (barrier) * and will not be left stranded. */ result = (b->nInitialBarrierHeight > 1 ? sem_post_multiple (&(b->semBarrierBreeched[step]), b->nInitialBarrierHeight - 1) : 0); } else { /* * Use the non-cancelable version of sem_wait(). */ result = ptw32_semwait (&(b->semBarrierBreeched[step])); } /* * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. * This also sets up the alternate semaphore as the next barrier. */ if (0 == result) { result = ((PTW32_INTERLOCKED_LONG) step == PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (b->iStep), (PTW32_INTERLOCKED_LONG) (1L - step), (PTW32_INTERLOCKED_LONG) step) ? PTHREAD_BARRIER_SERIAL_THREAD : 0); } return (result); }
void Threading::Semaphore::Post(int multiple) { #if defined(_MSC_VER) sem_post_multiple(&m_sema, multiple); #else // Only w32pthreads has the post_multiple, but it's easy enough to fake: while (multiple > 0) { multiple--; sem_post(&m_sema); } #endif }
void semaphore::try_release(uint32 releaseCount) { VOGL_ASSERT(releaseCount >= 1); #ifdef WIN32 if (1 == releaseCount) sem_post(&m_sem); else sem_post_multiple(&m_sem, releaseCount); #else while (releaseCount > 0) { sem_post(&m_sem); releaseCount--; } #endif }
int pthread_barrier_wait (pthread_barrier_t * barrier) { int result; pthread_barrier_t b; ptw32_mcs_local_node_t node; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } ptw32_mcs_lock_acquire(&(*barrier)->lock, &node); b = *barrier; if (--b->nCurrentBarrierHeight == 0) { ptw32_mcs_node_transfer(&b->proxynode, &node); result = (b->nInitialBarrierHeight > 1 ? sem_post_multiple (&(b->semBarrierBreeched), b->nInitialBarrierHeight - 1) : 0); } else { ptw32_mcs_lock_release(&node); result = ptw32_semwait (&(b->semBarrierBreeched)); } if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight) == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight) { ptw32_mcs_lock_release(&b->proxynode); if (0 == result) { result = PTHREAD_BARRIER_SERIAL_THREAD; } } return (result); }
int pthread_barrier_wait (pthread_barrier_t * barrier) { int result; pthread_barrier_t b; ptw32_mcs_local_node_t node; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } ptw32_mcs_lock_acquire(&(*barrier)->lock, &node); b = *barrier; if (--b->nCurrentBarrierHeight == 0) { /* * We are the last thread to arrive at the barrier before it releases us. * Move our MCS local node to the global scope barrier handle so that the * last thread out (not necessarily us) can release the lock. */ ptw32_mcs_node_transfer(&b->proxynode, &node); /* * Any threads that have not quite entered sem_wait below when the * multiple_post has completed will nevertheless continue through * the semaphore (barrier). */ result = (b->nInitialBarrierHeight > 1 ? sem_post_multiple (&(b->semBarrierBreeched), b->nInitialBarrierHeight - 1) : 0); } else { ptw32_mcs_lock_release(&node); /* * Use the non-cancelable version of sem_wait(). * * It is possible that all nInitialBarrierHeight-1 threads are * at this point when the last thread enters the barrier, resets * nCurrentBarrierHeight = nInitialBarrierHeight and leaves. * If pthread_barrier_destroy is called at that moment then the * barrier will be destroyed along with the semas. */ result = ptw32_semwait (&(b->semBarrierBreeched)); } if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight) == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight) { /* * We are the last thread to cross this barrier */ ptw32_mcs_lock_release(&b->proxynode); if (0 == result) { result = PTHREAD_BARRIER_SERIAL_THREAD; } } return (result); }
static INLINE int ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) /* * Notes. * * Does not use the external mutex for synchronisation, * therefore semBlockLock is needed. * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the * state where the external mutex is not necessarily locked by * any thread, ie. between cond_wait unlocking and re-acquiring * the lock after having been signaled or a timeout or * cancellation. * * Uses the following CV elements: * nWaitersBlocked * nWaitersToUnblock * nWaitersGone * mtxUnblockLock * semBlockLock * semBlockQueue */ { int result; pthread_cond_t cv; int nSignalsToIssue; if (cond == NULL || *cond == NULL) { return EINVAL; } cv = *cond; /* * No-op if the CV is static and hasn't been initialised yet. * Assuming that any race condition is harmless. */ if (cv == PTHREAD_COND_INITIALIZER) { return 0; } if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) { return result; } if (0 != cv->nWaitersToUnblock) { if (0 == cv->nWaitersBlocked) { return pthread_mutex_unlock (&(cv->mtxUnblockLock)); } if (unblockAll) { cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked); cv->nWaitersBlocked = 0; } else { nSignalsToIssue = 1; cv->nWaitersToUnblock++; cv->nWaitersBlocked--; } } else if (cv->nWaitersBlocked > cv->nWaitersGone) { /* Use the non-cancellable version of sem_wait() */ if (ptw32_semwait (&(cv->semBlockLock)) != 0) { result = errno; (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); return result; } if (0 != cv->nWaitersGone) { cv->nWaitersBlocked -= cv->nWaitersGone; cv->nWaitersGone = 0; } if (unblockAll) { nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked; cv->nWaitersBlocked = 0; } else { nSignalsToIssue = cv->nWaitersToUnblock = 1; cv->nWaitersBlocked--; } } else { return pthread_mutex_unlock (&(cv->mtxUnblockLock)); } if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) { if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0) { result = errno; } } return result; } /* ptw32_cond_unblock */
int pthread_barrier_wait(pthread_barrier_t *barrier) { int result; int step; pthread_barrier_t b; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } b = *barrier; step = b->iStep; if (0 == InterlockedDecrement((long *) &(b->nCurrentBarrierHeight))) { /* Must be done before posting the semaphore. */ b->nCurrentBarrierHeight = b->nInitialBarrierHeight; /* * There is no race condition between the semaphore wait and post * because we are using two alternating semas and all threads have * entered barrier_wait and checked nCurrentBarrierHeight before this * barrier's sema can be posted. Any threads that have not quite * entered sem_wait below when the multiple_post has completed * will nevertheless continue through the semaphore (barrier) * and will not be left stranded. */ result = (b->nInitialBarrierHeight > 1 ? sem_post_multiple(&(b->semBarrierBreeched[step]), b->nInitialBarrierHeight - 1) : 0); } else { BOOL switchCancelState; int oldCancelState; pthread_t self = pthread_self(); /* * This routine is not a cancelation point, so temporarily * prevent sem_wait() from being one. * PTHREAD_CANCEL_ASYNCHRONOUS threads can still be canceled. */ switchCancelState = (self->cancelType == PTHREAD_CANCEL_DEFERRED && 0 == pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldCancelState)); result = sem_wait(&(b->semBarrierBreeched[step])); if (switchCancelState) { (void) pthread_setcancelstate(oldCancelState, NULL); } } /* * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. * This also sets up the alternate semaphore as the next barrier. */ if (0 == result) { result = ((PTW32_INTERLOCKED_LONG) step == ptw32_interlocked_compare_exchange((PTW32_INTERLOCKED_LPLONG) &(b->iStep), (PTW32_INTERLOCKED_LONG) (1L - step), (PTW32_INTERLOCKED_LONG) step) ? PTHREAD_BARRIER_SERIAL_THREAD : 0); } return(result); }
void Semaphore::Post( int multiple ) { #if defined(_MSC_VER) sem_post_multiple( &sema, multiple ); #endif }