Ejemplo n.º 1
0
void tlTaskStart(tlTask* task) {
    trace("%s", tl_str(task));
    assert(tlTaskIs(task));
    assert(task->state == TL_STATE_INIT);
    assert(task->stack);
    tlVm* vm = tlTaskGetVm(task);
    a_inc(&vm->tasks);
    a_inc(&vm->runnable);
    task->worker = null;
    task->state = TL_STATE_READY;
    lqueue_put(&vm->run_q, &task->entry);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
tlTask* tlTaskNew(tlVm* vm, tlObject* locals) {
    tlTask* task = tlAlloc(tlTaskKind, sizeof(tlTask));
    assert(task->state == TL_STATE_INIT);
    task->id = a_inc(&vm->nexttaskid);
    task->worker = vm->waiter;
    task->locals = locals;
    task->ticks = START_TICKS;
    trace("new %s", tl_str(task));
    return task;
}
Ejemplo n.º 4
0
int pthread_cond_broadcast(pthread_cond_t *c)
{
	pthread_mutex_t *m;

	if (!c->_c_waiters) return 0;

	a_inc(&c->_c_seq);

#ifdef __EMSCRIPTEN__
	// XXX Emscripten: TODO: This is suboptimal but works naively correctly for now. The Emscripten-specific code path below
	// has a bug and does not work for some reason. Figure it out and remove this code block.
	__wake(&c->_c_seq, -1, 0);
	return 0;
#endif

	/* If cond var is process-shared, simply wake all waiters. */
	if (c->_c_mutex == (void *)-1) {
		__wake(&c->_c_seq, -1, 0);
		return 0;
	}

	/* Block waiters from returning so we can use the mutex. */
	while (a_swap(&c->_c_lock, 1))
		__wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
	if (!c->_c_waiters)
		goto out;
	m = c->_c_mutex;

	/* Move waiter count to the mutex */
	a_fetch_add(&m->_m_waiters, c->_c_waiters2);
	c->_c_waiters2 = 0;

#ifdef __EMSCRIPTEN__
	int futexResult;
	do {
		// XXX Emscripten: Bug, this does not work correctly.
		futexResult = emscripten_futex_wake_or_requeue(&c->_c_seq, !m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid,
			c->_c_seq, &m->_m_lock);
	} while(futexResult == -EAGAIN);
#else
	/* Perform the futex requeue, waking one waiter unless we know
	 * that the calling thread holds the mutex. */
	__syscall(SYS_futex, &c->_c_seq, FUTEX_REQUEUE,
		!m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid,
		INT_MAX, &m->_m_lock);
#endif

out:
	a_store(&c->_c_lock, 0);
	if (c->_c_lockwait) __wake(&c->_c_lock, 1, 0);

	return 0;
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
int pthread_barrier_wait(pthread_barrier_t *b)
{
	int limit = b->_b_limit;
	struct instance *inst;

	/* Trivial case: count was set at 1 */
	if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD;

	/* Process-shared barriers require a separate, inefficient wait */
	if (limit < 0) return pshared_barrier_wait(b);

	/* Otherwise we need a lock on the barrier object */
	while (a_swap(&b->_b_lock, 1))
		__wait(&b->_b_lock, &b->_b_waiters, 1, 1);
	inst = b->_b_inst;

	/* First thread to enter the barrier becomes the "instance owner" */
	if (!inst) {
		struct instance new_inst = { 0 };
		int spins = 10000;
		b->_b_inst = inst = &new_inst;
		a_store(&b->_b_lock, 0);
		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
		while (spins-- && !inst->finished)
			a_spin();
		a_inc(&inst->finished);
		while (inst->finished == 1)
			__syscall(SYS_futex, &inst->finished, FUTEX_WAIT,1,0);
		return PTHREAD_BARRIER_SERIAL_THREAD;
	}

	/* Last thread to enter the barrier wakes all non-instance-owners */
	if (++inst->count == limit) {
		b->_b_inst = 0;
		a_store(&b->_b_lock, 0);
		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
		a_store(&inst->last, 1);
		if (inst->waiters)
			__wake(&inst->last, -1, 1);
	} else {
		a_store(&b->_b_lock, 0);
		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);
		__wait(&inst->last, &inst->waiters, 0, 1);
	}

	/* Last thread to exit the barrier wakes the instance owner */
	if (a_fetch_add(&inst->count,-1)==1 && a_fetch_add(&inst->finished,1))
		__wake(&inst->finished, 1, 1);

	return 0;
}
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
void tlTaskReady(tlTask* task) {
    trace("%s.value: %s", tl_str(task), tl_str(task->value));
    assert(tlTaskIs(task));
    assert(task->state == TL_STATE_WAIT);
    assert(task->stack);
    tlVm* vm = tlTaskGetVm(task);
    task->waitFor = null;
    a_inc(&vm->runnable);
    task->state = TL_STATE_READY;
    if (tlWorkerIsBound(task->worker)) {
        tlWorkerSignal(task->worker);
    } else {
        task->worker = null;
        lqueue_put(&vm->run_q, &task->entry);
    }
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts)
{
    struct cm cm = { .c=c, .m=m };
    int r, e=0, seq;

    if (m->_m_type && (m->_m_lock&INT_MAX) != pthread_self()->tid)
        return EPERM;

    if (ts && ts->tv_nsec >= 1000000000UL)
        return EINVAL;

    pthread_testcancel();

    a_inc(&c->_c_waiters);

    if (c->_c_mutex != (void *)-1) {
        c->_c_mutex = m;
        while (a_swap(&c->_c_lock, 1))
            __wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
        c->_c_waiters2++;
        a_store(&c->_c_lock, 0);
        if (c->_c_lockwait) __wake(&c->_c_lock, 1, 1);
    }

    seq = c->_c_seq;

    pthread_mutex_unlock(m);

    do e = __timedwait(&c->_c_seq, seq, c->_c_clock, ts, cleanup, &cm, 0);
    while (c->_c_seq == seq && (!e || e==EINTR));
    if (e == EINTR) e = 0;

    unwait(c, m);

    if ((r=pthread_mutex_lock(m))) return r;

    return e;
}
Ejemplo n.º 12
0
int pthread_cond_broadcast(pthread_cond_t *c)
{
	pthread_mutex_t *m;

	if (!c->_c_waiters) return 0;

	a_inc(&c->_c_seq);

	/* If cond var is process-shared, simply wake all waiters. */
	if (c->_c_mutex == (void *)-1) {
		__wake(&c->_c_seq, -1, 0);
		return 0;
	}

	/* Block waiters from returning so we can use the mutex. */
	while (a_swap(&c->_c_lock, 1))
		__wait(&c->_c_lock, &c->_c_lockwait, 1, 1);
	if (!c->_c_waiters)
		goto out;
	m = c->_c_mutex;

	/* Move waiter count to the mutex */
	a_fetch_add(&m->_m_waiters, c->_c_waiters2);
	c->_c_waiters2 = 0;

	/* Perform the futex requeue, waking one waiter unless we know
	 * that the calling thread holds the mutex. */
	__syscall(SYS_futex, &c->_c_seq, FUTEX_REQUEUE,
		!m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid,
		INT_MAX, &m->_m_lock);

out:
	a_store(&c->_c_lock, 0);
	if (c->_c_lockwait) __wake(&c->_c_lock, 1, 0);

	return 0;
}
Ejemplo n.º 13
0
tlTask* tlTaskWaitExternal(tlTask* task) {
    tlVm* vm = tlTaskGetVm(task);
    if (!task->background) a_inc(&vm->waitevent);
    tlTaskWaitFor(task, null);
    return task;
}
Ejemplo n.º 14
0
void __aio_wake(void)
{
    a_inc(&seq);
    __wake(&seq, -1, 1);
}
Ejemplo n.º 15
0
void __vm_lock() {
  a_inc(vmlock);
}
Ejemplo n.º 16
0
void tlVmIncExternal(tlVm* vm) {
    assert(vm);
    a_inc(&vm->waitevent);
}