diff -Nru a/channels/chan_sip.c b/channels/chan_sip.c --- a/channels/chan_sip.c 2004-12-27 15:15:26 -07:00 +++ b/channels/chan_sip.c 2004-12-27 15:15:26 -07:00 @@ -1167,9 +1167,9 @@ struct sip_peer *p = NULL; if (peer) - ASTOBJ_CONTAINER_FIND(&peerl,p,peer); + p = ASTOBJ_CONTAINER_FIND(&peerl,peer); else - ASTOBJ_CONTAINER_FIND_FULL(&peerl,p,sin,name,sip_addr_hashfunc,1,sip_addrcmp); + p = ASTOBJ_CONTAINER_FIND_FULL(&peerl,sin,name,sip_addr_hashfunc,1,sip_addrcmp); if (!p) { p = realtime_peer(peer, sin); @@ -1236,7 +1236,7 @@ static struct sip_user *find_user(const char *name) { struct sip_user *u = NULL; - ASTOBJ_CONTAINER_FIND(&userl,u,name); + u = ASTOBJ_CONTAINER_FIND(&userl,name); if (!u) { u = realtime_user(name); } @@ -4078,14 +4078,17 @@ static int sip_reregister(void *data) { /* if we are here, we know that we need to reregister. */ - struct sip_registry *r=(struct sip_registry *)data; + struct sip_registry *r= ASTOBJ_REF((struct sip_registry *) data); + + /* if we couldn't get a reference to the registry object, punt */ + if (!r) + return 0; /* Since registry's are only added/removed by the the monitor thread, this may be overkill to reference/dereference at all here */ if (sipdebug) ast_log(LOG_NOTICE, " -- Re-registration for %s@%s\n", r->username, r->hostname); - ASTOBJ_REF(r); r->expire = -1; __sip_do_register(r); ASTOBJ_UNREF(r,sip_registry_destroy); @@ -4105,11 +4108,14 @@ { /* if we are here, our registration timed out, so we'll just do it over */ - struct sip_registry *r=data; + struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data); struct sip_pvt *p; int res; - ASTOBJ_REF(r); + /* if we couldn't get a reference to the registry object, punt */ + if (!r) + return 0; + ast_log(LOG_NOTICE, " -- Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); if (r->call) { /* Unlink us, destroy old call. Locking is not relevent here because all this happens @@ -4182,8 +4188,7 @@ p->sa.sin_port = htons(r->portno); ast_set_flag(p, SIP_OUTGOING); /* Registration is outgoing call */ r->call=p; /* Save pointer to SIP packet */ - p->registry=r; /* Add pointer to registry in packet */ - ASTOBJ_REF(p->registry); /* Reference registry to prevent it from disappearing */ + p->registry=ASTOBJ_REF(r); /* Add pointer to registry in packet */ if (!ast_strlen_zero(r->secret)) /* Secret (password) */ strncpy(p->peersecret, r->secret, sizeof(p->peersecret)-1); if (!ast_strlen_zero(r->md5secret)) @@ -5746,7 +5751,6 @@ static int sip_show_inuse(int fd, int argc, char *argv[]) { #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n" #define FORMAT2 "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n" - struct sip_user *user; char ilimits[40] = ""; char olimits[40] = ""; char iused[40]; @@ -5755,18 +5759,20 @@ if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT, "Username", "incoming", "Limit","outgoing","Limit"); - ASTOBJ_CONTAINER_TRAVERSE(&userl,user, do { - if (user->incominglimit) - snprintf(ilimits, sizeof(ilimits), "%d", user->incominglimit); + ASTOBJ_CONTAINER_TRAVERSE(&userl, do { + ASTOBJ_RDLOCK(iterator); + if (iterator->incominglimit) + snprintf(ilimits, sizeof(ilimits), "%d", iterator->incominglimit); else strncpy(ilimits, "N/A", sizeof(ilimits) - 1); - if (user->outgoinglimit) - snprintf(olimits, sizeof(olimits), "%d", user->outgoinglimit); + if (iterator->outgoinglimit) + snprintf(olimits, sizeof(olimits), "%d", iterator->outgoinglimit); else strncpy(olimits, "N/A", sizeof(olimits) - 1); - snprintf(iused, sizeof(iused), "%d", user->inUse); - snprintf(oused, sizeof(oused), "%d", user->outUse); - ast_cli(fd, FORMAT2, user->name, iused, ilimits,oused,olimits); + snprintf(iused, sizeof(iused), "%d", iterator->inUse); + snprintf(oused, sizeof(oused), "%d", iterator->outUse); + ast_cli(fd, FORMAT2, iterator->name, iused, ilimits,oused,olimits); + ASTOBJ_UNLOCK(iterator); } while (0) ); return RESULT_SUCCESS; #undef FORMAT @@ -5793,17 +5799,19 @@ static int sip_show_users(int fd, int argc, char *argv[]) { #define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-5.5s%-5.5s\n" - struct sip_user *user; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT, "Username", "Secret", "Accountcode", "Def.Context", "ACL", "NAT"); - ASTOBJ_CONTAINER_TRAVERSE(&userl,user, - ast_cli(fd, FORMAT, user->name, - user->secret, - user->accountcode, - user->context, - user->ha ? "Yes" : "No", - nat2str(user->nat)) + ASTOBJ_CONTAINER_TRAVERSE(&userl, do { + ASTOBJ_RDLOCK(iterator); + ast_cli(fd, FORMAT, iterator->name, + iterator->secret, + iterator->accountcode, + iterator->context, + iterator->ha ? "Yes" : "No", + nat2str(iterator->nat)); + ASTOBJ_UNLOCK(iterator); + } while (0) ); return RESULT_SUCCESS; #undef FORMAT @@ -5814,7 +5822,6 @@ { #define FORMAT2 "%-15.15s %-15.15s %s %s %s %-15.15s %-8s %-10s\n" #define FORMAT "%-15.15s %-15.15s %s %s %s %-15.15s %-8d %-10s\n" - struct sip_peer *peer; char name[256] = ""; char iabuf[INET_ADDRSTRLEN]; int total_peers = 0; @@ -5826,30 +5833,32 @@ return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT2, "Name/username", "Host", "Dyn", "Nat", "ACL", "Mask", "Port", "Status"); - ASTOBJ_CONTAINER_TRAVERSE(&peerl,peer, do { + ASTOBJ_CONTAINER_TRAVERSE(&peerl, do { char nm[20] = ""; char status[20] = ""; int print_line = -1; char srch[2000]; - ast_inet_ntoa(nm, sizeof(nm), peer->mask); - if (!ast_strlen_zero(peer->username)) - snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username); + ASTOBJ_RDLOCK(iterator); + + ast_inet_ntoa(nm, sizeof(nm), iterator->mask); + if (!ast_strlen_zero(iterator->username)) + snprintf(name, sizeof(name), "%s/%s", iterator->name, iterator->username); else - strncpy(name, peer->name, sizeof(name) - 1); - if (peer->maxms) { - if (peer->lastms < 0) { + strncpy(name, iterator->name, sizeof(name) - 1); + if (iterator->maxms) { + if (iterator->lastms < 0) { strncpy(status, "UNREACHABLE", sizeof(status) - 1); peers_offline++; - } else if (peer->lastms > peer->maxms) { - snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms); + } else if (iterator->lastms > iterator->maxms) { + snprintf(status, sizeof(status), "LAGGED (%d ms)", iterator->lastms); peers_online++; - } else if (peer->lastms) { - snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms); + } else if (iterator->lastms) { + snprintf(status, sizeof(status), "OK (%d ms)", iterator->lastms); peers_online++; } else { /* Checking if port is 0 */ - if ( ntohs(peer->addr.sin_port) == 0 ) { + if ( ntohs(iterator->addr.sin_port) == 0 ) { peers_offline++; } else { peers_online++; @@ -5859,7 +5868,7 @@ } else { strncpy(status, "Unmonitored", sizeof(status) - 1); /* Checking if port is 0 */ - if ( ntohs(peer->addr.sin_port) == 0 ) { + if ( ntohs(iterator->addr.sin_port) == 0 ) { peers_offline++; } else { peers_online++; @@ -5867,11 +5876,11 @@ } snprintf(srch, sizeof(srch), FORMAT, name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - ast_test_flag(peer, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ - (peer->nat & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ - peer->ha ? " A " : " ", /* permit/deny */ - nm, ntohs(peer->addr.sin_port), status); + iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", + ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ + (iterator->nat & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + iterator->ha ? " A " : " ", /* permit/deny */ + nm, ntohs(iterator->addr.sin_port), status); if (argc == 5) { if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) { @@ -5887,13 +5896,16 @@ if (print_line) { ast_cli(fd, FORMAT, name, - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - ast_test_flag(peer, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ - (peer->nat & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ - peer->ha ? " A " : " ", /* permit/deny */ + iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)", + ast_test_flag(iterator, SIP_DYNAMIC) ? " D " : " ", /* Dynamic or not? */ + (iterator->nat & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + iterator->ha ? " A " : " ", /* permit/deny */ nm, - ntohs(peer->addr.sin_port), status); + ntohs(iterator->addr.sin_port), status); } + + ASTOBJ_UNLOCK(iterator); + total_peers++; } while(0) ); ast_cli(fd,"%d sip peers loaded [%d online , %d offline]\n",total_peers,peers_online,peers_offline); @@ -5904,18 +5916,15 @@ static int sip_show_objects(int fd, int argc, char *argv[]) { - struct sip_user *user; - struct sip_peer *peer; - struct sip_registry *reg; char tmp[256]; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, "-= User objects: %d static, %d realtime =-\n\n", suserobjs, ruserobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &userl, user); + ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &userl); ast_cli(fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &peerl, peer); + ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), &peerl); ast_cli(fd, "-= Registry objects: %d =-\n\n", regobjs); - ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), ®l, reg); + ASTOBJ_CONTAINER_DUMP(fd, tmp, sizeof(tmp), ®l); return RESULT_SUCCESS; } /*--- print_group: Print call group and pickup group ---*/ @@ -6036,16 +6045,16 @@ { #define FORMAT2 "%-30.30s %-12.12s %8.8s %-20.20s\n" #define FORMAT "%-30.30s %-12.12s %8d %-20.20s\n" - struct sip_registry *reg; char host[80]; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT2, "Host", "Username", "Refresh", "State"); - ASTOBJ_CONTAINER_TRAVERSE(®l,reg, do { - snprintf(host, sizeof(host), "%s:%d", reg->hostname, reg->portno ? reg->portno : DEFAULT_SIP_PORT); - ast_cli(fd, FORMAT, host, - reg->username, reg->refresh, regstate2str(reg->regstate)); + ASTOBJ_CONTAINER_TRAVERSE(®l, do { + ASTOBJ_RDLOCK(iterator); + snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : DEFAULT_SIP_PORT); + ast_cli(fd, FORMAT, host, iterator->username, iterator->refresh, regstate2str(iterator->regstate)); + ASTOBJ_UNLOCK(iterator); } while(0)); return RESULT_SUCCESS; #undef FORMAT @@ -8094,18 +8103,20 @@ time(&t); fastrestart = 0; curpeernum = 0; - ASTOBJ_CONTAINER_TRAVERSE(&peerl,peer, - if ((curpeernum > lastpeernum) && !ast_strlen_zero(peer->mailbox) && ((t - peer->lastmsgcheck) > global_mwitime)) { + ASTOBJ_CONTAINER_TRAVERSE(&peerl, do { + if ((curpeernum > lastpeernum) && !ast_strlen_zero(iterator->mailbox) && ((t - iterator->lastmsgcheck) > global_mwitime)) { fastrestart = 1; lastpeernum = curpeernum; - ASTOBJ_REF(peer); - ast_mutex_unlock(&peer->lock); + peer = ASTOBJ_REF(iterator); break; - } - curpeernum++ + }; + curpeernum++; + } while (0) ); if (peer) { + ASTOBJ_WRLOCK(peer); sip_send_mwi_to_peer(peer); + ASTOBJ_UNLOCK(peer); ASTOBJ_UNREF(peer,sip_destroy_peer); } else { /* Reset where we come from */ @@ -8558,18 +8569,16 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int temponly) { struct sip_peer *peer; - struct sip_peer *prev; struct ast_ha *oldha = NULL; int maskfound=0; int obproxyfound=0; int found=0; - prev = NULL; if (temponly) { peer = NULL; } else { /* Note we do NOT use find_peer here, to avoid realtime recursion */ - ASTOBJ_CONTAINER_FIND_UNLINK(&peerl,peer,prev,name); + peer = ASTOBJ_CONTAINER_FIND_UNLINK(&peerl,name); } if (peer) { /* Already in the list, remove it and it will be added back (or FREE'd) */ @@ -9362,35 +9371,49 @@ /* Also, check registations with other SIP proxies */ static void delete_users(void) { - struct sip_user *user; - struct sip_peer *peer; - struct sip_registry *reg; - /* Delete all users */ - ASTOBJ_CONTAINER_DESTROYALL(&userl,user,sip_destroy_user); - ASTOBJ_CONTAINER_DESTROYALL(®l,reg,sip_registry_destroy); - ASTOBJ_CONTAINER_MARKALL(&peerl,peer); + ASTOBJ_CONTAINER_DESTROYALL(&userl,sip_destroy_user); + ASTOBJ_CONTAINER_DESTROYALL(®l,sip_registry_destroy); + ASTOBJ_CONTAINER_MARKALL(&peerl); } /*--- prune_peers: Delete all peers marked for deletion ---*/ static void prune_peers(void) { /* Prune peers who still are supposed to be deleted */ - struct sip_peer *peer, *peerlast, *peernext; - ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl,peerlast,peernext,peer,sip_destroy_peer); + ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl,sip_destroy_peer); +} + +/*--- sip_poke_all_peers: Send a poke to all known peers */ +static void sip_poke_all_peers(void) +{ + ASTOBJ_CONTAINER_TRAVERSE(&peerl, do { + ASTOBJ_WRLOCK(iterator); + sip_poke_peer(iterator); + ASTOBJ_UNLOCK(iterator); + } while (0) + ); +} + +/*--- sip_send_all_registers: Send all known registrations */ +static void sip_send_all_registers(void) +{ + ASTOBJ_CONTAINER_TRAVERSE(®l, do { + ASTOBJ_WRLOCK(iterator); + __sip_do_register(iterator); + ASTOBJ_UNLOCK(iterator); + } while (0) + ); } /*--- sip_do_reload: Reload module */ static int sip_do_reload(void) { - struct sip_registry *reg; - struct sip_peer *peer; delete_users(); reload_config(); prune_peers(); - /* And start the monitor for the first time */ - ASTOBJ_CONTAINER_TRAVERSE(®l,reg,__sip_do_register(reg)); - ASTOBJ_CONTAINER_TRAVERSE(&peerl,peer,sip_poke_peer(peer)); + sip_poke_all_peers(); + sip_send_all_registers(); return 0; } @@ -9421,8 +9444,6 @@ int load_module() { int res; - struct sip_peer *peer; - struct sip_registry *reg; ASTOBJ_CONTAINER_INIT(&userl); ASTOBJ_CONTAINER_INIT(&peerl); @@ -9469,8 +9490,8 @@ ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode); ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader); ast_register_application(app_sipgetheader, sip_getheader, synopsis_sipgetheader, descrip_sipgetheader); - ASTOBJ_CONTAINER_TRAVERSE(&peerl,peer,sip_poke_peer(peer)); - ASTOBJ_CONTAINER_TRAVERSE(®l,reg,__sip_do_register(reg)); + sip_poke_all_peers(); + sip_send_all_registers(); /* And start the monitor for the first time */ restart_monitor(); @@ -9557,9 +9578,9 @@ } /* Free memory for local network address mask */ ast_free_ha(localaddr); - ASTOBJ_CONTAINER_RELEASE(&userl); - ASTOBJ_CONTAINER_RELEASE(&peerl); - ASTOBJ_CONTAINER_RELEASE(®l); + ASTOBJ_CONTAINER_DESTROY(&userl); + ASTOBJ_CONTAINER_DESTROY(&peerl); + ASTOBJ_CONTAINER_DESTROY(®l); return 0; } diff -Nru a/include/asterisk/astobj.h b/include/asterisk/astobj.h --- a/include/asterisk/astobj.h 2004-12-27 15:15:26 -07:00 +++ b/include/asterisk/astobj.h 2004-12-27 15:15:26 -07:00 @@ -22,7 +22,6 @@ are used for maximum performance, to support multiple inheritance, and to be easily integrated into existing structures without additional malloc calls, etc. - */ #if defined(__cplusplus) || defined(c_plusplus) @@ -39,6 +38,10 @@ /* C++ is simply a syntactic crutch for those who cannot think for themselves in an object oriented way. */ +#define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock) +#define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock) +#define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock) + #ifdef ASTOBJ_CONTAINER_HASHMODEL #define __ASTOBJ_HASH(type,hashes) \ type *next[hashes] @@ -57,55 +60,66 @@ ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1) #define ASTOBJ_COMPONENTS(type) \ - ast_mutex_t lock; \ + ast_mutex_t _lock; \ ASTOBJ_COMPONENTS_NOLOCK(type) #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \ - ast_mutex_t lock; \ + ast_mutex_t _lock; \ ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) #define ASTOBJ_REF(object) \ - do { \ - ast_mutex_lock(&(object)->lock); \ - (object)->refcount++; \ - ast_mutex_unlock(&(object)->lock); \ - } while(0) + ({ \ + typeof(object) ref = NULL; \ + if (ASTOBJ_WRLOCK(object)) { \ + (object)->refcount++; \ + ASTOBJ_UNLOCK(object); \ + ref = object; \ + } \ + ref; \ + }) #define ASTOBJ_UNREF(object,destructor) \ do { \ - int destroyme; \ - ast_mutex_lock(&(object)->lock); \ - if ((object)->refcount > 0) \ + ASTOBJ_WRLOCK(object); \ + if (__builtin_expect((object)->refcount, 1)) \ (object)->refcount--; \ else \ ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \ - destroyme = (!(object)->refcount) && ((object)->objflags & ASTOBJ_FLAG_DELME); \ - ast_mutex_unlock(&(object)->lock); \ - if (destroyme) \ - destructor((object)); \ + ASTOBJ_UNLOCK(object); \ + ASTOBJ_DESTROY(object,destructor); \ } while(0) #define ASTOBJ_MARK(object) \ - (object)->objflags |= ASTOBJ_FLAG_MARKED; + do { \ + ASTOBJ_WRLOCK(object); \ + (object)->objflags |= ASTOBJ_FLAG_MARKED; \ + ASTOBJ_UNLOCK(object); \ + } while(0) #define ASTOBJ_UNMARK(object) \ - (object)->objflags &= ~ASTOBJ_FLAG_MARKED; + do { \ + ASTOBJ_WRLOCK(object); \ + (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \ + ASTOBJ_UNLOCK(object); \ + } while(0) #define ASTOBJ_DESTROY(object,destructor) \ do { \ - int destroyme; \ - ast_mutex_lock(&(object)->lock); \ - destroyme = (!(object)->refcount); \ - (object)->objflags |= ASTOBJ_FLAG_DELME; \ - ast_mutex_unlock(&(object)->lock); \ - if (destroyme) \ + if (__builtin_expect((object)->refcount, 1)) { \ + ASTOBJ_WRLOCK(object); \ + (object)->objflags |= ASTOBJ_FLAG_DELME; \ + ASTOBJ_UNLOCK(object); \ + } else { \ + ast_mutex_destroy(&(object)->_lock); \ destructor((object)); \ + } \ } while(0) #define ASTOBJ_INIT(object) \ do { \ - ast_mutex_init(&(object)->lock); \ + ast_mutex_init(&(object)->_lock); \ object->name[0] = '\0'; \ + object->refcount = 1; \ } while(0) /* Containers for objects -- current implementation is linked lists, but @@ -120,193 +134,145 @@ #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \ do { \ - ast_mutex_init(&(container)->lock); \ + ast_mutex_init(&(container)->_lock); \ } while(0) -#define ASTOBJ_CONTAINER_RELEASE_FULL(container,hashes,buckets) \ +#define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \ do { \ - ast_mutex_destroy(&(container)->lock); \ + ast_mutex_destroy(&(container)->_lock); \ } while(0) -#define ASTOBJ_CONTAINER_TRAVERSE(container,iterator,eval) \ +#define ASTOBJ_CONTAINER_TRAVERSE(container,eval) \ do { \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - while((iterator)) { \ - ast_mutex_lock(&(iterator)->lock); \ + typeof((container)->head) iterator; \ + typeof((container)->head) next; \ + ASTOBJ_RDLOCK(container); \ + next = (container)->head; \ + while((iterator = next)) { \ + next = iterator->next[0]; \ eval; \ - ast_mutex_unlock(&(iterator)->lock); \ - (iterator) = (iterator)->next[0]; \ } \ - ast_mutex_unlock(&(container)->lock); \ + ASTOBJ_UNLOCK(container); \ } while(0) -#define ASTOBJ_CONTAINER_FIND_FULL(container,iterator,data,field,hashfunc,hashoffset,comparefunc) \ - do { \ - int res; \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - while((iterator)) { \ - ast_mutex_lock(&(iterator)->lock); \ - res = (comparefunc((iterator)->field,(data))); \ - if (!res) \ - ASTOBJ_REF((iterator)); \ - ast_mutex_unlock(&(iterator)->lock); \ - if (!res) \ +#define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ + ({ \ + typeof((container)->head) found = NULL; \ + ASTOBJ_CONTAINER_TRAVERSE(container, do { \ + ASTOBJ_RDLOCK(iterator); \ + if (!(comparefunc(iterator->field, (data)))) { \ + found = ASTOBJ_REF(iterator); \ + } \ + ASTOBJ_UNLOCK(iterator); \ + if (found) \ break; \ - (iterator) = (iterator)->next[0]; \ - } \ - ast_mutex_unlock(&(container)->lock); \ - } while(0) - -#define ASTOBJ_CONTAINER_DESTROYALL(container,iterator,destructor) \ - do { \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - while((iterator)) { \ + } while (0)); \ + found; \ + }) + +#define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \ + do { \ + typeof((container)->head) iterator; \ + ASTOBJ_WRLOCK(container); \ + while((iterator = (container)->head)) { \ (container)->head = (iterator)->next[0]; \ ASTOBJ_DESTROY(iterator,destructor); \ - (iterator) = (container)->head; \ } \ - ast_mutex_unlock(&(container)->lock); \ + ASTOBJ_UNLOCK(container); \ } while(0) -#define ASTOBJ_CONTAINER_UNLINK_FULL(container,iterator,data,field,hashfunc,hashoffset,comparefunc) \ - do { \ - int res=-1; \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - if ((iterator)) { \ - ast_mutex_lock(&(iterator)->lock); \ - res = (comparefunc((iterator)->field,(data))); \ - if (!res && ((iterator)->refcount < 1)) \ - ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \ - ast_mutex_unlock(&(iterator)->lock); \ - if (!res) \ - (container)->head = (iterator)->next[0]; \ - else while((iterator)->next[0]) { \ - ast_mutex_lock(&(iterator)->next[0]->lock); \ - res = (comparefunc((iterator)->next[0]->field,(data))); \ - if (!res && ((iterator)->next[0]->refcount < 1)) \ - ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \ - ast_mutex_unlock(&(iterator)->next[0]->lock); \ - if (!res) { \ - (iterator)->next[0] = (iterator)->next[0]->next[0]; \ - break; \ - } \ - (iterator) = (iterator)->next[0]; \ - } \ - } \ - ast_mutex_unlock(&(container)->lock); \ - } while(0) - -#define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,reiterator,iterator,data,field,hashfunc,hashoffset,comparefunc) \ - do { \ - int res=-1; \ - (reiterator) = NULL; \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - if ((iterator)) { \ - ast_mutex_lock(&(iterator)->lock); \ - res = (comparefunc((iterator)->field,(data))); \ - if (!res && ((iterator)->refcount < 1)) \ - ast_log(LOG_WARNING, "Unlink called with refcount < 1!\n"); \ - ast_mutex_unlock(&(iterator)->lock); \ - if (!res) {\ - (reiterator) = (container)->head; \ - (container)->head = (iterator)->next[0]; \ - } else while((iterator)->next[0]) { \ - ast_mutex_lock(&(iterator)->next[0]->lock); \ - res = (comparefunc((iterator)->next[0]->field,(data))); \ - ast_mutex_unlock(&(iterator)->next[0]->lock); \ - if (!res) { \ - (reiterator) = (iterator)->next[0]; \ - (iterator)->next[0] = (iterator)->next[0]->next[0]; \ - break; \ - } \ - (iterator) = (iterator)->next[0]; \ +#define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ + ({ \ + typeof((container)->head) found = NULL; \ + typeof((container)->head) prev = NULL; \ + ASTOBJ_CONTAINER_TRAVERSE(container, do { \ + ASTOBJ_RDLOCK(iterator); \ + if (!(comparefunc(iterator->field, (data)))) { \ + found = iterator; \ + ASTOBJ_WRLOCK(container); \ + if (prev) \ + prev->next[0] = next; \ + else \ + (container)->head = next; \ + ASTOBJ_UNLOCK(container); \ + break; \ } \ - } \ - ast_mutex_unlock(&(container)->lock); \ - } while(0) - -#define ASTOBJ_CONTAINER_PRUNE_MARKED(container,previ,nexti,iterator,destructor) \ - do { \ - (previ) = NULL; \ - ast_mutex_lock(&((container)->lock)); \ - (iterator) = (container)->head; \ - while((iterator)) { \ - ast_mutex_lock(&(iterator)->lock); \ - (nexti) = (iterator)->next[0]; \ - if ((iterator)->objflags & ASTOBJ_FLAG_MARKED) { \ - if ((previ)) \ - (previ)->next[0] = (nexti); \ + ASTOBJ_UNLOCK(iterator); \ + if (found) \ + break; \ + prev = iterator; \ + } while (0)); \ + found; \ + }) + +#define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \ + do { \ + typeof((container)->head) prev = NULL; \ + ASTOBJ_CONTAINER_TRAVERSE(container, do { \ + ASTOBJ_RDLOCK(iterator); \ + if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \ + ASTOBJ_WRLOCK(container); \ + if (prev) \ + prev->next[0] = next; \ else \ - (container)->head = (nexti); \ - ast_mutex_unlock(&(iterator)->lock); \ + (container)->head = next; \ + ASTOBJ_UNLOCK(container); \ + ASTOBJ_UNLOCK(iterator); \ ASTOBJ_DESTROY(iterator,destructor); \ - } else { \ - (previ) = (iterator); \ - ast_mutex_unlock(&(iterator)->lock); \ + continue; \ } \ - (iterator) = (nexti); \ - } \ - ast_mutex_unlock(&(container)->lock); \ + ASTOBJ_UNLOCK(iterator); \ + prev = iterator; \ + } while (0)); \ } while(0) #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \ do { \ - ASTOBJ_REF(newobj); \ - ast_mutex_lock(&(container)->lock); \ + ASTOBJ_WRLOCK(container); \ (newobj)->next[0] = (container)->head; \ (container)->head = (newobj); \ - ast_mutex_unlock(&(container)->lock); \ + ASTOBJ_UNLOCK(container); \ } while(0) -#endif /* Hash model */ +#endif /* List model */ /* Common to hash and linked list models */ #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \ ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS) #define ASTOBJ_CONTAINER_COMPONENTS(type) \ - ast_mutex_t lock; \ + ast_mutex_t _lock; \ ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) #define ASTOBJ_CONTAINER_INIT(container) \ ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) -#define ASTOBJ_CONTAINER_RELEASE(container) \ - ASTOBJ_CONTAINER_RELEASE_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) - -#define ASTOBJ_CONTAINER_FIND(container,iterator,namestr) \ - ASTOBJ_CONTAINER_FIND_FULL(container,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) +#define ASTOBJ_CONTAINER_DESTROY(container) \ + ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) -#define ASTOBJ_CONTAINER_FIND_UNLINK(container,reiterator,iterator,namestr) \ - ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,reiterator,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) +#define ASTOBJ_CONTAINER_FIND(container,namestr) \ + ASTOBJ_CONTAINER_FIND_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) -#define ASTOBJ_CONTAINER_UNLINK(container,iterator,namestr) \ - ASTOBJ_CONTAINER_UNLINK_FULL(container,iterator,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) +#define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \ + ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,namestr,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) #define ASTOBJ_CONTAINER_LINK(container,newobj) \ ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) -#define ASTOBJ_CONTAINER_MARKALL(container,iterator) \ - ASTOBJ_CONTAINER_TRAVERSE(container,iterator,(iterator)->objflags |= ASTOBJ_FLAG_MARKED) +#define ASTOBJ_CONTAINER_MARKALL(container) \ + ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_MARK(iterator)) -#define ASTOBJ_CONTAINER_UNMARKALL(container,iterator) \ - ASTOBJ_CONTAINER_TRAVERSE(container,iterator,(iterator)->objflags &= ~ASTOBJ_FLAG_MARKED) +#define ASTOBJ_CONTAINER_UNMARKALL(container) \ + ASTOBJ_CONTAINER_TRAVERSE(container,ASTOBJ_UNMARK(iterator)) #define ASTOBJ_DUMP(s,slen,obj) \ snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount); -#define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container,iterator) \ - ASTOBJ_CONTAINER_TRAVERSE(container,iterator,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0)) +#define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \ + ASTOBJ_CONTAINER_TRAVERSE(container,do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0)) #if defined(__cplusplus) || defined(c_plusplus) } #endif - - #endif