static void tsd_test(void) { void *tres; int i, res; ethr_tid tid[TT_THREADS]; int values[TT_THREADS]; res = ethr_tsd_key_create(&tt_key,"tsd_test"); ASSERT(res == 0); for (i = 1; i < TT_THREADS; i++) { res = ethr_thr_create(&tid[i], tt_thread, (void *) &values[i], NULL); ASSERT(res == 0); } tres = tt_thread((void *) &values[0]); ASSERT(tres == (void *) &values[0]); for (i = 1; i < TT_THREADS; i++) { res = ethr_thr_join(tid[i], &tres); ASSERT(res == 0); ASSERT(tres == (void *) &values[i]); } res = ethr_tsd_key_delete(tt_key); ASSERT(res == 0); }
static void create_join_thread_test(void) { int i, res; for (i = 1; i <= CJTT_NO_THREADS; i++) { cjtt_ix[i] = i; cjtt_res[i] = 0; } for (i = 1; i <= CJTT_NO_THREADS; i++) { res = ethr_thr_create(&cjtt_tids[i], cjtt_thread, (void *) &cjtt_ix[i], NULL); ASSERT(res == 0); } for (i = 1; i <= CJTT_NO_THREADS; i++) { void *tres; res = ethr_thr_join(cjtt_tids[i], &tres); ASSERT(res == 0); ASSERT(tres == &cjtt_res[i]); ASSERT(cjtt_res[i] == i); } }
static void try_lock_mutex_test(void) { int i, res; ethr_tid tid; res = ethr_mutex_init(&tlmt_mtx1); ASSERT(res == 0); res = ethr_mutex_init(&tlmt_mtx2); ASSERT(res == 0); res = ethr_cond_init(&tlmt_cnd2); ASSERT(res == 0); tlmt_mtx1_locked = 0; tlmt_mtx1_do_unlock = 0; res = ethr_thr_create(&tid, tlmt_thread, NULL, NULL); ASSERT(res == 0); ethr_mutex_lock(&tlmt_mtx2); while (!tlmt_mtx1_locked) { res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2); ASSERT(res == 0 || res == EINTR); } ethr_mutex_unlock(&tlmt_mtx2); for (i = 0; i < 10; i++) { res = ethr_mutex_trylock(&tlmt_mtx1); ASSERT(res == EBUSY); } ethr_mutex_lock(&tlmt_mtx2); tlmt_mtx1_do_unlock = 1; ethr_cond_signal(&tlmt_cnd2); while (tlmt_mtx1_locked) { res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2); ASSERT(res == 0 || res == EINTR); } ethr_mutex_unlock(&tlmt_mtx2); res = ethr_mutex_trylock(&tlmt_mtx1); ASSERT(res == 0); ethr_mutex_unlock(&tlmt_mtx1); res = ethr_thr_join(tid, NULL); ASSERT(res == 0); res = ethr_mutex_destroy(&tlmt_mtx1); ASSERT(res == 0); res = ethr_mutex_destroy(&tlmt_mtx2); ASSERT(res == 0); res = ethr_cond_destroy(&tlmt_cnd2); ASSERT(res == 0); }
int erl_drv_thread_create(char *name, ErlDrvTid *tid, void* (*func)(void*), void* arg, ErlDrvThreadOpts *opts) { #ifdef USE_THREADS int res; struct ErlDrvTid_ *dtid; ethr_thr_opts ethr_opts; ethr_thr_opts *use_opts; if (!opts) use_opts = NULL; else { sys_memcpy((void *) ðr_opts, (void *) &def_ethr_opts, sizeof(ethr_thr_opts)); ethr_opts.suggested_stack_size = opts->suggested_stack_size; use_opts = ðr_opts; } dtid = erts_alloc_fnf(ERTS_ALC_T_DRV_TID, (sizeof(struct ErlDrvTid_) + (name ? sys_strlen(name) + 1 : 0))); if (!dtid) return ENOMEM; dtid->drv_thr = 1; dtid->func = func; dtid->arg = arg; dtid->tsd = NULL; dtid->tsd_len = 0; if (!name) dtid->name = no_name; else { dtid->name = ((char *) dtid) + sizeof(struct ErlDrvTid_); sys_strcpy(dtid->name, name); } #ifdef ERTS_ENABLE_LOCK_COUNT res = erts_lcnt_thr_create(&dtid->tid, erl_drv_thread_wrapper, dtid, use_opts); #else res = ethr_thr_create(&dtid->tid, erl_drv_thread_wrapper, dtid, use_opts); #endif if (res != 0) { erts_free(ERTS_ALC_T_DRV_TID, dtid); return res; } *tid = (ErlDrvTid) dtid; return 0; #else return ENOTSUP; #endif }
static int mtt_create_join_threads(void) { int no_tids = 100, ix = 0, res = 0, no_threads; ethr_tid *tids; mtt_terminate = 0; tids = (ethr_tid *) malloc(sizeof(ethr_tid)*no_tids); ASSERT(tids); print_line("Beginning to create threads"); while (1) { if (ix >= no_tids) { no_tids += 100; if (no_tids > MTT_HARD_LIMIT) { print_line("Hit the hard limit on number of threads (%d)!", MTT_HARD_LIMIT); break; } tids = (ethr_tid *) realloc((void *)tids, sizeof(ethr_tid)*no_tids); ASSERT(tids); } res = ethr_thr_create(&tids[ix], mtt_thread, NULL, NULL); if (res != 0) { break; } ix++; } no_threads = ix; print_line("%d = ethr_thr_create()", res); print_line("Number of created threads: %d", no_threads); ethr_mutex_lock(&mtt_mutex); mtt_terminate = 1; ethr_cond_broadcast(&mtt_cond); ethr_mutex_unlock(&mtt_mutex); while (ix) { res = ethr_thr_join(tids[--ix], NULL); ASSERT(res == 0); } print_line("All created threads terminated"); free((void *) tids); return no_threads; }
static void dw_atomic_massage_test(void) { int i, res; ethr_tid tid[AT_DW_THREADS]; ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; ethr_dw_sint_t dw; dw.sint[0] = dw.sint[1] = 0; ethr_dw_atomic_init(&at_dw_atomic, &dw); for (i = AT_DW_MIN; i <= AT_DW_MAX; i++) { ethr_sint_t val; memset(&val, i, sizeof(ethr_sint_t)); res = ethr_thr_create(&tid[i-AT_DW_MIN], at_dw_thr, (void *) val, &thr_opts); ASSERT(res == 0); } for (i = AT_DW_MIN; i <= AT_DW_MAX; i++) { res = ethr_thr_join(tid[i-AT_DW_MIN], NULL); ASSERT(res == 0); } }
static void detached_thread_test(void) { ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; ethr_tid tid[DT_BATCH_SIZE]; int i, j, res; res = ethr_mutex_init(&dt_mutex); ASSERT(res == 0); res = ethr_cond_init(&dt_cond); ASSERT(res == 0); thr_opts.detached = 1; dt_count = 0; dt_limit = 0; for (i = 0; i < DT_THREADS/DT_BATCH_SIZE; i++) { dt_limit += DT_BATCH_SIZE; for (j = 0; j < DT_BATCH_SIZE; j++) { res = ethr_thr_create(&tid[j], dt_thread, NULL, &thr_opts); ASSERT(res == 0); } ethr_mutex_lock(&dt_mutex); while (dt_count < dt_limit) { res = ethr_cond_wait(&dt_cond, &dt_mutex); ASSERT(res == 0 || res == EINTR); } ethr_mutex_unlock(&dt_mutex); print_line("dt_count = %d", dt_count); } do_sleep(1); }
static void broadcast_test(void) { int res, i; ethr_tid tid[BCT_THREADS]; res = ethr_mutex_init(&bct_mutex); ASSERT(res == 0); res = ethr_cond_init(&bct_cntrl_cond); ASSERT(res == 0); res = ethr_cond_init(&bct_cond); ASSERT(res == 0); for (i = 0; i < BCT_THREADS; i++) { res = ethr_thr_create(&tid[i], bct_thread, NULL, NULL); ASSERT(res == 0); } ethr_mutex_lock(&bct_mutex); for (i = 0; i < BCT_NO_OF_WAITS; i++) { while (bct_waiting != BCT_THREADS) { res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex); ASSERT(res == 0 || res == EINTR); } bct_waiting = 0; bct_woken = 0; /* Wake all threads */ ethr_cond_broadcast(&bct_cond); while (bct_woken != BCT_THREADS) { res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex); ASSERT(res == 0 || res == EINTR); } } bct_done = 1; /* Wake all threads */ ethr_cond_broadcast(&bct_cond); ethr_mutex_unlock(&bct_mutex); for (i = 0; i < BCT_THREADS; i++) { res = ethr_thr_join(tid[i], NULL); ASSERT(res == 0); } res = ethr_mutex_destroy(&bct_mutex); ASSERT(res == 0); res = ethr_cond_destroy(&bct_cntrl_cond); ASSERT(res == 0); res = ethr_cond_destroy(&bct_cond); ASSERT(res == 0); }
static void cond_wait_test(void) { ethr_tid tid1, tid2; int res; res = ethr_mutex_init(&cwt_mutex); ASSERT(res == 0); res = ethr_cond_init(&cwt_cond); ASSERT(res == 0); /* Wake with signal */ cwt_counter = 0; res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL); ASSERT(res == 0); res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL); ASSERT(res == 0); do_sleep(1); /* Make sure threads waits on cond var */ ethr_mutex_lock(&cwt_mutex); ethr_cond_signal(&cwt_cond); /* Wake one thread */ do_sleep(1); /* Make sure awakened thread waits on mutex */ ASSERT(cwt_counter == 0); ethr_mutex_unlock(&cwt_mutex); do_sleep(1); /* Let awakened thread proceed */ ethr_mutex_lock(&cwt_mutex); ASSERT(cwt_counter == 1); ethr_cond_signal(&cwt_cond); /* Wake the other thread */ do_sleep(1); /* Make sure awakened thread waits on mutex */ ASSERT(cwt_counter == 1); ethr_mutex_unlock(&cwt_mutex); do_sleep(1); /* Let awakened thread proceed */ ethr_mutex_lock(&cwt_mutex); ASSERT(cwt_counter == 2); ethr_mutex_unlock(&cwt_mutex); res = ethr_thr_join(tid1, NULL); ASSERT(res == 0); res = ethr_thr_join(tid2, NULL); ASSERT(res == 0); /* Wake with broadcast */ cwt_counter = 0; res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL); ASSERT(res == 0); res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL); ASSERT(res == 0); do_sleep(1); /* Make sure threads waits on cond var */ ethr_mutex_lock(&cwt_mutex); ethr_cond_broadcast(&cwt_cond); /* Wake the threads */ do_sleep(1); /* Make sure awakened threads wait on mutex */ ASSERT(cwt_counter == 0); ethr_mutex_unlock(&cwt_mutex); do_sleep(1); /* Let awakened threads proceed */ ethr_mutex_lock(&cwt_mutex); ASSERT(cwt_counter == 2); ethr_mutex_unlock(&cwt_mutex); res = ethr_thr_join(tid1, NULL); ASSERT(res == 0); res = ethr_thr_join(tid2, NULL); ASSERT(res == 0); res = ethr_mutex_destroy(&cwt_mutex); ASSERT(res == 0); res = ethr_cond_destroy(&cwt_cond); ASSERT(res == 0); }
static void mutex_test(void) { int res; ethr_tid tid; print_line("Trying to initialize mutex"); res = ethr_mutex_init(&mt_mutex); ASSERT(res == 0); print_line("Initialized mutex"); mt_data = 0; print_line("Main thread tries to lock mutex"); ethr_mutex_lock(&mt_mutex); print_line("Main thread locked mutex"); ASSERT(mt_data == 0); print_line("Main thread about to create aux thread"); res = ethr_thr_create(&tid, mt_thread, NULL, NULL); ASSERT(res == 0); print_line("Main thread created aux thread"); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(mt_data == 0); ethr_mutex_unlock(&mt_mutex); print_line("Main thread unlocked mutex"); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); print_line("Main thread tries to lock mutex"); ethr_mutex_lock(&mt_mutex); print_line("Main thread locked mutex"); ASSERT(mt_data == 1); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(mt_data == 1); ethr_mutex_unlock(&mt_mutex); print_line("Main thread unlocked mutex"); res = ethr_thr_join(tid, NULL); ASSERT(res == 0); print_line("Main thread joined aux thread"); res = ethr_mutex_destroy(&mt_mutex); ASSERT(res == 0); print_line("Main thread destroyed mutex"); }
static void equal_tids_test(void) { int res, i; res = ethr_mutex_init(&ett_mutex); ASSERT(res == 0); res = ethr_cond_init(&ett_cond); ASSERT(res == 0); ett_tids[0] = ethr_self(); res = ethr_thr_create(&ett_tids[1], ett_thread, (void *) &ett_tids[1], NULL); ASSERT(res == 0); ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0])); ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1])); res = ethr_thr_join(ett_tids[1], NULL); res = ethr_thr_create(&ett_tids[2], ett_thread, (void *) &ett_tids[2], NULL); ASSERT(res == 0); ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0])); ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1])); ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[2])); #if 0 /* This fails on some linux platforms. Until we decides if a tid * is allowed to be reused right away or not, we disable the test. */ ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2])); #endif res = ethr_thr_join(ett_tids[2], NULL); ASSERT(res == 0); /* Second part of test */ ett_terminate = 0; res = ethr_thr_create(&ett_tids[1], ett_thread2, NULL, NULL); ASSERT(res == 0); ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[1])); for (i = 0; i < ETT_THREADS; i++) { res = ethr_thr_create(&ett_tids[2], ett_thread, (void*)&ett_tids[2], NULL); ASSERT(res == 0); ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[2])); ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2])); res = ethr_thr_join(ett_tids[2], NULL); ASSERT(res == 0); } ethr_mutex_lock(&ett_mutex); ett_terminate = 1; ethr_cond_signal(&ett_cond); ethr_mutex_unlock(&ett_mutex); res = ethr_thr_join(ett_tids[1], NULL); ASSERT(res == 0); res = ethr_cond_destroy(&ett_cond); ASSERT(res == 0); res = ethr_mutex_destroy(&ett_mutex); ASSERT(res == 0); }
static void atomic_test(void) { long data_init, data_final, val; int res, i; ethr_tid tid[AT_THREADS]; ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; atomic_basic_test(); #if ETHR_SIZEOF_PTR > 4 at_rm_val = ((long) 1) << 57; at_set_val = ((long) 1) << 60; #else at_rm_val = ((long) 1) << 27; at_set_val = ((long) 1) << 30; #endif at_max_val = at_set_val + at_rm_val + ((long) AT_THREADS + 1) * 4711; data_init = at_rm_val + (long) 4711; data_final = at_set_val + (long) 4711; thr_opts.detached = 1; print_line("Initializing"); ethr_atomic_init(&at_ready, 0); ethr_atomic_init(&at_go, 0); ethr_atomic_init(&at_done, data_init); ethr_atomic_init(&at_data, data_init); val = ethr_atomic_read(&at_data); ASSERT(val == data_init); ethr_atomic_set(&at_done, 0); val = ethr_atomic_read(&at_done); ASSERT(val == 0); print_line("Creating threads"); for (i = 0; i < AT_THREADS; i++) { res = ethr_thr_create(&tid[i], at_thread, NULL, &thr_opts); ASSERT(res == 0); } print_line("Waiting for threads to ready up"); do { val = ethr_atomic_read(&at_ready); ASSERT(val >= 0); ASSERT(val <= AT_THREADS); } while (val != AT_THREADS); print_line("Letting threads loose"); val = ethr_atomic_xchg(&at_go, 17); ASSERT(val == 0); val = ethr_atomic_read(&at_go); ASSERT(val == 17); print_line("Waiting for threads to finish"); do { val = ethr_atomic_read(&at_done); ASSERT(val >= 0); ASSERT(val <= AT_THREADS); } while (val != AT_THREADS); print_line("Checking result"); val = ethr_atomic_read(&at_data); ASSERT(res == 0); ASSERT(val == data_final); print_line("Result ok"); }
static void rwmutex_test(void) { int data; int res; ethr_tid tid; print_line("Trying to initialize rwmutex"); res = ethr_rwmutex_init(&rwmt_rwmutex); ASSERT(res == 0); print_line("Initialized rwmutex"); rwmt_data = 4711; print_line("Main thread tries to read lock rwmutex"); ethr_rwmutex_rlock(&rwmt_rwmutex); print_line("Main thread read locked rwmutex"); ASSERT(rwmt_data == 4711); print_line("Main thread about to create aux thread"); res = ethr_thr_create(&tid, rwmt_thread, NULL, NULL); ASSERT(res == 0); print_line("Main thread created aux thread"); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(rwmt_data == 4711); print_line("Main thread tries to read unlock rwmutex"); ethr_rwmutex_runlock(&rwmt_rwmutex); print_line("Main thread read unlocked rwmutex"); print_line("Main thread tries to write lock rwmutex"); ethr_rwmutex_rwlock(&rwmt_rwmutex); print_line("Main thread write locked rwmutex"); data = ++rwmt_data; print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(rwmt_data == data); ++rwmt_data; print_line("Main thread tries to write unlock rwmutex"); ethr_rwmutex_rwunlock(&rwmt_rwmutex); print_line("Main thread write unlocked rwmutex"); res = ethr_thr_join(tid, NULL); ASSERT(res == 0); print_line("Main thread joined aux thread"); res = ethr_rwmutex_destroy(&rwmt_rwmutex); ASSERT(res == 0); print_line("Main thread destroyed rwmutex"); }
static void spinlock_test(void) { int res; ethr_tid tid; print_line("Trying to initialize spinlock"); res = ethr_spinlock_init(&st_spinlock); ASSERT(res == 0); print_line("Initialized spinlock"); st_data = 0; print_line("Main thread tries to lock spinlock"); ethr_spin_lock(&st_spinlock); print_line("Main thread locked spinlock"); ASSERT(st_data == 0); print_line("Main thread about to create aux thread"); res = ethr_thr_create(&tid, st_thread, NULL, NULL); ASSERT(res == 0); print_line("Main thread created aux thread"); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(st_data == 0); ethr_spin_unlock(&st_spinlock); print_line("Main thread unlocked spinlock"); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); print_line("Main thread tries to lock spinlock"); ethr_spin_lock(&st_spinlock); print_line("Main thread locked spinlock"); ASSERT(st_data == 1); print_line("Main thread goes to sleep for 1 second"); do_sleep(1); print_line("Main thread woke up"); ASSERT(st_data == 1); ethr_spin_unlock(&st_spinlock); print_line("Main thread unlocked spinlock"); res = ethr_thr_join(tid, NULL); ASSERT(res == 0); print_line("Main thread joined aux thread"); res = ethr_spinlock_destroy(&st_spinlock); ASSERT(res == 0); print_line("Main thread destroyed spinlock"); }