void __wait(volatile int *addr, volatile int *waiters, int val, int priv) { int spins=10000; if (priv) priv = 128; priv=0; while (spins--) { if (*addr==val) a_spin(); else return; } if (waiters) a_inc(waiters); while (*addr==val) { #ifdef __EMSCRIPTEN__ if (pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) { // Must wait in slices in case this thread is cancelled in between. int e; do { if (_pthread_isduecanceled(pthread_self())) { if (waiters) a_dec(waiters); return; } e = emscripten_futex_wait((void*)addr, val, 100); } while(e == -ETIMEDOUT); } else { // Can wait in one go. emscripten_futex_wait((void*)addr, val, INFINITY); } #else __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0); #endif } if (waiters) a_dec(waiters); }
int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at) { int r, w=0; while ((r=pthread_mutex_trylock(m)) == EBUSY) { if (!(r=m->_m_lock) || (r&0x40000000)) continue; if (!w) a_inc(&m->_m_waiters), w++; if (__timedwait(&m->_m_lock, r, CLOCK_REALTIME, at, 0) == ETIMEDOUT) { if (w) a_dec(&m->_m_waiters); return ETIMEDOUT; } } if (w) a_dec(&m->_m_waiters); return r; }
static tlHandle tlTaskDone(tlTask* task) { trace("%p done: %s%s", task, tl_str(task->value), tlTaskHasError(task)? " (error)":""); assert(!task->stack); assert(task->value); assert(task->state == TL_STATE_RUN); task->state = tlTaskHasError(task)? TL_STATE_ERROR : TL_STATE_DONE; tlVm* vm = tlTaskGetVm(task); a_dec(&vm->tasks); a_dec(&vm->runnable); task->worker = vm->waiter; signalWaiters(task); signalVm(task); if (tlBlockingTaskIs(task)) tlBlockingTaskDone(task); if (task->debugger) tlDebuggerTaskDone(task->debugger, task); if (task->yields) tlQueueClose(task->yields); return tlTaskNotRunning; }
void __wait(volatile int *addr, volatile int *waiters, int val, int priv) { int spins=50000; if (priv) priv = 128; priv=0; while (spins--) { if (*addr==val) a_spin(); else return; } if (waiters) a_inc(waiters); while (*addr==val) __syscall(SYS_futex, (long)addr, FUTEX_WAIT|priv, val, 0); if (waiters) a_dec(waiters); }
static void unwait(pthread_cond_t *c, pthread_mutex_t *m) { /* Removing a waiter is non-trivial if we could be using requeue * based broadcast signals, due to mutex access issues, etc. */ if (c->_c_mutex == (void *)-1) { a_dec(&c->_c_waiters); if (c->_c_destroy) __wake(&c->_c_waiters, 1, 0); return; } while (a_swap(&c->_c_lock, 1)) __wait(&c->_c_lock, &c->_c_lockwait, 1, 1); if (c->_c_waiters2) c->_c_waiters2--; else a_dec(&m->_m_waiters); a_store(&c->_c_lock, 0); if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1); a_dec(&c->_c_waiters); if (c->_c_destroy) __wake(&c->_c_waiters, 1, 1); }
int sem_timedwait(sem_t *sem, const struct timespec *at) { while (sem_trywait(sem)) { int r; a_inc(sem->__val+1); a_cas(sem->__val, 0, -1); r = __timedwait(sem->__val, -1, CLOCK_REALTIME, at, cleanup, sem->__val+1, 0); a_dec(sem->__val+1); if (r) { errno = r; return -1; } } return 0; }
tlArray* tlTaskWaitFor(tlTask* task, tlHandle on) { assert(tlTaskIs(task)); assert(task->state == TL_STATE_RUN); assert(task->value); trace("%s.value: %s", tl_str(task), tl_str(task->value)); tlVm* vm = tlTaskGetVm(task); task->state = TL_STATE_WAIT; task->waitFor = on; if (checkDeadlock(task, on)) { task->state = TL_STATE_RUN; return deadlocked(task, on); } if (!tlWorkerIsBound(task->worker)) task->worker = vm->waiter; a_dec(&vm->runnable); return null; }
int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at) { int r, t; if (m->_m_type == PTHREAD_MUTEX_NORMAL && !a_cas(&m->_m_lock, 0, EBUSY)) return 0; while ((r=pthread_mutex_trylock(m)) == EBUSY) { if (!(r=m->_m_lock) || (r&0x40000000)) continue; if ((m->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK && (r&0x1fffffff) == pthread_self()->tid) return EDEADLK; a_inc(&m->_m_waiters); t = r | 0x80000000; a_cas(&m->_m_lock, r, t); r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, 0, 0, 0); a_dec(&m->_m_waiters); if (r && r != EINTR) break; } return r; }
void tlTaskReadyExternal(tlTask* task) { tlVm* vm = tlTaskGetVm(task); if (!task->background) a_dec(&vm->waitevent); tlTaskReady(task); if (vm->signalcb) vm->signalcb(); }
void tlTaskWaitNothing2(tlTask* task) { tlVm* vm = tlTaskGetVm(task); a_dec(&vm->runnable); }
static void cleanup(void *p) { a_dec(p); }
void tlVmDecExternal(tlVm* vm) { assert(vm); a_dec(&vm->waitevent); if (vm->signalcb) vm->signalcb(); }