void erts_lc_lock_flg(erts_lc_lock_t *lck, Uint16 op_flags) { erts_lc_locked_locks_t *l_lcks; erts_lc_locked_lock_t *l_lck; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; l_lcks = make_my_locked_locks(); l_lck = new_locked_lock(lck, op_flags); if (!l_lcks->locked.last) { ASSERT(!l_lcks->locked.first); l_lcks->locked.last = l_lcks->locked.first = l_lck; } else if (l_lcks->locked.last->id < lck->id || (l_lcks->locked.last->id == lck->id && l_lcks->locked.last->extra < lck->extra)) { if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, l_lcks->locked.last->flags)) type_order_violation("locking ", l_lcks, lck); l_lck->prev = l_lcks->locked.last; l_lcks->locked.last->next = l_lck; l_lcks->locked.last = l_lck; } else if (l_lcks->locked.last->id == lck->id && l_lcks->locked.last->extra == lck->extra) lock_twice("Locking", l_lcks, lck, op_flags); else lock_order_violation(l_lcks, lck); }
void erts_lc_destroy_lock(erts_lc_lock_t *lck) { if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); lck->inited = 0; lck->id = -1; lck->extra = THE_NON_VALUE; lck->flags = 0; }
void erts_lc_trylock_flg_x(int locked, erts_lc_lock_t *lck, Uint16 op_flags, char *file, unsigned int line) { erts_lc_locked_locks_t *l_lcks; erts_lc_locked_lock_t *l_lck; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; l_lcks = make_my_locked_locks(); l_lck = locked ? new_locked_lock(lck, op_flags, file, line) : NULL; if (!l_lcks->locked.last) { ASSERT(!l_lcks->locked.first); if (locked) l_lcks->locked.first = l_lcks->locked.last = l_lck; } else { erts_lc_locked_lock_t *tl_lck; #if 0 /* Ok when trylocking I guess... */ if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, l_lcks->locked.last->flags)) type_order_violation("trylocking ", l_lcks, lck); #endif for (tl_lck = l_lcks->locked.last; tl_lck; tl_lck = tl_lck->prev) { if (tl_lck->id < lck->id || (tl_lck->id == lck->id && tl_lck->extra <= lck->extra)) { if (tl_lck->id == lck->id && tl_lck->extra == lck->extra) lock_twice("Trylocking", l_lcks, lck, op_flags); if (locked) { l_lck->next = tl_lck->next; l_lck->prev = tl_lck; if (tl_lck->next) tl_lck->next->prev = l_lck; else l_lcks->locked.last = l_lck; tl_lck->next = l_lck; } return; } } if (locked) { l_lck->next = l_lcks->locked.first; l_lcks->locked.first->prev = l_lck; l_lcks->locked.first = l_lck; } } }
void erts_lc_trylock_flg_x(int locked, erts_lc_lock_t *lck, erts_lock_options_t options, char *file, unsigned int line) { lc_thread_t *thr; lc_locked_lock_t *ll; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; thr = make_my_locked_locks(); ll = locked ? new_locked_lock(thr, lck, options, file, line) : NULL; if (!thr->locked.last) { ASSERT(!thr->locked.first); if (locked) thr->locked.first = thr->locked.last = ll; } else { lc_locked_lock_t *tl_lck; #if 0 /* Ok when trylocking I guess... */ if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, thr->locked.last->flags)) type_order_violation("trylocking ", thr, lck); #endif for (tl_lck = thr->locked.last; tl_lck; tl_lck = tl_lck->prev) { if (tl_lck->id < lck->id || (tl_lck->id == lck->id && tl_lck->extra <= lck->extra)) { if (tl_lck->id == lck->id && tl_lck->extra == lck->extra && lck->check_order) lock_twice("Trylocking", thr, lck, options); if (locked) { ll->next = tl_lck->next; ll->prev = tl_lck; if (tl_lck->next) tl_lck->next->prev = ll; else thr->locked.last = ll; tl_lck->next = ll; } return; } } if (locked) { ll->next = thr->locked.first; thr->locked.first->prev = ll; thr->locked.first = ll; } } }
void erts_lc_lock_flg_x(erts_lc_lock_t *lck, erts_lock_options_t options, char *file, unsigned int line) { lc_thread_t *thr; lc_locked_lock_t *new_ll; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; thr = make_my_locked_locks(); new_ll = new_locked_lock(thr, lck, options, file, line); if (!thr->locked.last) { ASSERT(!thr->locked.first); thr->locked.last = thr->locked.first = new_ll; ASSERT(0 < lck->id && lck->id < ERTS_LOCK_ORDER_SIZE); thr->matrix.m[lck->id][0] = 1; } else if (( ! lck->check_order && thr->locked.last->id == lck->id) || (thr->locked.last->id < lck->id || (thr->locked.last->id == lck->id && thr->locked.last->extra < lck->extra))) { lc_locked_lock_t* ll; if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, thr->locked.last->flags)) { type_order_violation("locking ", thr, lck); } ASSERT(0 < lck->id && lck->id < ERTS_LOCK_ORDER_SIZE); ll = thr->locked.last; thr->matrix.m[lck->id][ll->id] |= 1; for (ll = ll->prev; ll; ll = ll->prev) { ASSERT(0 < ll->id && ll->id < ERTS_LOCK_ORDER_SIZE); thr->matrix.m[lck->id][ll->id] |= 2; } new_ll->prev = thr->locked.last; thr->locked.last->next = new_ll; thr->locked.last = new_ll; } else if (thr->locked.last->id == lck->id && thr->locked.last->extra == lck->extra) lock_twice("Locking", thr, lck, options); else lock_order_violation(thr, lck); }
void erts_lc_unlock_flg(erts_lc_lock_t *lck, Uint16 op_flags) { erts_lc_locked_locks_t *l_lcks; erts_lc_locked_lock_t *l_lck; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; l_lcks = get_my_locked_locks(); if (l_lcks) { l_lck = l_lcks->required.first; if (find_lock(&l_lck, lck)) unlock_of_required_lock(l_lcks, lck); } for (l_lck = l_lcks ? l_lcks->locked.last : NULL; l_lck; l_lck = l_lck->prev) { if (l_lck->id == lck->id && l_lck->extra == lck->extra) { if ((l_lck->flags & ERTS_LC_FLG_LO_ALL) != op_flags) unlock_op_mismatch(l_lcks, lck, op_flags); if (l_lck->prev) l_lck->prev->next = l_lck->next; else l_lcks->locked.first = l_lck->next; if (l_lck->next) l_lck->next->prev = l_lck->prev; else l_lcks->locked.last = l_lck->prev; lc_free((void *) l_lck); return; } } unlock_of_not_locked(l_lcks, lck); }
void erts_lc_unlock_flg(erts_lc_lock_t *lck, erts_lock_options_t options) { lc_thread_t *thr; lc_locked_lock_t *ll; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; thr = get_my_locked_locks(); if (thr) { ll = thr->required.first; if (find_lock(&ll, lck)) unlock_of_required_lock(thr, lck); } for (ll = thr ? thr->locked.last : NULL; ll; ll = ll->prev) { if (ll->id == lck->id && ll->extra == lck->extra) { if ((ll->taken_options & ERTS_LOCK_OPTIONS_RDWR) != options) unlock_op_mismatch(thr, lck, options); if (ll->prev) ll->prev->next = ll->next; else thr->locked.first = ll->next; if (ll->next) ll->next->prev = ll->prev; else thr->locked.last = ll->prev; lc_free(thr, ll); return; } } unlock_of_not_locked(thr, lck); }
void erts_lc_might_unlock_flg(erts_lc_lock_t *lck, Uint16 op_flags) { erts_lc_locked_locks_t *l_lcks; erts_lc_locked_lock_t *l_lck; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; l_lcks = get_my_locked_locks(); if (l_lcks) { l_lck = l_lcks->required.first; if (find_lock(&l_lck, lck)) unlock_of_required_lock(l_lcks, lck); } l_lck = l_lcks->locked.first; if (!find_lock(&l_lck, lck)) unlock_of_not_locked(l_lcks, lck); }
void erts_lc_might_unlock_flg(erts_lc_lock_t *lck, erts_lock_options_t options) { lc_thread_t *thr; lc_locked_lock_t *ll; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return; thr = get_my_locked_locks(); if (thr) { ll = thr->required.first; if (find_lock(&ll, lck)) unlock_of_required_lock(thr, lck); } ll = thr->locked.first; if (!find_lock(&ll, lck)) unlock_of_not_locked(thr, lck); }
int erts_lc_trylock_force_busy_flg(erts_lc_lock_t *lck, Uint16 op_flags) { #ifdef ERTS_LC_DO_NOT_FORCE_BUSY_TRYLOCK_ON_LOCK_ORDER_VIOLATION return 0; #else /* * Force busy trylock if locking doesn't follow lock order. * This in order to make sure that caller can handle * the situation without causing a lock order violation. */ erts_lc_locked_locks_t *l_lcks; if (lck->inited != ERTS_LC_INITITALIZED) uninitialized_lock(); if (lck->id < 0) return 0; l_lcks = get_my_locked_locks(); if (!l_lcks || !l_lcks->locked.first) { ASSERT(!l_lcks || !l_lcks->locked.last); return 0; } else { erts_lc_locked_lock_t *tl_lck; ASSERT(l_lcks->locked.last); #if 0 /* Ok when trylocking I guess... */ if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, l_lcks->locked.last->flags)) type_order_violation("trylocking ", l_lcks, lck); #endif if (l_lcks->locked.last->id < lck->id || (l_lcks->locked.last->id == lck->id && l_lcks->locked.last->extra < lck->extra)) return 0; /* * Lock order violation */ /* Check that we are not trying to lock this lock twice */ for (tl_lck = l_lcks->locked.last; tl_lck; tl_lck = tl_lck->prev) { if (tl_lck->id < lck->id || (tl_lck->id == lck->id && tl_lck->extra <= lck->extra)) { if (tl_lck->id == lck->id && tl_lck->extra == lck->extra) lock_twice("Trylocking", l_lcks, lck, op_flags); break; } } #ifndef ERTS_LC_ALLWAYS_FORCE_BUSY_TRYLOCK_ON_LOCK_ORDER_VIOLATION /* We only force busy if a lock order violation would occur and when on an even millisecond. */ { SysTimeval tv; sys_gettimeofday(&tv); if ((tv.tv_usec / 1000) & 1) return 0; } #endif return 1; } #endif }