store feature_pvt list using linked list macros
authorRussell Bryant <russell@russellbryant.com>
Wed, 25 Jan 2006 18:24:32 +0000 (18:24 +0000)
committerRussell Bryant <russell@russellbryant.com>
Wed, 25 Jan 2006 18:24:32 +0000 (18:24 +0000)
(issue #6351, with additional changes to prevent a memory leak in unload_module)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8665 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_features.c

index 3f7ac9f..dc2b70a 100644 (file)
@@ -71,9 +71,6 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 
 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
 
-/* Protect the interface list (of feature_pvt's) */
-AST_MUTEX_DEFINE_STATIC(featurelock);
-
 struct feature_sub {
        struct ast_channel *owner;
        int inthreeway;
@@ -82,15 +79,17 @@ struct feature_sub {
        int alertpipebackup[2];
 };
 
-static struct feature_pvt {
+struct feature_pvt {
        ast_mutex_t lock;                       /* Channel private lock */
        char tech[AST_MAX_EXTENSION];           /* Technology to abstract */
        char dest[AST_MAX_EXTENSION];           /* Destination to abstract */
        struct ast_channel *subchan;
        struct feature_sub subs[3];             /* Subs */
        struct ast_channel *owner;              /* Current Master Channel */
-       struct feature_pvt *next;               /* Next entity */
-} *features = NULL;
+       AST_LIST_ENTRY(feature_pvt) list;       /* Next entity */
+};
+
+static AST_LIST_HEAD_STATIC(features, feature_pvt);
 
 #define SUB_REAL       0                       /* Active call */
 #define SUB_CALLWAIT   1                       /* Call-Waiting call on hold */
@@ -366,7 +365,6 @@ static int features_call(struct ast_channel *ast, char *dest, int timeout)
 static int features_hangup(struct ast_channel *ast)
 {
        struct feature_pvt *p = ast->tech_pvt;
-       struct feature_pvt *cur, *prev=NULL;
        int x;
 
        ast_mutex_lock(&p->lock);
@@ -378,24 +376,12 @@ static int features_hangup(struct ast_channel *ast)
        }
        ast->tech_pvt = NULL;
        
-       
        if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
                ast_mutex_unlock(&p->lock);
                /* Remove from list */
-               ast_mutex_lock(&featurelock);
-               cur = features;
-               while(cur) {
-                       if (cur == p) {
-                               if (prev)
-                                       prev->next = cur->next;
-                               else
-                                       features = cur->next;
-                               break;
-                       }
-                       prev = cur;
-                       cur = cur->next;
-               }
-               ast_mutex_unlock(&featurelock);
+               AST_LIST_LOCK(&features);
+               AST_LIST_REMOVE(&features, p, list);
+               AST_LIST_UNLOCK(&features);
                ast_mutex_lock(&p->lock);
                /* And destroy */
                if (p->subchan)
@@ -431,14 +417,12 @@ static struct feature_pvt *features_alloc(char *data, int format)
                        data);
                return NULL;
        }
-       ast_mutex_lock(&featurelock);
-       tmp = features;
-       while(tmp) {
+       AST_LIST_LOCK(&features);
+       AST_LIST_TRAVERSE(&features, tmp, list) {
                if (!strcasecmp(tmp->tech, tech) && !strcmp(tmp->dest, dest))
                        break;
-               tmp = tmp->next;
        }
-       ast_mutex_unlock(&featurelock);
+       AST_LIST_UNLOCK(&features);
        if (!tmp) {
                chan = ast_request(tech, format, dest, &status);
                if (!chan) {
@@ -454,10 +438,9 @@ static struct feature_pvt *features_alloc(char *data, int format)
                        strncpy(tmp->tech, tech, sizeof(tmp->tech) - 1);
                        strncpy(tmp->dest, dest, sizeof(tmp->dest) - 1);
                        tmp->subchan = chan;
-                       ast_mutex_lock(&featurelock);
-                       tmp->next = features;
-                       features = tmp;
-                       ast_mutex_unlock(&featurelock);
+                       AST_LIST_LOCK(&features);
+                       AST_LIST_INSERT_HEAD(&features, tmp, list);
+                       AST_LIST_UNLOCK(&features);
                }
        }
        return tmp;
@@ -530,17 +513,19 @@ static int features_show(int fd, int argc, char **argv)
 
        if (argc != 3)
                return RESULT_SHOWUSAGE;
-       ast_mutex_lock(&featurelock);
-       p = features;
-       while(p) {
+
+       if (AST_LIST_EMPTY(&features)) {
+               ast_cli(fd, "No feature channels in use\n");
+               return RESULT_SUCCESS;
+       }
+
+       AST_LIST_LOCK(&features);
+       AST_LIST_TRAVERSE(&features, p, list) {
                ast_mutex_lock(&p->lock);
                ast_cli(fd, "%s -- %s/%s\n", p->owner ? p->owner->name : "<unowned>", p->tech, p->dest);
                ast_mutex_unlock(&p->lock);
-               p = p->next;
        }
-       if (!features)
-               ast_cli(fd, "No feature channels in use\n");
-       ast_mutex_unlock(&featurelock);
+       AST_LIST_UNLOCK(&features);
        return RESULT_SUCCESS;
 }
 
@@ -571,23 +556,23 @@ int reload()
 int unload_module()
 {
        struct feature_pvt *p;
+       
        /* First, take us out of the channel loop */
        ast_cli_unregister(&cli_show_features);
        ast_channel_unregister(&features_tech);
-       if (!ast_mutex_lock(&featurelock)) {
-               /* Hangup all interfaces if they have an owner */
-               p = features;
-               while(p) {
-                       if (p->owner)
-                               ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
-                       p = p->next;
-               }
-               features = NULL;
-               ast_mutex_unlock(&featurelock);
-       } else {
-               ast_log(LOG_WARNING, "Unable to lock the monitor\n");
+       
+       if (!AST_LIST_LOCK(&features))
                return -1;
-       }               
+       /* Hangup all interfaces if they have an owner */
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&features, p, list) {
+               if (p->owner)
+                       ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+               AST_LIST_REMOVE_CURRENT(&features, list);
+               free(p);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&features);
+       
        return 0;
 }