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 */ if (ethr_spinlock_init(&free_blocks_lock) != 0) lc_abort(); erts_tsd_key_create(&locks_key); }
static void unlock_of_required_lock(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Unlocking required ", lck, " lock!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void required_not_locked(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Required ", lck, " lock not locked!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void require_twice(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Require on ", lck, " lock already required!\n"); print_curr_locks(thr); lc_abort(); }
static void required_not_locked(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Required ", lck, " lock not locked!\n"); print_curr_locks(thr); lc_abort(); }
static void unlock_of_required_lock(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Unlocking required ", lck, " lock!\n"); print_curr_locks(thr); lc_abort(); }
static void unrequire_of_not_required_lock(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Unrequire on ", lck, " lock not required!\n"); print_curr_locks(thr); lc_abort(); }
static void unlock_of_not_locked(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Unlocking ", lck, " lock which is not locked by thread!\n"); print_curr_locks(thr); lc_abort(); }
static void unrequire_of_not_required_lock(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Unrequire on ", lck, " lock not required!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void require_twice(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Require on ", lck, " lock already required!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void *lc_core_alloc(void) { int i; erts_lc_free_block_t *fbs; lc_unlock(); fbs = (erts_lc_free_block_t *) malloc(sizeof(erts_lc_free_block_t) * ERTS_LC_FB_CHUNK_SIZE); if (!fbs) { erts_fprintf(stderr, "Lock checker failed to allocate memory!\n"); lc_abort(); } for (i = 1; 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 lc_lock(); fbs[ERTS_LC_FB_CHUNK_SIZE-1].next = free_blocks; free_blocks = &fbs[1]; return (void *) &fbs[0]; }
static void uninitialized_lock(void) { erts_fprintf(stderr, "Performing operations on uninitialized lock!\n"); print_curr_locks(get_my_locked_locks()); lc_abort(); }
static void unlock_of_not_locked(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Unlocking ", lck, " lock which is not locked by thread!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void lock_order_violation(lc_thread_t *thr, erts_lc_lock_t *lck) { print_lock("Lock order violation occured when locking ", lck, "!\n"); print_curr_locks(thr); print_lock_order(); lc_abort(); }
static void lock_order_violation(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { print_lock("Lock order violation occured when locking ", lck, "!\n"); print_curr_locks(l_lcks); print_lock_order(); lc_abort(); }
static void lock_twice(char *prefix, erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck, Uint16 op_flags) { erts_fprintf(stderr, "%s%s", prefix, rw_op_str(op_flags)); print_lock(" ", lck, " lock which is already locked by thread!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void unlock_op_mismatch(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck, Uint16 op_flags) { erts_fprintf(stderr, "Unlocking%s ", rw_op_str(op_flags)); print_lock("", lck, " lock which mismatch previous lock operation!\n"); print_curr_locks(l_lcks); lc_abort(); }
static void lock_twice(char *prefix, lc_thread_t *thr, erts_lc_lock_t *lck, erts_lock_options_t options) { erts_fprintf(stderr, "%s (%s)", prefix, rw_op_str(options)); print_lock(" ", lck, " lock which is already locked by thread!\n"); print_curr_locks(thr); lc_abort(); }
static void unlock_op_mismatch(lc_thread_t *thr, erts_lc_lock_t *lck, erts_lock_options_t options) { erts_fprintf(stderr, "Unlocking (%s) ", rw_op_str(options)); print_lock("", lck, " lock which mismatch previous lock operation!\n"); print_curr_locks(thr); lc_abort(); }
int erts_lc_assert_failed(char *file, int line, char *assertion) { erts_fprintf(stderr, "%s:%d: Lock check assertion \"%s\" failed!\n", file, line, assertion); print_curr_locks(get_my_locked_locks()); lc_abort(); return 0; }
static void type_order_violation(char *op, erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck) { erts_fprintf(stderr, "Lock type order violation occured when "); print_lock(op, lck, "!\n"); ASSERT(l_lcks); print_curr_locks(l_lcks); lc_abort(); }
void erts_lc_fail(char *fmt, ...) { va_list args; erts_fprintf(stderr, "Lock check failed: "); va_start(args, fmt); erts_vfprintf(stderr, fmt, args); va_end(args); erts_fprintf(stderr, "\n"); print_curr_locks(get_my_locked_locks()); lc_abort(); }
static void lock_mismatch(erts_lc_locked_locks_t *l_lcks, int exact, int failed_have, erts_lc_lock_t *have, int have_len, int failed_have_not, erts_lc_lock_t *have_not, int have_not_len) { int i; erts_fprintf(stderr, "Lock mismatch found!\n"); if (failed_have >= 0) { ASSERT(have && have_len > failed_have); print_lock2("At least the ", have[failed_have].id, have[failed_have].extra, 0, " lock is not locked when it should have been\n"); } else if (failed_have_not >= 0) { ASSERT(have_not && have_not_len > failed_have_not); print_lock2("At least the ", have_not[failed_have_not].id, have_not[failed_have_not].extra, 0, " lock is locked when it should not have been\n"); } if (exact) { if (!have || have_len <= 0) erts_fprintf(stderr, "Thread should not have any locks locked at all\n"); else { erts_fprintf(stderr, "Thread should have these and only these locks " "locked:\n"); for (i = 0; i < have_len; i++) print_lock2(" ", have[i].id, have[i].extra, 0, "\n"); } } else { if (have && have_len > 0) { erts_fprintf(stderr, "Thread should at least have these locks locked:\n"); for (i = 0; i < have_len; i++) print_lock2(" ", have[i].id, have[i].extra, 0, "\n"); } if (have_not && have_not_len > 0) { erts_fprintf(stderr, "Thread should at least not have these locks " "locked:\n"); for (i = 0; i < have_not_len; i++) print_lock2(" ", have_not[i].id, have_not[i].extra, 0, "\n"); } } print_curr_locks(l_lcks); lc_abort(); }
void erts_lc_set_thread_name(char *thread_name) { erts_lc_locked_locks_t *l_lcks = get_my_locked_locks(); if (!l_lcks) (void) create_locked_locks(thread_name); else { ASSERT(l_lcks->thread_name); free((void *) l_lcks->thread_name); l_lcks->thread_name = strdup(thread_name ? thread_name : "unknown"); if (!l_lcks->thread_name) lc_abort(); } }
static void thread_exit_handler(void) { erts_lc_locked_locks_t *l_lcks = get_my_locked_locks(); if (l_lcks) { if (l_lcks->locked.first) { erts_fprintf(stderr, "Thread exiting while having locked locks!\n"); print_curr_locks(l_lcks); lc_abort(); } destroy_locked_locks(l_lcks); /* erts_tsd_set(locks_key, NULL); */ } }
static char * rw_op_str(Uint16 flags) { switch (flags & ERTS_LC_FLG_LO_READ_WRITE) { case ERTS_LC_FLG_LO_READ_WRITE: return " (rw)"; case ERTS_LC_FLG_LO_READ: return " (r)"; case ERTS_LC_FLG_LO_WRITE: erts_fprintf(stderr, "\nInternal error\n"); lc_abort(); default: break; } return ""; }
void erts_lc_check_no_locked_of_type(Uint16 flags) { erts_lc_locked_locks_t *l_lcks = get_my_locked_locks(); if (l_lcks) { erts_lc_locked_lock_t *l_lck = l_lcks->locked.first; for (l_lck = l_lcks->locked.first; l_lck; l_lck = l_lck->next) { if (l_lck->flags & flags) { erts_fprintf(stderr, "Locked lock of type %s found which isn't " "allowed here!\n", lock_type(l_lck->flags)); print_curr_locks(l_lcks); lc_abort(); } } } }
void erts_lc_check_no_locked_of_type(erts_lock_flags_t type) { lc_thread_t *thr = get_my_locked_locks(); if (thr) { lc_locked_lock_t *ll = thr->locked.first; for (ll = thr->locked.first; ll; ll = ll->next) { if ((ll->flags & ERTS_LOCK_FLAGS_MASK_TYPE) == type) { erts_fprintf(stderr, "Locked lock of type %s found which isn't " "allowed here!\n", erts_lock_flags_get_type_name(ll->flags)); print_curr_locks(thr); lc_abort(); } } } }
void erts_lc_check_no_locked_of_type(erts_lock_flags_t type) { erts_lc_locked_locks_t *l_lcks = get_my_locked_locks(); if (l_lcks) { erts_lc_locked_lock_t *l_lck = l_lcks->locked.first; for (l_lck = l_lcks->locked.first; l_lck; l_lck = l_lck->next) { if ((l_lck->flags & ERTS_LOCK_FLAGS_MASK_TYPE) == type) { erts_fprintf(stderr, "Locked lock of type %s found which isn't " "allowed here!\n", erts_lock_flags_get_type_name(l_lck->flags)); print_curr_locks(l_lcks); lc_abort(); } } } }
Sint16 erts_lc_get_lock_order_id(char *name) { int i; if (!name || name[0] == '\0') erts_fprintf(stderr, "Missing lock name\n"); else { for (i = 0; i < ERTS_LOCK_ORDER_SIZE; i++) if (strcmp(erts_lock_order[i].name, name) == 0) return i; erts_fprintf(stderr, "Lock name '%s' missing in lock order " "(update erl_lock_check.c)\n", name); } lc_abort(); return (Sint16) -1; }