ast_err Msgtest_read(ast_runtime* rt, Msgtest** msgtest_vp) { ast_err status = AST_NOERR; uint32_t wiretype, fieldno; Msgtest* msgtest_v; msgtest_v = (Msgtest*)ast_alloc(rt,sizeof(Msgtest)); if(msgtest_v == NULL) return AST_ENOMEM; while(status == AST_NOERR) { status = ast_read_tag(rt,&wiretype,&fieldno); if(status == AST_EOF) {status = AST_NOERR; break;} if(status != AST_NOERR) break; switch (fieldno) { case 1: { size_t size; if(wiretype != ast_counted) {status=AST_EFAIL; goto done;} status = ast_read_size(rt,&size); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_mark(rt,size); status = Submsg_read(rt,&msgtest_v->rmsg); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_unmark(rt); } break; case 2: { size_t size; if(wiretype != ast_counted) {status=AST_EFAIL; goto done;} status = ast_read_size(rt,&size); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_mark(rt,size); msgtest_v->omsg.defined = 1; msgtest_v->omsg.value = NULL; status = Submsg_read(rt,&msgtest_v->omsg.value); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_unmark(rt); } break; case 3: { size_t size; Submsg* tmp; if(wiretype != ast_counted) {status=AST_EFAIL; goto done;} status = ast_read_size(rt,&size); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_mark(rt,size); status = Submsg_read(rt,&tmp); if(status != AST_NOERR) {ACATCH(status); goto done;} status = ast_repeat_append(rt,ast_message,&msgtest_v->pmsg,&tmp); if(status != AST_NOERR) {ACATCH(status); goto done;} ast_unmark(rt); } break; default: status = ast_skip_field(rt,wiretype,fieldno); if(status != AST_NOERR) {ACATCH(status); goto done;} }; /*switch*/ };/*while*/ if(status != AST_NOERR) {ACATCH(status); goto done;} if(msgtest_vp) *msgtest_vp = msgtest_v; done: return status; } /*Msgtest_read*/
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char* mutex_name, ast_mutex_t *t) { int res; #ifdef DEBUG_THREADS struct ast_lock_track *lt; int canlog = strcmp(filename, "logger.c") & t->tracking; #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { /* Don't warn abount uninitialized mutex. * Simple try to initialize it. * May be not needed in linux system. */ res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t); if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n", filename, lineno, func, mutex_name); return res; } } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ if (t->tracking && !t->track) { ast_reentrancy_init(&t->track); } lt = t->track; if (t->tracking) { #ifdef HAVE_BKTR ast_reentrancy_lock(lt); if (lt->reentrancy != AST_MAX_REENTRANCY) { ast_bt_get_addresses(<->backtrace[lt->reentrancy]); bt = <->backtrace[lt->reentrancy]; } ast_reentrancy_unlock(lt); ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt); #else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t); #endif } #endif /* DEBUG_THREADS */ #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS) { time_t seconds = time(NULL); time_t wait_time, reported_wait = 0; do { #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 1); #endif res = pthread_mutex_trylock(&t->mutex); #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 0); #endif if (res == EBUSY) { wait_time = time(NULL) - seconds; if (wait_time > reported_wait && (wait_time % 5) == 0) { __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", filename, lineno, func, (int) wait_time, mutex_name); ast_reentrancy_lock(lt); #ifdef HAVE_BKTR __dump_backtrace(<->backtrace[lt->reentrancy], canlog); #endif __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name); #ifdef HAVE_BKTR __dump_backtrace(<->backtrace[ROFFSET], canlog); #endif ast_reentrancy_unlock(lt); reported_wait = wait_time; } usleep(200); } } while (res == EBUSY); } #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */ #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 1); res = pthread_mutex_trylock(&t->mutex); ast_mark(mtx_prof, 0); if (res) #endif res = pthread_mutex_lock(&t->mutex); #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */ #ifdef DEBUG_THREADS if (t->tracking && !res) { ast_reentrancy_lock(lt); if (lt->reentrancy < AST_MAX_REENTRANCY) { lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = lineno; lt->func[lt->reentrancy] = func; lt->thread[lt->reentrancy] = pthread_self(); lt->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", filename, lineno, func, mutex_name); } ast_reentrancy_unlock(lt); if (t->tracking) { ast_mark_lock_acquired(t); } } else if (t->tracking) { #ifdef HAVE_BKTR if (lt->reentrancy) { ast_reentrancy_lock(lt); bt = <->backtrace[lt->reentrancy-1]; ast_reentrancy_unlock(lt); } else { bt = NULL; } ast_remove_lock_info(t, bt); #else ast_remove_lock_info(t); #endif } if (res) { __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n", filename, lineno, func, strerror(res)); DO_THREAD_CRASH; } #endif /* DEBUG_THREADS */ return res; }
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char* mutex_name, ast_mutex_t *t) { int res; #ifdef DEBUG_THREADS struct ast_lock_track *lt = NULL; int canlog = t->tracking && strcmp(filename, "logger.c"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif if (t->tracking) { lt = ast_get_reentrancy(&t->track); } if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; /* The implementation of backtrace() may have its own locks. * Capture the backtrace outside of the reentrancy lock to * avoid deadlocks. See ASTERISK-22455. */ ast_bt_get_addresses(&tmp); ast_reentrancy_lock(lt); if (lt->reentrancy < AST_MAX_REENTRANCY) { lt->backtrace[lt->reentrancy] = tmp; bt = <->backtrace[lt->reentrancy]; } ast_reentrancy_unlock(lt); ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt); #else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t); #endif } #endif /* DEBUG_THREADS */ #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS) { time_t seconds = time(NULL); time_t wait_time, reported_wait = 0; do { #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 1); #endif res = pthread_mutex_trylock(&t->mutex); #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 0); #endif if (res == EBUSY) { wait_time = time(NULL) - seconds; if (wait_time > reported_wait && (wait_time % 5) == 0) { __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", filename, lineno, func, (int) wait_time, mutex_name); if (lt) { ast_reentrancy_lock(lt); #ifdef HAVE_BKTR __dump_backtrace(<->backtrace[lt->reentrancy], canlog); #endif __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name); #ifdef HAVE_BKTR __dump_backtrace(<->backtrace[ROFFSET], canlog); #endif ast_reentrancy_unlock(lt); } reported_wait = wait_time; } usleep(200); } } while (res == EBUSY); } #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */ #ifdef HAVE_MTX_PROFILE ast_mark(mtx_prof, 1); res = pthread_mutex_trylock(&t->mutex); ast_mark(mtx_prof, 0); if (res) #endif res = pthread_mutex_lock(&t->mutex); #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */ #ifdef DEBUG_THREADS if (lt && !res) { ast_reentrancy_lock(lt); if (lt->reentrancy < AST_MAX_REENTRANCY) { lt->file[lt->reentrancy] = filename; lt->lineno[lt->reentrancy] = lineno; lt->func[lt->reentrancy] = func; lt->thread[lt->reentrancy] = pthread_self(); lt->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", filename, lineno, func, mutex_name); } ast_reentrancy_unlock(lt); ast_mark_lock_acquired(t); } else if (lt) { #ifdef HAVE_BKTR if (lt->reentrancy) { ast_reentrancy_lock(lt); bt = <->backtrace[lt->reentrancy-1]; ast_reentrancy_unlock(lt); } else { bt = NULL; } ast_remove_lock_info(t, bt); #else ast_remove_lock_info(t); #endif } if (res) { __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n", filename, lineno, func, strerror(res)); DO_THREAD_CRASH; } #endif /* DEBUG_THREADS */ return res; }
/* * This is testing code for astobj */ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ao2_container *c1; struct ao2_container *c2; int i, lim; char *obj; static int prof_id = -1; struct ast_cli_args fake_args = { a->fd, 0, NULL }; switch (cmd) { case CLI_INIT: e->command = "astobj2 test"; e->usage = "Usage: astobj2 test <num>\n" " Runs astobj2 test. Creates 'num' objects,\n" " and test iterators, callbacks and maybe other stuff\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != 3) { return CLI_SHOWUSAGE; } if (prof_id == -1) { prof_id = ast_add_profile("ao2_alloc", 0); } ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]); lim = atoi(a->argv[2]); ast_cli(a->fd, "called astobj_test\n"); handle_astobj2_stats(e, CLI_HANDLER, &fake_args); /* * Allocate a list container. */ c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */, NULL /* no callback */, "test"); ast_cli(a->fd, "container allocated as %p\n", c1); /* * fill the container with objects. * ao2_alloc() gives us a reference which we pass to the * container when we do the insert. */ for (i = 0; i < lim; i++) { ast_mark(prof_id, 1 /* start */); obj = ao2_t_alloc(80, NULL,"test"); ast_mark(prof_id, 0 /* stop */); ast_cli(a->fd, "object %d allocated as %p\n", i, obj); sprintf(obj, "-- this is obj %d --", i); ao2_link(c1, obj); /* At this point, the refcount on obj is 2 due to the allocation * and linking. We can go ahead and reduce the refcount by 1 * right here so that when the container is unreffed later, the * objects will be freed */ ao2_t_ref(obj, -1, "test"); } ast_cli(a->fd, "testing callbacks\n"); ao2_t_callback(c1, 0, print_cb, a, "test callback"); ast_cli(a->fd, "testing container cloning\n"); c2 = ao2_container_clone(c1, 0); if (ao2_container_count(c1) != ao2_container_count(c2)) { ast_cli(a->fd, "Cloned container does not have the same number of objects!\n"); } ao2_t_callback(c2, 0, print_cb, a, "test callback"); ast_cli(a->fd, "testing iterators, remove every second object\n"); { struct ao2_iterator ai; int x = 0; ai = ao2_iterator_init(c1, 0); while ( (obj = ao2_t_iterator_next(&ai,"test")) ) { ast_cli(a->fd, "iterator on <%s>\n", obj); if (x++ & 1) ao2_t_unlink(c1, obj,"test"); ao2_t_ref(obj, -1,"test"); } ao2_iterator_destroy(&ai); ast_cli(a->fd, "testing iterators again\n"); ai = ao2_iterator_init(c1, 0); while ( (obj = ao2_t_iterator_next(&ai,"test")) ) { ast_cli(a->fd, "iterator on <%s>\n", obj); ao2_t_ref(obj, -1,"test"); } ao2_iterator_destroy(&ai); } ast_cli(a->fd, "testing callbacks again\n"); ao2_t_callback(c1, 0, print_cb, a, "test callback"); ast_verbose("now you should see an error and possible assertion failure messages:\n"); ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */ ast_cli(a->fd, "destroy container\n"); ao2_t_ref(c1, -1, ""); /* destroy container */ ao2_t_ref(c2, -1, ""); /* destroy container */ handle_astobj2_stats(e, CLI_HANDLER, &fake_args); return CLI_SUCCESS; }