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); }
void erts_lcnt_init() { erts_lcnt_thread_data_t *eltd = NULL; /* init lock */ if (ethr_mutex_init(&lcnt_data_lock) != 0) abort(); /* init tsd */ lcnt_n_thr = 0; ethr_tsd_key_create(&lcnt_thr_data_key); lcnt_lock(); erts_lcnt_rt_options = ERTS_LCNT_OPT_PROCLOCK | ERTS_LCNT_OPT_LOCATION; eltd = lcnt_thread_data_alloc(); ethr_tsd_set(lcnt_thr_data_key, eltd); /* init lcnt structure */ erts_lcnt_data = (erts_lcnt_data_t*)malloc(sizeof(erts_lcnt_data_t)); erts_lcnt_data->current_locks = erts_lcnt_list_init(); erts_lcnt_data->deleted_locks = erts_lcnt_list_init(); lcnt_unlock(); /* set start timer and zero statistics */ erts_lcnt_clear_counters(); }
void erts_lc_init(void) { #ifdef ERTS_LC_STATIC_ALLOC int i; static erts_lc_free_block_t fbs[ERTS_LC_FB_CHUNK_SIZE]; for (i = 0; i < ERTS_LC_FB_CHUNK_SIZE - 1; i++) { #ifdef DEBUG memset((void *) &fbs[i], 0xdf, sizeof(erts_lc_free_block_t)); #endif fbs[i].next = &fbs[i+1]; } #ifdef DEBUG memset((void *) &fbs[ERTS_LC_FB_CHUNK_SIZE-1], 0xdf, sizeof(erts_lc_free_block_t)); #endif fbs[ERTS_LC_FB_CHUNK_SIZE-1].next = NULL; free_blocks = &fbs[0]; #else /* #ifdef ERTS_LC_STATIC_ALLOC */ free_blocks = NULL; #endif /* #ifdef ERTS_LC_STATIC_ALLOC */ #ifdef ETHR_HAVE_NATIVE_LOCKS if (ethr_spinlock_init(&free_blocks_lock) != 0) abort(); #else if (ethr_mutex_init(&free_blocks_lock) != 0) abort(); #endif erts_tsd_key_create(&locks_key); }
static void max_threads_test(void) { int no_threads[MTT_TIMES], i, up, down, eq, res; char *str; res = ethr_mutex_init(&mtt_mutex); ASSERT(res == 0); res = ethr_cond_init(&mtt_cond); ASSERT(res == 0); for (i = 0; i < MTT_TIMES; i++) { no_threads[i] = mtt_create_join_threads(); } str = &mtt_string[0]; eq = up = down = 0; for (i = 0; i < MTT_TIMES; i++) { if (i == 0) { str += sprintf(str, "%d", no_threads[i]); continue; } str += sprintf(str, ", %d", no_threads[i]); if (no_threads[i] < no_threads[i-1]) down++; else if (no_threads[i] > no_threads[i-1]) up++; else eq++; } print_line("Max created threads: %s", mtt_string); /* We fail if the no of threads we are able to create constantly decrease */ ASSERT(!down || up || eq); succeed("Max created threads: %s", mtt_string); }
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); }
ErlDrvMutex * erl_drv_mutex_create(char *name) { #ifdef USE_THREADS ErlDrvMutex *dmtx = erts_alloc_fnf(ERTS_ALC_T_DRV_MTX, (sizeof(ErlDrvMutex) + (name ? sys_strlen(name) + 1 : 0))); if (dmtx) { if (ethr_mutex_init(&dmtx->mtx) != 0) { erts_free(ERTS_ALC_T_DRV_MTX, (void *) dmtx); dmtx = NULL; } else if (!name) dmtx->name = no_name; else { dmtx->name = ((char *) dmtx) + sizeof(ErlDrvMutex); sys_strcpy(dmtx->name, name); } } return dmtx; #else return (ErlDrvMutex *) NULL; #endif }
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); }