Esempio n. 1
0
static void
native_thread_destroy(rb_thread_t *th)
{
    HANDLE intr = th->native_thread_data.interrupt_event;
    thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id);
    th->native_thread_data.interrupt_event = 0;
    w32_close_handle(intr);
}
Esempio n. 2
0
static void
ubf_handle(void *ptr)
{
    rb_thread_t *th = (rb_thread_t *)ptr;
    thread_debug("ubf_handle: %p\n", th);

    w32_set_event(th->native_thread_data.interrupt_event);
}
Esempio n. 3
0
static void
native_thread_destroy(rb_thread_t *th)
{
    HANDLE intr = InterlockedExchangePointer(&th->native_thread_data.interrupt_event, 0);
    native_mutex_destroy(&th->interrupt_lock);
    thread_debug("close handle - intr: %p, thid: %p\n", intr, th->thread_id);
    w32_close_handle(intr);
}
Esempio n. 4
0
static void
ubf_select_each(rb_thread_t *th)
{
    thread_debug("ubf_select_each (%p)\n", (void *)th->thread_id);
    if (th) {
	pthread_kill(th->thread_id, SIGVTALRM);
    }
}
Esempio n. 5
0
static unsigned long _stdcall
thread_start_func_1(void *th_ptr)
{
    rb_thread_t *th = th_ptr;
    VALUE stack_start;
    volatile HANDLE thread_id = th->thread_id;

    th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);

    /* run */
    thread_debug("thread created (th: %p, thid: %p, event: %p)\n", th,
		 th->thread_id, th->native_thread_data.interrupt_event);
    thread_start_func_2(th, &stack_start, 0);

    w32_close_handle(thread_id);
    thread_debug("thread deleted (th: %p)\n", th);
    return 0;
}
Esempio n. 6
0
static void
ubf_handle(void *ptr)
{
    typedef BOOL (WINAPI *cancel_io_func_t)(HANDLE);
    rb_thread_t *th = (rb_thread_t *)ptr;
    thread_debug("ubf_handle: %p\n", th);

    w32_set_event(th->native_thread_data.interrupt_event);
}
Esempio n. 7
0
static int
native_thread_create(rb_thread_t *th)
{
    int err = 0;

    if (use_cached_thread(th)) {
	thread_debug("create (use cached thread): %p\n", (void *)th);
    }
    else {
	pthread_attr_t attr;
	const size_t stack_size = th->vm->default_params.thread_machine_stack_size;
	const size_t space = space_size(stack_size);

        th->machine_stack_maxsize = stack_size - space;
#ifdef __ia64
        th->machine_stack_maxsize /= 2;
        th->machine_register_stack_maxsize = th->machine_stack_maxsize;
#endif

#ifdef HAVE_PTHREAD_ATTR_INIT
	CHECK_ERR(pthread_attr_init(&attr));

# ifdef PTHREAD_STACK_MIN
	thread_debug("create - stack size: %lu\n", (unsigned long)stack_size);
	CHECK_ERR(pthread_attr_setstacksize(&attr, stack_size));
# endif

# ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED
	CHECK_ERR(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED));
# endif
	CHECK_ERR(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));

	err = pthread_create(&th->thread_id, &attr, thread_start_func_1, th);
#else
	err = pthread_create(&th->thread_id, NULL, thread_start_func_1, th);
#endif
	thread_debug("create: %p (%d)\n", (void *)th, err);
#ifdef HAVE_PTHREAD_ATTR_INIT
	CHECK_ERR(pthread_attr_destroy(&attr));
#endif
    }
    return err;
}
Esempio n. 8
0
static int
w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th)
{
    HANDLE *targets = events;
    HANDLE intr;
    DWORD ret;

    thread_debug("  w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n",
		 events, count, timeout, th);
    if (th && (intr = th->native_thread_data.interrupt_event)) {
	native_mutex_lock(&th->vm->global_vm_lock);
	if (intr == th->native_thread_data.interrupt_event) {
	    w32_reset_event(intr);
	    if (RUBY_VM_INTERRUPTED(th)) {
		w32_set_event(intr);
	    }

	    targets = ALLOCA_N(HANDLE, count + 1);
	    memcpy(targets, events, sizeof(HANDLE) * count);

	    targets[count++] = intr;
	    thread_debug("  * handle: %p (count: %d, intr)\n", intr, count);
	}
	native_mutex_unlock(&th->vm->global_vm_lock);
    }

    thread_debug("  WaitForMultipleObjects start (count: %d)\n", count);
    ret = WaitForMultipleObjects(count, targets, FALSE, timeout);
    thread_debug("  WaitForMultipleObjects end (ret: %lu)\n", ret);

    if (ret == WAIT_OBJECT_0 + count - 1 && th) {
	errno = EINTR;
    }
    if (ret == -1 && THREAD_DEBUG) {
	int i;
	DWORD dmy;
	for (i = 0; i < count; i++) {
	    thread_debug("  * error handle %d - %s\n", i,
			 GetHandleInformation(targets[i], &dmy) ? "OK" : "NG");
	}
    }
    return ret;
}
Esempio n. 9
0
static int
native_mutex_trylock(rb_thread_lock_t *lock)
{
#if USE_WIN32_MUTEX
    int result;
    thread_debug("native_mutex_trylock: %p\n", *lock);
    result = w32_wait_events(&*lock, 1, 1, 0);
    thread_debug("native_mutex_trylock result: %d\n", result);
    switch (result) {
      case WAIT_OBJECT_0:
	return 0;
      case WAIT_TIMEOUT:
	return EBUSY;
    }
    return EINVAL;
#else
    return TryEnterCriticalSection(lock) == 0;
#endif
}
Esempio n. 10
0
static void
native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
{
    struct timespec timeout;
    struct timeval tvn;
    pthread_mutex_t *lock = &th->interrupt_lock;
    rb_thread_cond_t *cond = &th->native_thread_data.sleep_cond;

    if (timeout_tv) {
	struct timespec timeout_rel;

	timeout_rel.tv_sec = timeout_tv->tv_sec;
	timeout_rel.tv_nsec = timeout_tv->tv_usec;

	timeout = native_cond_timeout(cond, timeout_rel);
    }

    GVL_UNLOCK_BEGIN();
    {
	pthread_mutex_lock(lock);
	th->unblock.func = ubf_pthread_cond_signal;
	th->unblock.arg = th;

	if (RUBY_VM_INTERRUPTED(th)) {
	    /* interrupted.  return immediate */
	    thread_debug("native_sleep: interrupted before sleep\n");
	}
	else {
	    if (!timeout_tv)
		native_cond_wait(cond, lock);
	    else
		native_cond_timedwait(cond, lock, &timeout);
	}
	th->unblock.func = 0;
	th->unblock.arg = 0;

	pthread_mutex_unlock(lock);
    }
    GVL_UNLOCK_END();

    thread_debug("native_sleep done\n");
}
Esempio n. 11
0
static int
native_mutex_unlock(rb_thread_lock_t *lock)
{
#if USE_WIN32_MUTEX
    thread_debug("release mutex: %p\n", *lock);
    return ReleaseMutex(*lock);
#else
    LeaveCriticalSection(lock);
    return 0;
#endif
}
Esempio n. 12
0
static void
native_sleep(rb_thread_t *th, struct timeval *tv)
{
    struct timespec ts;
    struct timeval tvn;

    if (tv) {
	gettimeofday(&tvn, NULL);
	ts.tv_sec = tvn.tv_sec + tv->tv_sec;
	ts.tv_nsec = (tvn.tv_usec + tv->tv_usec) * 1000;
	if (ts.tv_nsec >= PER_NANO){
	    ts.tv_sec += 1;
	    ts.tv_nsec -= PER_NANO;
	}
    }

    thread_debug("native_sleep %ld\n", (long)(tv ? tv->tv_sec : -1));
    GVL_UNLOCK_BEGIN();
    {
	pthread_mutex_lock(&th->interrupt_lock);
	th->unblock.func = ubf_pthread_cond_signal;
	th->unblock.arg = th;

	if (RUBY_VM_INTERRUPTED(th)) {
	    /* interrupted.  return immediate */
	    thread_debug("native_sleep: interrupted before sleep\n");
	}
	else {
	    if (tv == 0 || ts.tv_sec < tvn.tv_sec /* overflow */ ) {
		int r;
		thread_debug("native_sleep: pthread_cond_wait start\n");
		r = pthread_cond_wait(&th->native_thread_data.sleep_cond,
				      &th->interrupt_lock);
                if (r) rb_bug_errno("pthread_cond_wait", r);
		thread_debug("native_sleep: pthread_cond_wait end\n");
	    }
	    else {
		int r;
		thread_debug("native_sleep: pthread_cond_timedwait start (%ld, %ld)\n",
			     (unsigned long)ts.tv_sec, ts.tv_nsec);
		r = pthread_cond_timedwait(&th->native_thread_data.sleep_cond,
					   &th->interrupt_lock, &ts);
		if (r && r != ETIMEDOUT) rb_bug_errno("pthread_cond_timedwait", r);

		thread_debug("native_sleep: pthread_cond_timedwait end (%d)\n", r);
	    }
	}
	th->unblock.func = 0;
	th->unblock.arg = 0;

	pthread_mutex_unlock(&th->interrupt_lock);
    }
    GVL_UNLOCK_END();

    thread_debug("native_sleep done\n");
}
Esempio n. 13
0
static void
native_sleep(rb_thread_t *th, struct timeval *tv)
{
    DWORD msec;

    if (tv) {
	msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
    }
    else {
	msec = INFINITE;
    }

    GVL_UNLOCK_BEGIN();
    {
	DWORD ret;

	native_mutex_lock(&th->interrupt_lock);
	th->unblock.func = ubf_handle;
	th->unblock.arg = th;
	native_mutex_unlock(&th->interrupt_lock);

	if (RUBY_VM_INTERRUPTED(th)) {
	    /* interrupted.  return immediate */
	}
	else {
	    thread_debug("native_sleep start (%lu)\n", msec);
	    ret = w32_wait_events(0, 0, msec, th);
	    thread_debug("native_sleep done (%lu)\n", ret);
	}

	native_mutex_lock(&th->interrupt_lock);
	th->unblock.func = 0;
	th->unblock.arg = 0;
	native_mutex_unlock(&th->interrupt_lock);
    }
    GVL_UNLOCK_END();
}
Esempio n. 14
0
//RHO
/*static*/ int
//RHO
native_mutex_lock(rb_thread_lock_t *lock)
{
#if USE_WIN32_MUTEX
    DWORD result;
    while (1) {
	thread_debug("native_mutex_lock: %p\n", *lock);
	result = w32_wait_events(&*lock, 1, INFINITE, 0);
	switch (result) {
	  case WAIT_OBJECT_0:
	    /* get mutex object */
	    thread_debug("acquire mutex: %p\n", *lock);
	    return 0;
	  case WAIT_OBJECT_0 + 1:
	    /* interrupt */
	    errno = EINTR;
	    thread_debug("acquire mutex interrupted: %p\n", *lock);
	    return 0;
	  case WAIT_TIMEOUT:
	    thread_debug("timeout mutex: %p\n", *lock);
	    break;
	  case WAIT_ABANDONED:
	    rb_bug("win32_mutex_lock: WAIT_ABANDONED");
	    break;
	  default:
	    rb_bug("win32_mutex_lock: unknown result (%d)", result);
	    break;
	}
    }
    return 0;
#else
    EnterCriticalSection(lock);
    return 0;
#endif
}
Esempio n. 15
0
static void
native_sleep(rb_thread_t *th, struct timeval *tv)
{
    DWORD msec;
    if (tv) {
	msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
    }
    else {
	msec = INFINITE;
    }

    GVL_UNLOCK_BEGIN();
    {
	DWORD ret;
	int status = th->status;

	th->status = THREAD_STOPPED;
	th->unblock_function = ubf_handle;
	th->unblock_function_arg = th;

	if (RUBY_VM_INTERRUPTED(th)) {
	    /* interrupted.  return immediate */
	}
	else {
	    thread_debug("native_sleep start (%d)\n", (int)msec);
	    ret = w32_wait_events(0, 0, msec, th);
	    thread_debug("native_sleep done (%d)\n", ret);
	}

	th->unblock_function = 0;
	th->unblock_function_arg = 0;
	th->status = status;
    }
    GVL_UNLOCK_END();
    RUBY_VM_CHECK_INTS();
}
Esempio n. 16
0
static void
Init_native_thread(void)
{
    rb_thread_t *th = GET_THREAD();

    ruby_native_thread_key = TlsAlloc();
    DuplicateHandle(GetCurrentProcess(),
		    GetCurrentThread(),
		    GetCurrentProcess(),
		    &th->thread_id, 0, FALSE, DUPLICATE_SAME_ACCESS);

    th->native_thread_data.interrupt_event = CreateEvent(0, TRUE, FALSE, 0);

    thread_debug("initial thread (th: %p, thid: %p, event: %p)\n",
		 th, GET_THREAD()->thread_id,
		 th->native_thread_data.interrupt_event);
}
Esempio n. 17
0
static int
native_thread_create(rb_thread_t *th)
{
    size_t stack_size = 4 * 1024; /* 4KB */
    th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th);

    if ((th->thread_id) == 0) {
	return thread_errno;
    }

    w32_resume_thread(th->thread_id);

    if (THREAD_DEBUG) {
	Sleep(0);
	thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %d\n",
		     th, th->thread_id,
		     th->native_thread_data.interrupt_event, stack_size);
    }
    return 0;
}
Esempio n. 18
0
static int
native_thread_create(rb_thread_t *th)
{
    size_t stack_size = 4 * 1024; /* 4KB */
    th->thread_id = w32_create_thread(stack_size, thread_start_func_1, th);

    if ((th->thread_id) == 0) {
	st_delete_wrap(th->vm->living_threads, th->self);
	rb_raise(rb_eThreadError, "can't create Thread (%d)", errno);
    }

    w32_resume_thread(th->thread_id);

    if (THREAD_DEBUG) {
	Sleep(0);
	thread_debug("create: (th: %p, thid: %p, intr: %p), stack size: %d\n",
		     th, th->thread_id,
		     th->native_thread_data.interrupt_event, stack_size);
    }
    return 0;
}
Esempio n. 19
0
int search_tree_for_val(tree *t, int num_threads, int val)
{
    int i;
    treenode *n;
    dsp_stack_t *s;
    int *thread_id;
    int threads_ready = 1;
    int node_val;

    n = t->head;
    if(n == NULL) return -1;

    //Set globals for new search...
    DFS_NUM_THREADS = num_threads;
    search_val = val;
    val_found = 0;

    //Allocate threads and thread id's
    threads = (pthread_t *)malloc(sizeof(pthread_t) * num_threads);
    thread_id = (int *)malloc(sizeof(int) * num_threads);
    if(threads == NULL || thread_id == NULL) {
        perror(PROGNAME "error: error allocating threads");
        exit(1);
    }

    //Allocate thread work stacks
    thread_work_stack = (dsp_stack_t **)malloc(sizeof(dsp_stack_t *) * num_threads);
    if(thread_work_stack == NULL) {
        perror(PROGNAME "error: error allocating thread_stacks");
        exit(1);
    }
    for(i = 0; i < num_threads; i++) {
        thread_work_stack[i] = dsp_stack_create(t->node_count);
    }

    //Allocate thread work stack mutexes
    thread_work_stack_mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t) * num_threads);
    if(thread_work_stack_mutex == NULL) {
        perror(PROGNAME "error: error allocating thread_stacks");
        exit(1);
    }

    //Initialize threads
    for(i = 0; i < num_threads; i++) {
        thread_id[i] = i;
        dsp_stack_init(thread_work_stack[i], t->node_count);
        pthread_mutex_init(&thread_work_stack_mutex[i], NULL);
    }


    //Spread initial work across other thread work stacks
    while(n != NULL && threads_ready < num_threads) {
        if(n->right != NULL) {
            dsp_stack_push(thread_work_stack[threads_ready], n->right);
            threads_ready++;
        }
        //Heck, we might get lucky and find it in this predistribution step
        if(n->data != NULL) {
            node_val = *((int *)n->data);
            if(node_val == search_val) {
                thread_debug(1, "main thread: found value during predistribution step!\n");
                printf("%d\t\t%d\t\t%f\t\t%d\n", DFS_TREE_SIZE, num_threads, 0.0, 1);
                return 0;
            }
        }
        n = n->left;
    }

    thread_debug(1, "main thread: predistribution step checked %d nodes\n", threads_ready - 1);

    //Put current node (post distribution) on first thread's work stack.
    s = thread_work_stack[0];
    dsp_stack_push(s, n);


    //Timing vars
    float search_time;
    struct timeval t0, t1;
    gettimeofday(&t0, NULL);


    prog_debug(1, PROGNAME ": starting %d threads\n", num_threads);

    //Create threads
    for(i = 0; i < num_threads; i++) {
        pthread_create(&threads[i], NULL, thread_traverse_tree, &thread_id[i]);
    }

    //Join threads
    for(i = 0; i < num_threads; i++) {
        pthread_join(threads[i], NULL);
    }

    gettimeofday(&t1, NULL);
    search_time = (float)(t1.tv_sec - t0.tv_sec) + ((float)(t1.tv_usec - t0.tv_usec)/1000000.0);


    if(val_found == 0) {
        prog_debug(1, PROGNAME ": value not found in tree!\n");
    } else {
        prog_debug(1, PROGNAME ": value found!\n");
    }
    prog_debug(1, PROGNAME ": all threads complete\n");

    //printf("size\t\tthreads\t\ttime\t\tfound\n");
    printf("%d\t\t%d\t\t%f\t\t%d\n", DFS_TREE_SIZE, num_threads, search_time, val_found);

    //Clean up
    free(threads);
    free(thread_id);
    for(i = 0; i < num_threads; i++) {
        dsp_stack_destroy(thread_work_stack[i]);
    }
    free(thread_work_stack);
    free(thread_work_stack_mutex);

    return 0;
}
Esempio n. 20
0
void *thread_traverse_tree(void *tid)
{
    int id = *((int *)tid);
    dsp_stack_t *s = thread_work_stack[id];
    pthread_mutex_t *dsp_stack_mutex = &thread_work_stack_mutex[id];
    treenode *n;
    int node_val;
    int nodes_processed = 0;

    thread_debug(1, "thread %d: started...\n", id);

    while(1) {
        //Check to see if we are done
        if(val_found) break;

        //Get next node from my stack
        pthread_mutex_lock(dsp_stack_mutex);
        n = dsp_stack_pop(s);
        pthread_mutex_unlock(dsp_stack_mutex);

        //If my stack is empty, get next available node from another stack.
        if(n == NULL) {
            n = get_next_available_treenode(id);
        }

        //If no work found in any other thread's stack, exit...
        if(n == NULL) {
            break;
        }

        //Go depth first in searching, going to the left child
        //and pushing the right child onto my stack.
        while(n != NULL) {

            nodes_processed++;

            //Make sure we are not done.
            if(val_found) break;

            //Because this is hit so often, we don't even compile
            //unless we absolutely need it.
            //thread_debug(3, "thread %d: traversing node %d\n", id, n->id);

            //Check value against search value
            if(n->data != NULL) {
                node_val = *((int *)n->data);
                if(node_val == search_val) {
                    val_found = 1;
                    thread_debug(1, "thread %d: value %d found at node %d!\n",
                                 id, node_val, n->id);
                    break;
                }
            }

            if(n->right != NULL) {
                pthread_mutex_lock(dsp_stack_mutex);
                dsp_stack_push(s, n->right);
                pthread_mutex_unlock(dsp_stack_mutex);
            }
            n = n->left;
        }
    }

    thread_debug(1, "thread %d: exiting after processing %d nodes...\n", id, nodes_processed);
    pthread_exit(0);
}