void erts_lcnt_lock_opt(erts_lcnt_lock_t *lock, Uint16 option) { erts_aint_t r_state = 0, w_state = 0; erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; if (!ERTS_LCNT_LOCK_TYPE(lock)) return; eltd = lcnt_get_thread_data(); ASSERT(eltd); w_state = ethr_atomic_read(&lock->w_state); if (option & ERTS_LCNT_LO_WRITE) { r_state = ethr_atomic_read(&lock->r_state); ethr_atomic_inc( &lock->w_state); } if (option & ERTS_LCNT_LO_READ) { ethr_atomic_inc( &lock->r_state); } /* we cannot acquire w_lock if either w or r are taken */ /* we cannot acquire r_lock if w_lock is taken */ if ((w_state > 0) || (r_state > 0)) { eltd->lock_in_conflict = 1; if (eltd->timer_set == 0) lcnt_time(&eltd->timer); eltd->timer_set++; } else { eltd->lock_in_conflict = 0; } }
void * at_thread(void *unused) { int i; long val, go; val = ethr_atomic_inc_read(&at_ready); ASSERT(val > 0); ASSERT(val <= AT_THREADS); do { go = ethr_atomic_read(&at_go); } while (!go); for (i = 0; i < AT_ITER; i++) { val = ethr_atomic_read_bor(&at_data, at_set_val); ASSERT(val >= (i == 0 ? 0 : at_set_val) + (long) 4711); ASSERT(val <= at_max_val); val = ethr_atomic_read_band(&at_data, ~at_rm_val); ASSERT(val >= at_set_val + (long) 4711); ASSERT(val <= at_max_val); val = ethr_atomic_read(&at_data); ASSERT(val >= at_set_val + (long) 4711); ASSERT(val <= at_max_val); val = ethr_atomic_inc_read(&at_data); ASSERT(val > at_set_val + (long) 4711); ASSERT(val <= at_max_val); val = ethr_atomic_dec_read(&at_data); ASSERT(val >= at_set_val + (long) 4711); ASSERT(val <= at_max_val); ethr_atomic_inc(&at_data); ethr_atomic_dec(&at_data); val = ethr_atomic_add_read(&at_data, (long) 4711); ASSERT(val >= at_set_val + (long) 2*4711); ASSERT(val <= at_max_val); ethr_atomic_add(&at_data, (long) -4711); ASSERT(val >= at_set_val + (long) 4711); ASSERT(val <= at_max_val); } ethr_atomic_inc(&at_done); return NULL; }
void erts_lcnt_lock(erts_lcnt_lock_t *lock) { erts_aint_t w_state; erts_lcnt_thread_data_t *eltd; if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; if (!ERTS_LCNT_LOCK_TYPE(lock)) return; w_state = ethr_atomic_read(&lock->w_state); ethr_atomic_inc( &lock->w_state); eltd = lcnt_get_thread_data(); ASSERT(eltd); if (w_state > 0) { eltd->lock_in_conflict = 1; /* only set the timer if nobody else has it * This should only happen when proc_locks aquires several locks * 'atomicly'. All other locks will block the thread if w_state > 0 * i.e. locked. */ if (eltd->timer_set == 0) lcnt_time(&eltd->timer); eltd->timer_set++; } else { eltd->lock_in_conflict = 0; } }
void erts_lcnt_unlock(erts_lcnt_lock_t *lock) { #ifdef DEBUG erts_aint_t w_state; erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; #ifdef DEBUG /* flowstate */ flowstate = ethr_atomic_read(&lock->flowstate); ASSERT(flowstate == 1); ethr_atomic_dec( &lock->flowstate); /* write state */ w_state = ethr_atomic_read(&lock->w_state); ASSERT(w_state > 0) #endif ethr_atomic_dec(&lock->w_state); }
static void print_lock_x(erts_lcnt_lock_t *lock, Uint16 flag, char *action, char *extra) { erts_aint_t colls, tries, w_state, r_state; erts_lcnt_lock_stats_t *stats = NULL; char *type; int i; type = lcnt_lock_type(lock->flag); r_state = ethr_atomic_read(&lock->r_state); w_state = ethr_atomic_read(&lock->w_state); if (lock->flag & flag) { erts_printf("%20s [%30s] [r/w state %4ld/%4ld] id %T %s\r\n", action, lock->name, r_state, w_state, lock->id, extra); } }
void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line) { erts_lcnt_thread_data_t *eltd; erts_lcnt_time_t timer; erts_lcnt_time_t time_wait; erts_lcnt_lock_stats_t *stats; #ifdef DEBUG erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; if (!ERTS_LCNT_LOCK_TYPE(lock)) return; #ifdef DEBUG if (!(lock->flag & (ERTS_LCNT_LT_RWMUTEX | ERTS_LCNT_LT_RWSPINLOCK))) { flowstate = ethr_atomic_read(&lock->flowstate); ASSERT(flowstate == 0); ethr_atomic_inc( &lock->flowstate); } #endif eltd = lcnt_get_thread_data(); ASSERT(eltd); /* if lock was in conflict, time it */ if (erts_lcnt_rt_options & ERTS_LCNT_OPT_LOCATION) { stats = lcnt_get_lock_stats(lock, file, line); } else { stats = &lock->stats[0]; } if (eltd->timer_set) { lcnt_time(&timer); lcnt_time_diff(&time_wait, &timer, &(eltd->timer)); lcnt_update_stats(stats, eltd->lock_in_conflict, &time_wait); eltd->timer_set--; ASSERT(eltd->timer_set >= 0); } else { lcnt_update_stats(stats, eltd->lock_in_conflict, NULL); } }
void erts_lcnt_trylock(erts_lcnt_lock_t *lock, int res) { /* Determine lock_state via res instead of state */ #ifdef DEBUG erts_aint_t flowstate; #endif if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return; if (res != EBUSY) { #ifdef DEBUG flowstate = ethr_atomic_read(&lock->flowstate); ASSERT(flowstate == 0); ethr_atomic_inc( &lock->flowstate); #endif ethr_atomic_inc(&lock->w_state); lcnt_update_stats(&(lock->stats[0]), 0, NULL); } else { ethr_atomic_inc(&lock->stats[0].tries); ethr_atomic_inc(&lock->stats[0].colls); } }
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"); }