This supercedes prior patches submitted for mutex initialization. On Linux static mutexes are initialized statically, as before, whereas on FreeBSD they are initialized and destroyed using constructors and destructors. All other mutexes are initialized explicitly at load_module(), allocation, or startup, and destroyed on unload_module(), deallocation, or shutdown. At startup, run a regression test for recursive mutexes and print a warning if the application is not thread safe. -DDEBUG_THREADS turns on diagnostic warning messages in lock.h for uninitialized locks and deadlock. Change g++ to $(CXX) in order to use alternate compilers for diagnostics. Change ifeq (${OSARCH},FreeBSD) to ifeq ($(findstring BSD,${OSARCH}),BSD) for portions of Makefiles that are common to BSD flavors. Index: Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/Makefile,v retrieving revision 1.95 diff -u -r1.95 Makefile --- Makefile 13 Jun 2004 21:25:09 -0000 1.95 +++ Makefile 22 Jun 2004 16:12:05 -0000 @@ -26,15 +26,12 @@ #PROC=athlon OPTIONS+=-m64 endif -else -ifeq (${OSARCH},FreeBSD) -PROC=$(shell uname -m) -else -ifeq (${OSARCH},OpenBSD) -PROC=$(shell uname -m) -endif endif + +ifeq ($(findstring BSD,${OSARCH}),BSD) +PROC=$(shell uname -m) endif + # Pentium Pro Optimize #PROC=i686 @@ -120,10 +117,15 @@ CFLAGS+=$(OPTIMIZE) CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi) CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi) + ifeq (${OSARCH},FreeBSD) -CFLAGS+=-pthread +OSVERSION=$(shell make -V OSVERSION -f /usr/share/mk/bsd.port.subdir.mk) +CFLAGS+=$(if ${OSVERSION}<500016,-D_THREAD_SAFE) +LIBS+=$(if ${OSVERSION}<502102,-lc_r,-pthread) INCLUDE+=-I/usr/local/include -endif +CFLAGS+=$(shell if [ -d /usr/local/include/spandsp ]; then echo "-I/usr/local/include/spandsp"; fi) +endif # FreeBSD + ifeq (${OSARCH},OpenBSD) CFLAGS+=-pthread endif @@ -161,14 +163,6 @@ ifeq (${OSARCH},Linux) LIBS=-ldl -lpthread endif -ifeq (${OSARCH},OpenBSD) -LIBS=-pthread -else -ifeq (${OSARCH},FreeBSD) -LIBS=-pthread -else -endif -endif LIBS+=-lncurses -lm ifeq (${OSARCH},Linux) LIBS+=-lresolv #-lnjamd Index: asterisk.c =================================================================== RCS file: /usr/cvsroot/asterisk/asterisk.c,v retrieving revision 1.95 diff -u -r1.95 asterisk.c --- asterisk.c 21 Jun 2004 19:12:20 -0000 1.95 +++ asterisk.c 22 Jun 2004 16:12:06 -0000 @@ -49,6 +49,7 @@ #include "asterisk.h" #include #include +#include #if defined(__FreeBSD__) #include @@ -1561,6 +1562,11 @@ term_init(); printf(term_end()); fflush(stdout); + + /* Test recursive mutex locking. */ + if(test_for_thread_safety()) + ast_verbose("Warning! Asterisk is not thread safe.\n"); + if (option_console && !option_verbose) ast_verbose("[ Reading Master Configuration ]"); ast_readconfig(); Index: manager.c =================================================================== RCS file: /usr/cvsroot/asterisk/manager.c,v retrieving revision 1.55 diff -u -r1.55 manager.c --- manager.c 9 Jun 2004 01:45:07 -0000 1.55 +++ manager.c 22 Jun 2004 16:12:08 -0000 @@ -220,6 +220,7 @@ sessions = cur->next; if (s->fd > -1) close(s->fd); + ast_mutex_destroy(&s->lock); free(s); } else ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s); Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.127 diff -u -r1.127 pbx.c --- pbx.c 22 Jun 2004 03:51:34 -0000 1.127 +++ pbx.c 22 Jun 2004 16:12:11 -0000 @@ -4173,6 +4173,7 @@ e = e->next; destroy_exten(el); } + ast_mutex_destroy(&tmp->lock); free(tmp); if (!con) { /* Might need to get another one -- restart */ Index: sched.c =================================================================== RCS file: /usr/cvsroot/asterisk/sched.c,v retrieving revision 1.11 diff -u -r1.11 sched.c --- sched.c 21 Nov 2003 22:05:08 -0000 1.11 +++ sched.c 22 Jun 2004 16:12:11 -0000 @@ -63,6 +63,7 @@ struct sched_context *tmp; tmp = malloc(sizeof(struct sched_context)); if (tmp) { + memset(tmp, 0, sizeof(struct sched_context)); ast_mutex_init(&tmp->lock); tmp->eventcnt = 1; tmp->schedcnt = 0; @@ -97,6 +98,7 @@ } /* And the context */ ast_mutex_unlock(&con->lock); + ast_mutex_destroy(&con->lock); free(con); } Index: utils.c =================================================================== RCS file: /usr/cvsroot/asterisk/utils.c,v retrieving revision 1.7 diff -u -r1.7 utils.c --- utils.c 12 Jun 2004 14:53:53 -0000 1.7 +++ utils.c 22 Jun 2004 16:12:11 -0000 @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -22,9 +24,9 @@ AST_MUTEX_DEFINE_STATIC(__mutex); -int gethostbyname_r (const char *name, struct hostent *ret, char *buf, - size_t buflen, struct hostent **result, - int *h_errnop) +static int gethostbyname_r (const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, + int *h_errnop) { int hsave; struct hostent *ph; @@ -143,3 +145,60 @@ return NULL; return &hp->hp; } + + +/* This is a regression test for recursive mutexes. + test_for_thread_safety() will return 0 if recursive mutex locks are + working properly, and non-zero if they are not working properly. */ + +AST_MUTEX_DEFINE_STATIC(test_lock); +AST_MUTEX_DEFINE_STATIC(test_lock2); +static pthread_t test_thread; +static int lock_count = 0; +static int test_errors = 0; + +static void *test_thread_body(void *data) +{ + ast_mutex_lock(&test_lock); + lock_count += 10; + if(lock_count != 10) test_errors++; + ast_mutex_lock(&test_lock); + lock_count += 10; + if(lock_count != 20) test_errors++; + ast_mutex_lock(&test_lock2); + ast_mutex_unlock(&test_lock); + lock_count -= 10; + if(lock_count != 10) test_errors++; + ast_mutex_unlock(&test_lock); + lock_count -= 10; + ast_mutex_unlock(&test_lock2); + if(lock_count != 0) test_errors++; + return NULL; +} + +int test_for_thread_safety(void) +{ + ast_mutex_lock(&test_lock2); + ast_mutex_lock(&test_lock); + lock_count += 1; + ast_mutex_lock(&test_lock); + lock_count += 1; + pthread_create(&test_thread, NULL, test_thread_body, NULL); + pthread_yield(); + usleep(100); + if(lock_count != 2) test_errors++; + ast_mutex_unlock(&test_lock); + lock_count -= 1; + pthread_yield(); + usleep(100); + if(lock_count != 1) test_errors++; + ast_mutex_unlock(&test_lock); + lock_count -= 1; + if(lock_count != 0) test_errors++; + ast_mutex_unlock(&test_lock2); + pthread_yield(); + usleep(100); + if(lock_count != 0) test_errors++; + pthread_join(test_thread, NULL); + return(test_errors); /* return 0 on success. */ +} Index: agi/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/agi/Makefile,v retrieving revision 1.7 diff -u -r1.7 Makefile --- agi/Makefile 4 May 2004 01:46:01 -0000 1.7 +++ agi/Makefile 22 Jun 2004 16:12:11 -0000 @@ -22,10 +22,10 @@ for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done eagi-test: eagi-test.o - $(CC) -o eagi-test eagi-test.o - + $(CC) $(CFLAGS) -o eagi-test eagi-test.o + eagi-sphinx-test: eagi-sphinx-test.o - $(CC) -o eagi-sphinx-test eagi-sphinx-test.o + $(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o clean: rm -f *.so *.o look .depend eagi-test eagi-sphinx-test Index: apps/app_queue.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_queue.c,v retrieving revision 1.70 diff -u -r1.70 app_queue.c --- apps/app_queue.c 19 Jun 2004 16:00:50 -0000 1.70 +++ apps/app_queue.c 22 Jun 2004 16:12:13 -0000 @@ -330,6 +330,7 @@ } ast_mutex_unlock(&qlock); free_members(q, 1); + ast_mutex_destroy(&q->lock); free(q); } Index: apps/app_rpt.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_rpt.c,v retrieving revision 1.6 diff -u -r1.6 app_rpt.c --- apps/app_rpt.c 21 Jun 2004 04:24:50 -0000 1.6 +++ apps/app_rpt.c 22 Jun 2004 16:12:14 -0000 @@ -2113,7 +2113,10 @@ int unload_module(void) { + int i; STANDARD_HANGUP_LOCALUSERS; + for(i = 0; i < nrpts; i++) { + ast_mutex_destroy(&rpt_vars[i].lock); return ast_unregister_application(app); return 0; } Index: apps/app_voicemail.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v retrieving revision 1.113 diff -u -r1.113 app_voicemail.c --- apps/app_voicemail.c 16 Jun 2004 18:35:01 -0000 1.113 +++ apps/app_voicemail.c 22 Jun 2004 16:12:17 -0000 @@ -330,7 +330,7 @@ PGconn *dbhandler; char dboption[256]; -ast_mutex_t postgreslock; +AST_MUTEX_DEFINE_STATIC(postgreslock); static int sql_init(void) { @@ -342,8 +342,6 @@ ast_log(LOG_WARNING, "Error Logging into database %s: %s\n",dboption,PQerrorMessage(dbhandler)); return(-1); } - ast_mutex_init(&postgreslock); - /* fprintf(stderr,"postgres login OK\n"); */ return(0); } Index: astman/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/astman/Makefile,v retrieving revision 1.8 diff -u -r1.8 Makefile --- astman/Makefile 4 Jun 2004 15:44:14 -0000 1.8 +++ astman/Makefile 22 Jun 2004 16:12:17 -0000 @@ -4,7 +4,7 @@ CFLAGS+=-DNO_AST_MM OSARCH=$(shell uname -s) -ifeq (${OSARCH},FreeBSD) +ifeq ($(findstring BSD,${OSARCH}),BSD) CFLAGS+=-I/usr/local/include -L/usr/local/lib endif Index: channels/chan_agent.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_agent.c,v retrieving revision 1.74 diff -u -r1.74 chan_agent.c --- channels/chan_agent.c 9 Jun 2004 01:45:07 -0000 1.74 +++ channels/chan_agent.c 22 Jun 2004 16:12:18 -0000 @@ -213,8 +213,8 @@ if (p) { memset(p, 0, sizeof(struct agent_pvt)); strncpy(p->agent, tmp, sizeof(p->agent) -1); - ast_mutex_init( &p->lock ); - ast_mutex_init( &p->app_lock ); + ast_mutex_init(&p->lock); + ast_mutex_init(&p->app_lock); p->owning_app = (pthread_t) -1; p->app_sleep_cond = 1; p->group = group; @@ -252,8 +252,11 @@ ast_mutex_unlock(&p->app_lock); if (chan) ast_channel_free(chan); - if (p->dead) + if (p->dead) { + ast_mutex_destroy(&p->lock); + ast_mutex_destroy(&p->app_lock); free(p); + } return 0; } @@ -571,6 +574,8 @@ kill it later */ p->abouttograb = 0; } else if (p->dead) { + ast_mutex_destroy(&p->lock); + ast_mutex_destroy(&p->app_lock); free(p); } else { if (p->chan) { @@ -844,6 +849,8 @@ /* Destroy if appropriate */ if (!p->owner) { if (!p->chan) { + ast_mutex_destroy(&p->lock); + ast_mutex_destroy(&p->app_lock); free(p); } else { /* Cause them to hang up */ @@ -1425,8 +1432,11 @@ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent); /* If there is no owner, go ahead and kill it now */ - if (p->dead && !p->owner) + if (p->dead && !p->owner) { + ast_mutex_destroy(&p->lock); + ast_mutex_destroy(&p->app_lock); free(p); + } } else { ast_mutex_unlock(&p->lock); Index: channels/chan_h323.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_h323.c,v retrieving revision 1.59 diff -u -r1.59 chan_h323.c --- channels/chan_h323.c 15 Jun 2004 20:56:05 -0000 1.59 +++ channels/chan_h323.c 22 Jun 2004 16:12:19 -0000 @@ -55,7 +55,8 @@ #include #include #include -#ifdef __OpenBSD__ +#include +#if defined(BSD) #include #ifndef IPTOS_MINCOST #define IPTOS_MINCOST 0x02 @@ -186,8 +187,10 @@ } if (!cur) { ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur); - } else + } else { + ast_mutex_destroy(&p->lock); free(p); + } } static void oh323_destroy(struct oh323_pvt *p) @@ -1840,11 +1843,14 @@ set_rtp_peer: oh323_set_rtp_peer, }; - int load_module() { int res; + ast_mutex_init(&userl.lock); + ast_mutex_init(&peerl.lock); + ast_mutex_init(&aliasl.lock); + res = reload_config(); if (res) { @@ -1948,6 +1954,7 @@ pl = p; p = p->next; /* free associated memory */ + ast_mutex_destroy(&pl->lock); free(pl); } iflist = NULL; Index: channels/chan_iax.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_iax.c,v retrieving revision 1.59 diff -u -r1.59 chan_iax.c --- channels/chan_iax.c 9 Jun 2004 01:45:07 -0000 1.59 +++ channels/chan_iax.c 22 Jun 2004 16:12:23 -0000 @@ -447,7 +447,7 @@ struct iax_dpcache *peer; /* For linking in peers */ } *dpcache; -static ast_mutex_t dpcache_lock; +AST_MUTEX_DEFINE_STATIC(dpcache_lock); #ifdef DEBUG_SUPPORT static void showframe(struct ast_iax_frame *f, struct ast_iax_full_hdr *fhi, int rx, struct sockaddr_in *sin) @@ -5369,6 +5369,12 @@ int unload_module() { + int x; + for (x=0;xaddr.sin_addr), ntohs(drop->addr.sin_port)); free(drop->trunkdata); ast_mutex_unlock(&drop->lock); + ast_mutex_destroy(&drop->lock); free(drop); } @@ -6820,6 +6821,10 @@ int unload_module() { + ast_mutex_destroy(&iaxq.lock); + ast_mutex_destroy(&userl.lock); + ast_mutex_destroy(&peerl.lock); + ast_mutex_destroy(&waresl.lock); return __unload_module(); } @@ -6867,6 +6872,7 @@ ast_mutex_init(&iaxq.lock); ast_mutex_init(&userl.lock); ast_mutex_init(&peerl.lock); + ast_mutex_init(&waresl.lock); ast_cli_register(&cli_show_users); ast_cli_register(&cli_show_channels); Index: channels/chan_local.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_local.c,v retrieving revision 1.29 diff -u -r1.29 chan_local.c --- channels/chan_local.c 22 Jun 2004 04:54:52 -0000 1.29 +++ channels/chan_local.c 22 Jun 2004 16:12:28 -0000 @@ -87,6 +87,7 @@ /* We had a glare on the hangup. Forget all this business, return and destroy p. */ ast_mutex_unlock(&p->lock); + ast_mutex_destroy(&p->lock); free(p); return -1; } @@ -271,6 +272,7 @@ prev->next = cur->next; else locals = cur->next; + ast_mutex_destroy(cur); free(cur); break; } @@ -324,8 +326,10 @@ } ast_mutex_unlock(&locallock); /* And destroy */ - if (!glaredetect) + if (!glaredetect) { + ast_mutex_destroy(&p->lock); free(p); + } return 0; } if (p->chan && !p->launchedpbx) @@ -366,6 +370,7 @@ tmp->reqformat = format; if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->context, tmp->exten); + ast_mutex_destroy(&tmp->lock); free(tmp); tmp = NULL; } else { Index: channels/chan_mgcp.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_mgcp.c,v retrieving revision 1.54 diff -u -r1.54 chan_mgcp.c --- channels/chan_mgcp.c 9 Jun 2004 01:45:07 -0000 1.54 +++ channels/chan_mgcp.c 22 Jun 2004 16:12:31 -0000 @@ -3423,15 +3423,19 @@ gw->expire = -1; gw->dynamic = 0; if (ast_get_ip(&gw->addr, v->value)) { - if (!gw_reload) + if (!gw_reload) { + ast_mutex_destroy(&gw->msgs_lock); free(gw); + } return NULL; } } } else if (!strcasecmp(v->name, "defaultip")) { if (ast_get_ip(&gw->defaddr, v->value)) { - if (!gw_reload) + if (!gw_reload) { + ast_mutex_destroy(&gw->msgs_lock); free(gw); + } return NULL; } } else if (!strcasecmp(v->name, "permit") || @@ -3501,15 +3505,17 @@ } if (!e) { + /* Allocate wildcard endpoint */ e = malloc(sizeof(struct mgcp_endpoint)); ep_reload = 0; } - /* Allocate wildcard endpoint */ - e = malloc(sizeof(struct mgcp_endpoint)); if (e) { if (!ep_reload) { memset(e, 0, sizeof(struct mgcp_endpoint)); + ast_mutex_init(&e->lock); + ast_mutex_init(&e->rqnt_queue_lock); + ast_mutex_init(&e->cmd_queue_lock); strncpy(e->name, v->value, sizeof(e->name) - 1); e->needaudit = 1; } @@ -3545,6 +3551,8 @@ if (sub) { ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name); memset(sub, 0, sizeof(struct mgcp_subchannel)); + ast_mutex_init(&sub->lock); + ast_mutex_init(&sub->cx_queue_lock); sub->parent = e; sub->id = i; snprintf(sub->txident, sizeof(sub->txident), "%08x", rand()); @@ -3594,6 +3602,9 @@ if (e) { if (!ep_reload) { memset(e, 0, sizeof(struct mgcp_endpoint)); + ast_mutex_init(&e->lock); + ast_mutex_init(&e->rqnt_queue_lock); + ast_mutex_init(&e->cmd_queue_lock); strncpy(e->name, v->value, sizeof(e->name) - 1); e->needaudit = 1; } @@ -3633,8 +3644,6 @@ /* ASSUME we're onhook */ e->hookstate = MGCP_ONHOOK; snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08x", rand()); - ast_mutex_init(&e->rqnt_queue_lock); - ast_mutex_init(&e->cmd_queue_lock); } for (i = 0, sub = NULL; i < MAX_SUBS; i++) { @@ -3652,13 +3661,14 @@ if (!ep_reload) { ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name); memset(sub, 0, sizeof(struct mgcp_subchannel)); + ast_mutex_init(&sub->lock); + ast_mutex_init(&sub->cx_queue_lock); strncpy(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic) - 1); sub->parent = e; sub->id = i; snprintf(sub->txident, sizeof(sub->txident), "%08x", rand()); sub->cxmode = MGCP_CX_INACTIVE; sub->next = e->sub; - ast_mutex_init(&sub->cx_queue_lock); e->sub = sub; } sub->nat = nat; @@ -3690,8 +3700,10 @@ } if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) { ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name); - if (!gw_reload) + if (!gw_reload) { + ast_mutex_destroy(&gw->msgs_lock); free(gw); + } return NULL; } if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) @@ -3803,8 +3815,13 @@ for (i = 0; (i < MAX_SUBS) && sub; i++) { s = sub; sub = sub->next; + ast_mutex_destroy(&s->lock); + ast_mutex_destroy(&s->cx_queue_lock); free(s); } + ast_mutex_destroy(&e->lock); + ast_mutex_destroy(&e->rqnt_queue_lock); + ast_mutex_destroy(&e->cmd_queue_lock); free(e); } @@ -4132,6 +4149,9 @@ pl = p; p = p->next; /* Free associated memory */ + ast_mutex_destroy(&pl->lock); + ast_mutex_destroy(&pl->rqnt_queue_lock); + ast_mutex_destroy(&pl->cmd_queue_lock); free(pl); } iflist = NULL; Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.420 diff -u -r1.420 chan_sip.c --- channels/chan_sip.c 21 Jun 2004 16:52:04 -0000 1.420 +++ channels/chan_sip.c 22 Jun 2004 16:12:37 -0000 @@ -2042,11 +2042,11 @@ struct sip_pvt *p; p = malloc(sizeof(struct sip_pvt)); - ast_mutex_init(&p->lock); if (!p) return NULL; /* Keep track of stuff */ memset(p, 0, sizeof(struct sip_pvt)); + ast_mutex_init(&p->lock); p->initid = -1; p->autokillid = -1; p->stateid = -1; @@ -8326,6 +8326,7 @@ pl = p; p = p->next; /* Free associated memory */ + ast_mutex_destroy(&pl->lock); free(pl); } iflist = NULL; @@ -8338,6 +8339,9 @@ if (localaddr) { ast_free_ha(localaddr); } + ast_mutex_destroy(&userl.lock); + ast_mutex_destroy(&peerl.lock); + ast_mutex_destroy(®l.lock); return 0; } Index: channels/chan_skinny.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_skinny.c,v retrieving revision 1.46 diff -u -r1.46 chan_skinny.c --- channels/chan_skinny.c 14 Jun 2004 21:18:52 -0000 1.46 +++ channels/chan_skinny.c 22 Jun 2004 16:12:39 -0000 @@ -1104,6 +1104,7 @@ l = malloc(sizeof(struct skinny_line));; if (l) { memset(l, 0, sizeof(struct skinny_line)); + ast_mutex_init(&l->lock); strncpy(l->name, v->value, sizeof(l->name) - 1); /* XXX Should we check for uniqueness?? XXX */ @@ -1145,6 +1146,7 @@ if (sub) { ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, d->name); memset(sub, 0, sizeof(struct skinny_subchannel)); + ast_mutex_init(&sub->lock); sub->parent = l; /* Make a call*ID */ sub->callid = callnums; @@ -2262,6 +2264,7 @@ sessions = cur->next; if (s->fd > -1) close(s->fd); + ast_mutex_destroy(&s->lock); free(s); } else ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s); @@ -2662,10 +2665,12 @@ for (sub=l->sub;sub;) { slast = sub; sub = sub->next; + ast_mutex_destroy(&slast->lock); free(slast); } llast = l; l = l->next; + ast_mutex_destroy(&llast->lock); free(llast); } dlast = d; @@ -2758,6 +2763,7 @@ pl = p; p = p->next; /* Free associated memory */ + ast_mutex_destroy(&pl->lock); free(pl); } iflist = NULL; Index: channels/chan_vpb.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_vpb.c,v retrieving revision 1.26 diff -u -r1.26 chan_vpb.c --- channels/chan_vpb.c 9 Jun 2004 01:45:08 -0000 1.26 +++ channels/chan_vpb.c 22 Jun 2004 16:12:40 -0000 @@ -279,8 +279,6 @@ bridges[i].fo = fo; bridges[i].c0 = c0; bridges[i].c1 = c1; - ast_mutex_init(&bridges[i].lock); - pthread_cond_init(&bridges[i].cond, NULL); } } ast_mutex_unlock(&bridge_lock); @@ -356,8 +354,6 @@ ast_mutex_lock(&bridge_lock); { bridges[i].inuse = 0; - ast_mutex_destroy(&bridges[i].lock); - pthread_cond_destroy(&bridges[i].cond); } ast_mutex_unlock(&bridge_lock); p0->bridge = NULL; @@ -975,8 +971,13 @@ bridges = (vpb_bridge_t *)malloc(max_bridges * sizeof(vpb_bridge_t) ); if(!bridges) ast_log(LOG_ERROR, "Failed to initialize bridges\n"); - else + else { memset(bridges,0,max_bridges * sizeof(vpb_bridge_t)); + for(int i = 0; i < max_bridges; i++ ) { + ast_mutex_init(&bridges[i].lock); + pthread_cond_init(&bridges[i].cond, NULL); + } + } } if(!echo_cancel) { if (model==vpb_model_v4pci) { @@ -1062,6 +1063,7 @@ tmp->vpb_model = vpb_model_v4pci; } + ast_mutex_init(&tmp->owner_lock); ast_mutex_init(&tmp->lock); ast_mutex_init(&tmp->record_lock); ast_mutex_init(&tmp->play_lock); @@ -2080,6 +2082,7 @@ p = iflist; ast_mutex_destroy(&p->lock); pthread_cancel(p->readthread); + ast_mutex_destroy(&p->owner_lock); ast_mutex_destroy(&p->record_lock); ast_mutex_destroy(&p->play_lock); ast_mutex_destroy(&p->play_dtmf_lock); @@ -2098,6 +2101,10 @@ memset(bridges, 0, sizeof bridges); } ast_mutex_unlock(&bridge_lock); ast_mutex_destroy(&bridge_lock); + for(int i = 0; i < max_bridges; i++ ) { + ast_mutex_destroy(&bridges[i].lock); + pthread_cond_destroy(&bridges[i].cond, NULL); + } free(bridges); return 0; Index: channels/chan_zap.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_zap.c,v retrieving revision 1.278 diff -u -r1.278 chan_zap.c --- channels/chan_zap.c 21 Jun 2004 03:37:13 -0000 1.278 +++ channels/chan_zap.c 22 Jun 2004 16:12:47 -0000 @@ -1756,6 +1756,14 @@ return 0; } +static void destroy_zt_pvt(struct zt_pvt **pvt) +{ + struct zt_pvt *p = *pvt; + ast_mutex_destroy(&p->lock); + free(p); + pvt = NULL; +} + static int destroy_channel(struct zt_pvt *prev, struct zt_pvt *cur, int now) { int owned = 0; @@ -1788,7 +1796,7 @@ if (cur->subs[SUB_REAL].zfd > -1) { zt_close(cur->subs[SUB_REAL].zfd); } - free(cur); + destroy_zt_pvt(&cur); } } else { if (prev) { @@ -1807,7 +1815,7 @@ if (cur->subs[SUB_REAL].zfd > -1) { zt_close(cur->subs[SUB_REAL].zfd); } - free(cur); + destroy_zt_pvt(&cur); } return 0; } @@ -5751,10 +5759,11 @@ tmp = (struct zt_pvt*)malloc(sizeof(struct zt_pvt)); if (!tmp) { ast_log(LOG_ERROR, "MALLOC FAILED\n"); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } memset(tmp, 0, sizeof(struct zt_pvt)); + ast_mutex_init(&tmp->lock); ifcount++; for (x=0;x<3;x++) tmp->subs[x].zfd = -1; @@ -5811,20 +5820,19 @@ /* Allocate a zapata structure */ if (tmp->subs[SUB_REAL].zfd < 0) { ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } memset(&p, 0, sizeof(p)); res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_GET_PARAMS, &p); if (res < 0) { ast_log(LOG_ERROR, "Unable to get parameters\n"); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (p.sigtype != (signalling & 0x3ffff)) { ast_log(LOG_ERROR, "Signalling requested is %s but line is in %s signalling\n", sig2str(signalling), sig2str(p.sigtype)); - free(tmp); - tmp = NULL; + destroy_zt_pvt(&tmp); return tmp; } if (here) { @@ -5855,18 +5863,18 @@ offset = 0; if ((signalling == SIG_PRI) && ioctl(tmp->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &offset)) { ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (span >= NUM_SPANS) { ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } else { si.spanno = 0; if (ioctl(tmp->subs[SUB_REAL].zfd,ZT_SPANSTAT,&si) == -1) { ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } /* Store the logical span first based upon the real span */ @@ -5874,7 +5882,7 @@ pri_resolve_span(&span, channel, (channel - p.chanpos), &si); if (span < 0) { ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (signalling == SIG_PRI) @@ -5895,43 +5903,43 @@ if (!matchesdchan) { if (pris[span].nodetype && (pris[span].nodetype != pritype)) { ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) { ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if ((pris[span].dialplan) && (pris[span].dialplan != dialplan)) { ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, pri_plan2str(pris[span].dialplan)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, idledial)) { ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, idledial); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, idleext)) { ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, idleext); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (pris[span].minunused && (pris[span].minunused != minunused)) { ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, minunused); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (pris[span].minidle && (pris[span].minidle != minidle)) { ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, minidle); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (pris[span].numchans >= MAX_CHANNELS) { ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel, pris[span].trunkgroup); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } pris[span].nodetype = pritype; @@ -5949,7 +5957,7 @@ tmp->call = NULL; } else { ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } } @@ -5968,7 +5976,7 @@ if (!tmp->r2) { ast_log(LOG_WARNING, "Unable to create r2 call :(\n"); zt_close(tmp->subs[SUB_REAL].zfd); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } } else { @@ -6021,7 +6029,7 @@ res = ioctl(tmp->subs[SUB_REAL].zfd, ZT_SET_PARAMS, &p); if (res < 0) { ast_log(LOG_ERROR, "Unable to set parameters\n"); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } } @@ -6081,7 +6089,6 @@ tmp->propconfno = -1; } tmp->transfer = transfer; - ast_mutex_init(&tmp->lock); strncpy(tmp->defcontext,context,sizeof(tmp->defcontext)-1); strncpy(tmp->language, language, sizeof(tmp->language)-1); strncpy(tmp->musicclass, musicclass, sizeof(tmp->musicclass)-1); @@ -6117,7 +6124,7 @@ memset(&si, 0, sizeof(si)); if (ioctl(tmp->subs[SUB_REAL].zfd,ZT_SPANSTAT,&si) == -1) { ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno)); - free(tmp); + destroy_zt_pvt(&tmp); return NULL; } if (si.alarms) tmp->inalarm = 1; @@ -6222,11 +6229,12 @@ p = malloc(sizeof(struct zt_pvt)); if (p) { memcpy(p, src, sizeof(struct zt_pvt)); + ast_mutex_init(&p->lock); p->subs[SUB_REAL].zfd = zt_open("/dev/zap/pseudo"); /* Allocate a zapata structure */ if (p->subs[SUB_REAL].zfd < 0) { ast_log(LOG_ERROR, "Unable to dup channel: %s\n", strerror(errno)); - free(p); + destroy_zt_pvt(&p); return NULL; } res = ioctl(p->subs[SUB_REAL].zfd, ZT_GET_BUFINFO, &bi); @@ -8280,8 +8288,8 @@ p = p->next; x++; /* Free associated memory */ - if(p) - free(pl); + if(pl) + destroy_zt_pvt(&pl); ast_verbose(VERBOSE_PREFIX_3 "Unregistered channel %d\n", x); } iflist = NULL; @@ -8302,6 +8310,11 @@ int unload_module() { +#ifdef ZAPATA_PRI + int y; + for (y=0;ylock); + memset(pris, 0, sizeof(pris)); + for (y=0;ylock); pris[y].fd = -1; + } #endif #endif /* 0 */ Index: channels/h323/INSTALL.openh323 =================================================================== RCS file: /usr/cvsroot/asterisk/channels/h323/INSTALL.openh323,v retrieving revision 1.4 diff -u -r1.4 INSTALL.openh323 --- channels/h323/INSTALL.openh323 3 Apr 2003 09:05:53 -0000 1.4 +++ channels/h323/INSTALL.openh323 22 Jun 2004 16:12:47 -0000 @@ -6,3 +6,13 @@ Also, you will notice they never tell you to 'make install' so don't do it. +On FreeBSD, the Makefiles are configured to +locate the compiled openh323 port, if it has +been built. Here is one way to build +openh323 and ptlib on such that the Makefiles +find it: + # cd /usr/ports/net/openh323 + # make +It is not necessary to install the port. The +asterisk makefiles do not use any files +installed by the port. Index: channels/h323/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/channels/h323/Makefile,v retrieving revision 1.15 diff -u -r1.15 Makefile --- channels/h323/Makefile 28 Apr 2004 21:06:29 -0000 1.15 +++ channels/h323/Makefile 22 Jun 2004 16:12:47 -0000 @@ -19,8 +19,15 @@ # # This needs to be updated to deal with more than just little endian machines # -CFLAGS += -march=$(shell uname -m) -DPBYTE_ORDER=PLITTLE_ENDIAN +OSARCH=$(shell uname -s) +ifneq (${OSARCH},FreeBSD) +CFLAGS += -march=$(shell uname -m) +endif +CFLAGS += -DPBYTE_ORDER=PLITTLE_ENDIAN +ifeq (${OSARCH},Linux) +LDLIBS+=-ldl +endif ############################################# # @@ -38,16 +45,22 @@ # Pre Janus release directives CFLAGS += -DNDEBUG -DDO_CRASH -DDEBUG_THREADS -CFLAGS += -pipe -Wall -fPIC -Wmissing-prototypes -Wmissing-declarations +CFLAGS += -pipe -Wall -fPIC ifeq (${OSARCH},Linux) CFLAGS += -DP_LINUX +LIBS+=-lpthread +endif +ifeq ($(findstring BSD,${OSARCH}),BSD) +CFLAGS += -pthread endif CFLAGS += -D_REENTRANT -D_GNU_SOURCE CFLAGS += -DP_HAS_SEMAPHORES -DP_SSL -DP_PTHREADS CFLAGS += -DPHAS_TEMPLATES -DPTRACING -DP_USE_PRAGMA CFLAGS += -I../../include CFLAGS += -I$(PWLIBDIR)/include/ptlib/unix -I$(PWLIBDIR)/include -CFLAGS += -I$(OPENH323DIR)/include -Wno-missing-prototypes -Wno-missing-declarations +CFLAGS += -I$(OPENH323DIR)/include +CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations +LIBS+= -lcrypto -lssl -lexpat all: libchanh323.a @@ -59,19 +72,19 @@ ast_h323.o: ast_h323.cpp - g++ -g -c -fno-rtti -o $@ $(CFLAGS) $< + $(CXX) -g -c -fno-rtti -o $@ $(CFLAGS) $< libchanh323.a: ast_h323.o ar cr libchanh323.a ast_h323.o chan_h323.so: - g++ -g -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r -L$(OPENH323DIR)/lib -lh323_linux_x86_r -L/usr/lib -lpthread -ldl -lcrypto -lssl -lexpat + $(CXX) -g -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r -L$(OPENH323DIR)/lib -lh323_linux_x86_r -L/usr/lib $(CHANH323LIB) chan_h323_d.so: chan_h323.o ast_h323.o - g++ -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_d -L$(OPENH323DIR)/lib -lh323_linux_x86_d -L/usr/lib -lpthread -ldl -lcrypto -lssl -lexpat + $(CXX) -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_d -L$(OPENH323DIR)/lib -lh323_linux_x86_d -L/usr/lib $(CHANH323LIB) chan_h323_s.so: chan_h323.o ast_h323.o - g++ -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r_s -L$(OPENH323DIR)/lib -lh323_linux_x86_r_s -L/usr/lib -lpthread -ldl -lcrypto -lssl -lexpat + $(CXX) -shared -Xlinker -x -o chan_h323.so chan_h323.o ast_h323.o -L$(PWLIBDIR)/lib -lpt_linux_x86_r_s -L$(OPENH323DIR)/lib -lh323_linux_x86_r_s -L/usr/lib $(CHANH323LIB) clean: rm -f *.o *.so core.* libchanh323.a Index: codecs/gsm/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/codecs/gsm/Makefile,v retrieving revision 1.14 diff -u -r1.14 Makefile --- codecs/gsm/Makefile 13 Jun 2004 21:25:10 -0000 1.14 +++ codecs/gsm/Makefile 22 Jun 2004 16:12:47 -0000 @@ -64,8 +64,8 @@ # CC = /usr/lang/acc # CCFLAGS = -c -O -CC = gcc $(OPTIMIZE) -fomit-frame-pointer -CCFLAGS += -c -DNeedFunctionPrototypes=1 -funroll-loops -fPIC +CC ?= gcc +CCFLAGS += -c -DNeedFunctionPrototypes=1 -funroll-loops -fPIC $(OPTIMIZE) -fomit-frame-pointer LD = $(CC) @@ -150,7 +150,7 @@ DEBUG = -DNDEBUG ######### Remove -DNDEBUG to enable assertions. -CFLAGS = $(PG) $(CCFLAGS) $(SASR) $(DEBUG) $(MULHACK) $(FAST) \ +CFLAGS += $(PG) $(CCFLAGS) $(SASR) $(DEBUG) $(MULHACK) $(FAST) \ $(LTP_CUT) $(WAV49) $(K6OPT) $(CCINC) -I$(INC) ######### It's $(CC) $(CFLAGS) Index: codecs/lpc10/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/codecs/lpc10/Makefile,v retrieving revision 1.10 diff -u -r1.10 Makefile --- codecs/lpc10/Makefile 15 Mar 2004 16:51:58 -0000 1.10 +++ codecs/lpc10/Makefile 22 Jun 2004 16:12:47 -0000 @@ -3,7 +3,7 @@ # # default C compiler -CC= gcc +CC?= gcc # # These definitions for CFLAGS and LIB_TARGET_DIR are used when one @@ -22,11 +22,12 @@ # WARNINGS = -Wall -Wno-comment -Wno-error -CFLAGS = $(OPTIMIZE) -I$(LIB_TARGET_DIR) $(WARNINGS) -fPIC +CFLAGS += $(OPTIMIZE) -I$(LIB_TARGET_DIR) $(WARNINGS) -fPIC #CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi) #fix for PPC processors and ALPHA too ifneq ($(OSARCH),Darwin) +ifneq ($(findstring BSD,${OSARCH}),BSD) ifneq ($(PROC),ppc) ifneq ($(PROC),x86_64) ifneq ($(PROC),alpha) @@ -35,6 +36,7 @@ endif endif endif +endif LIB = $(LIB_TARGET_DIR)/liblpc10.a Index: include/asterisk/lock.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/lock.h,v retrieving revision 1.20 diff -u -r1.20 lock.h --- include/asterisk/lock.h 9 Jun 2004 13:49:42 -0000 1.20 +++ include/asterisk/lock.h 22 Jun 2004 16:12:48 -0000 @@ -16,6 +16,8 @@ #include #include +#include +#include #define AST_PTHREADT_NULL (pthread_t) -1 #define AST_PTHREADT_STOP (pthread_t) -2 @@ -28,13 +30,23 @@ 0x20 } } #endif -#ifdef __FreeBSD__ +#ifdef BSD #ifdef __GNUC__ #define AST_MUTEX_INIT_W_CONSTRUCTORS #else #define AST_MUTEX_INIT_ON_FIRST_USE #endif -#endif /* __FreeBSD__ */ +#endif /* BSD */ + +/* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes + and will not run without them. */ +#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP +#else +#define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER +#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE +#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ #ifdef DEBUG_THREADS @@ -47,15 +59,7 @@ #include #include -/* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes - and will not run without them. */ -#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -#define AST_MUTEX_INIT_VAULE { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, NULL, 0, NULL, 0 } -#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP -#else -#define AST_MUTEX_INIT_VAULE { PTHREAD_MUTEX_INITIALIZER, NULL, 0, NULL, 0 } -#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE -#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ +#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, NULL, 0 } struct ast_mutex_info { pthread_mutex_t mutex; @@ -67,28 +71,88 @@ typedef struct ast_mutex_info ast_mutex_t; -static inline int ast_pthread_mutex_init(ast_mutex_t *t, pthread_mutexattr_t *attr) +static inline int __ast_pthread_mutex_init_attr(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t, + pthread_mutexattr_t *attr) { - t->file = NULL; - t->lineno = 0; - t->func = 0; +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + if((t->mutex) != ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) { + fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is already initialized.\n", + filename, lineno, func, mutex_name); + fprintf(stderr, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n", + t->file, t->lineno, t->func, mutex_name); +#ifdef THREAD_CRASH + DO_THREAD_CRASH; +#endif + return 0; + } +#endif + t->file = filename; + t->lineno = lineno; + t->func = func; t->thread = 0; return pthread_mutex_init(&t->mutex, attr); } -static inline int ast_mutex_init(ast_mutex_t *t) +static inline int __ast_pthread_mutex_init(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t) { static pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, AST_MUTEX_KIND); - return ast_pthread_mutex_init(t, &attr); + return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr); } +#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex) +#define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr) + +static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t) +{ + int res; +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) { + fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n", + filename, lineno, func, mutex_name); + } +#endif + res = pthread_mutex_trylock(&t->mutex); + switch( res ) { + case 0: + pthread_mutex_unlock(&t->mutex); + break; + case EINVAL: + fprintf(stderr, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n", + filename, lineno, func, mutex_name); + break; + case EBUSY: + fprintf(stderr, "%s line %d (%s): Error: attemp to destroy locked mutex '%s'.\n", + filename, lineno, func, mutex_name); + fprintf(stderr, "%s line %d (%s): Error: '%s' was locked here.\n", + t->file, t->lineno, t->func, mutex_name); + break; + } + res = pthread_mutex_destroy(&t->mutex); + if (res) + fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n", + filename, lineno, func, strerror(res)); +#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + else + t->mutex = PTHREAD_MUTEX_INIT_VALUE; +#endif + t->file = filename; + t->lineno = lineno; + t->func = func; + return res; +} + +#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) + #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope - constrictors/destructors to create/destroy mutexes. */ + constrictors/destructors to create/destroy mutexes. */ #define __AST_MUTEX_DEFINE(scope,mutex) \ - scope ast_mutex_t mutex = AST_MUTEX_INIT_VAULE; \ + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \ static void __attribute__ ((constructor)) init_##mutex(void) \ { \ ast_mutex_init(&mutex); \ @@ -97,24 +161,54 @@ { \ ast_mutex_destroy(&mutex); \ } -#elif defined(AST_MUTEX_INIT_ON_FIRST_USE) || !defined(AST_MUTEX_INIT_W_CONSTRUCTORS) +#elif defined(AST_MUTEX_INIT_ON_FIRST_USE) /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on first use. The performance impact on FreeBSD should be small since the pthreads library does this itself to initialize errror checking (defaulty type) mutexes. If nither is defined, the pthreads librariy does the initialization itself on first use. */ #define __AST_MUTEX_DEFINE(scope,mutex) \ - scope ast_mutex_t mutex = AST_MUTEX_INIT_VAULE + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE +#else /* AST_MUTEX_INIT_W_CONSTRUCTORS */ +/* By default, use static initialization of mutexes.*/ +#define __AST_MUTEX_DEFINE(scope,mutex) \ + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ -static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, ast_mutex_t *t) + + +static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t) { int res; -#ifdef AST_MUTEX_INIT_ON_FIRST_USE - if(*t->mutex == (ast_mutex_t)AST_MUTEX_KIND) - ast_mutex_init(t->mutex); +#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) + if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) { +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n", + filename, lineno, func, mutex_name); #endif - res = pthread_mutex_lock(&t->mutex); + ast_mutex_init(t); + } +#endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */ +#ifdef DETECT_DEADLOCKS + { + time_t seconds seconds = time(NULL); + do { + res = pthread_mutex_trylock(&t->mutex); + if(res == EBUSY) { + if((time(NULL) - seconds) % 5) { + fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", + filename, lineno, func, (time(NULL) - seconds), mutex_name); + fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n", + t->file, t->lineno, t->func, mutex_name); + } + usleep(200); + } + } while (res == EBUSY); + } +#else + res = pthread_mutex_lock(&t->mutex); +#endif /* DETECT_DEADLOCKS */ if (!res) { t->file = filename; t->lineno = lineno; @@ -130,14 +224,21 @@ return res; } -#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a) +#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) -static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func, ast_mutex_t *t) { +static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t) +{ int res; -#ifdef AST_MUTEX_INIT_ON_FIRST_USE - if(*t->mutex == (ast_mutex_t)AST_MUTEX_KIND) - ast_mutex_init(t->mutex); +#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) + if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) { +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n", + filename, lineno, func, mutex_name); #endif + ast_mutex_init(t); + } +#endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */ res = pthread_mutex_trylock(&t->mutex); if (!res) { t->file = filename; @@ -148,10 +249,17 @@ return res; } -#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a) +#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) -static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, ast_mutex_t *t) { +static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func, + char* mutex_name, ast_mutex_t *t) { int res; +#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS + if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) { + fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n", + filename, lineno, func, mutex_name); + } +#endif /* Assumes lock is actually held */ t->file = NULL; t->lineno = 0; @@ -168,23 +276,7 @@ return res; } -#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a) - -static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func, ast_mutex_t *t) -{ - int res; - t->file = NULL; - t->lineno = 0; - t->func = NULL; - t->thread = 0; - res = pthread_mutex_destroy(&t->mutex); - if (res) - fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n", - filename, lineno, func, strerror(res)); - return res; -} - -#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, a) +#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a) #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock @@ -195,15 +287,9 @@ #else /* DEBUG_THREADS */ -/* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes - and will not run without them. */ -#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -#define AST_MUTEX_INIT_VAULE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP -#else -#define AST_MUTEX_INIT_VAULE PTHREAD_MUTEX_INITIALIZER -#define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE -#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ + +#define AST_MUTEX_INIT_VALUE PTHREAD_MUTEX_INIT_VALUE + typedef pthread_mutex_t ast_mutex_t; @@ -222,7 +308,7 @@ /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constrictors/destructors to create/destroy mutexes. */ #define __AST_MUTEX_DEFINE(scope,mutex) \ - scope ast_mutex_t mutex = AST_MUTEX_INIT_VAULE; \ + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \ static void __attribute__ ((constructor)) init_##mutex(void) \ { \ ast_mutex_init(&mutex); \ @@ -241,7 +327,7 @@ the pthreads library does this itself to initialize errror checking (defaulty type) mutexes.*/ #define __AST_MUTEX_DEFINE(scope,mutex) \ - scope ast_mutex_t mutex = AST_MUTEX_INIT_VAULE + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE static inline int ast_mutex_lock(ast_mutex_t *pmutex) { @@ -258,7 +344,7 @@ #else /* By default, use static initialization of mutexes.*/ #define __AST_MUTEX_DEFINE(scope,mutex) \ - scope ast_mutex_t mutex = AST_MUTEX_INIT_VAULE + scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex) #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex) #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ @@ -270,6 +356,7 @@ #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__ + #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__ #endif Index: include/asterisk/utils.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/utils.h,v retrieving revision 1.2 diff -u -r1.2 utils.h --- include/asterisk/utils.h 9 May 2004 08:22:15 -0000 1.2 +++ include/asterisk/utils.h 22 Jun 2004 16:12:48 -0000 @@ -26,4 +26,6 @@ extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp); +extern int test_for_thread_safety(void); + #endif