Exemple #1
0
static VALUE
rb_mutex_lock(VALUE self, SEL sel)
{
    rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
    rb_vm_mutex_t *m = GetMutexPtr(self);
    rb_vm_thread_status_t prev_status;
    if (m->thread == current) {
	rb_raise(rb_eThreadError, "deadlock; recursive locking");
    }

    prev_status = current->status;
    if (current->status == THREAD_ALIVE) {
	current->status = THREAD_SLEEP;
    }
    current->wait_for_mutex_lock = true;
    pthread_assert(pthread_mutex_lock(&m->mutex));
    current->wait_for_mutex_lock = false;
    current->status = prev_status;
    m->thread = current;
    if (current->mutexes == Qnil) {
	GC_WB(&current->mutexes, rb_ary_new());
	OBJ_UNTRUST(current->mutexes);
    }
    rb_ary_push(current->mutexes, self);

    return self;
}
Exemple #2
0
static VALUE
thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eThreadError, "must be called with a block");
    }
    rb_vm_block_t *b = rb_vm_current_block();
    assert(b != NULL);

    rb_vm_thread_t *t = GetThreadPtr(thread);
    rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm());

    // The thread's group is always the parent's one.
    rb_thgroup_add(GetThreadPtr(rb_vm_current_thread())->group, thread);

    // Retain the Thread object to avoid a potential GC, the corresponding
    // release is done in rb_vm_thread_run().
    rb_objc_retain((void *)thread);

    if (pthread_create(&t->thread, NULL, (void *(*)(void *))rb_vm_thread_run,
		(void *)thread) != 0) {
	rb_sys_fail("pthread_create() failed");
    }

    return thread;
}
Exemple #3
0
static VALUE
rb_mutex_trylock(VALUE self, SEL sel)
{
    if (pthread_mutex_trylock(&GetMutexPtr(self)->mutex) == 0) {
	GetMutexPtr(self)->thread = GetThreadPtr(rb_vm_current_thread());
	return Qtrue;
    }
    return Qfalse;
}
Exemple #4
0
static VALUE
thread_initialize(VALUE thread, SEL sel, int argc, const VALUE *argv)
{
    if (!rb_block_given_p()) {
	rb_raise(rb_eThreadError, "must be called with a block");
    }
    rb_vm_block_t *b = rb_vm_current_block();
    assert(b != NULL);

    rb_vm_thread_t *t = GetThreadPtr(thread);
    if (t->thread != 0) {
	rb_raise(rb_eThreadError, "already initialized thread");
    }
    rb_vm_thread_pre_init(t, b, argc, argv, rb_vm_create_vm());

    // The thread's group is always the parent's one.
    // The parent group might be nil (ex. if created from GCD).
    VALUE group = GetThreadPtr(rb_vm_current_thread())->group;
    if (group != Qnil) {
	thgroup_add_m(group, thread, false);
    }

    // Retain the Thread object to avoid a potential GC, the corresponding
    // release is done in rb_vm_thread_run().
    GC_RETAIN(thread);

    // Prepare attributes for the thread.
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // Register the thread to the core. We are doing this before actually
    // running it because the current thread might perform a method poking at
    // the current registered threads (such as Kernel#sleep) right after that.
    rb_vm_register_thread(thread);

    // Launch it.
    if (pthread_create(&t->thread, &attr, (void *(*)(void *))rb_vm_thread_run,
		(void *)thread) != 0) {
	rb_sys_fail("pthread_create() failed");
    }
    pthread_attr_destroy(&attr);

    return thread;
}
Exemple #5
0
static VALUE
rb_mutex_trylock(VALUE self, SEL sel)
{
    rb_vm_mutex_t *m = GetMutexPtr(self);

    if (pthread_mutex_trylock(&m->mutex) == 0) {
	rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
	m->thread = current;
	if (current->mutexes == Qnil) {
	    GC_WB(&current->mutexes, rb_ary_new());
	    OBJ_UNTRUST(current->mutexes);
	}
	rb_ary_push(current->mutexes, self);
	return Qtrue;
    }

    return Qfalse;
}
Exemple #6
0
static bool
rb_mutex_can_unlock(rb_vm_mutex_t *m, bool raise)
{
    if (m->thread == NULL) {
	if (!raise) {
	    return false;
	}
	rb_raise(rb_eThreadError,
		"Attempt to unlock a mutex which is not locked");
    }
    else if (m->thread != GetThreadPtr(rb_vm_current_thread())) {
	if (!raise) {
	    return false;
	}
	rb_raise(rb_eThreadError,
		"Attempt to unlock a mutex which is locked by another thread");
    }
    return true;
}
Exemple #7
0
static VALUE
rb_mutex_lock(VALUE self, SEL sel)
{
    rb_vm_thread_t *current = GetThreadPtr(rb_vm_current_thread());
    rb_vm_mutex_t *m = GetMutexPtr(self);
    if (m->thread == current) {
	rb_raise(rb_eThreadError, "deadlock; recursive locking");
    }

    current->status = THREAD_SLEEP;
    pthread_assert(pthread_mutex_lock(&m->mutex));
    current->status = THREAD_ALIVE;
    m->thread = current;
    if (current->mutexes == Qnil) {
	GC_WB(&current->mutexes, rb_ary_new());
    }
    rb_ary_push(current->mutexes, self);

    return self;
}
Exemple #8
0
static VALUE
thread_s_current(VALUE klass, SEL sel)
{
    return rb_vm_current_thread();
}
Exemple #9
0
static VALUE
rb_thread_exit(void)
{
    return rb_thread_kill(rb_vm_current_thread(), 0);
}
Exemple #10
0
static int
do_select(int n, fd_set *read, fd_set *write, fd_set *except,
	  struct timeval *timeout)
{
    int result, lerrno;
    fd_set orig_read, orig_write, orig_except;

    bzero(&orig_read, sizeof(fd_set));
    bzero(&orig_write, sizeof(fd_set));
    bzero(&orig_except, sizeof(fd_set));

#ifndef linux
    double limit = 0;
    struct timeval wait_rest;

    if (timeout) {
	limit = timeofday() +
	  (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
	wait_rest = *timeout;
	timeout = &wait_rest;
    }
#endif

    if (read) orig_read = *read;
    if (write) orig_write = *write;
    if (except) orig_except = *except;

  retry:
    lerrno = 0;

    rb_vm_thread_t *thread = GetThreadPtr(rb_vm_current_thread());
    rb_vm_thread_status_t prev_status = thread->status;
    thread->status = THREAD_SLEEP;
    //BLOCKING_REGION({
	result = select(n, read, write, except, timeout);
	if (result < 0) lerrno = errno;
    //}, ubf_select, GET_THREAD());
    thread->status = prev_status;

    errno = lerrno;

    if (result < 0) {
	switch (errno) {
	  case EINTR:
#ifdef ERESTART
	  case ERESTART:
#endif
	    if (read) *read = orig_read;
	    if (write) *write = orig_write;
	    if (except) *except = orig_except;
#ifndef linux
	    if (timeout) {
		double d = limit - timeofday();

		wait_rest.tv_sec = (unsigned int)d;
		wait_rest.tv_usec = (long)((d-(double)wait_rest.tv_sec)*1e6);
		if (wait_rest.tv_sec < 0)  wait_rest.tv_sec = 0;
		if (wait_rest.tv_usec < 0) wait_rest.tv_usec = 0;
	    }
#endif
	    goto retry;
	  default:
	    break;
	}
    }
    return result;
}