Really clean up indications to use the linkedlists API
authorJoshua Colp <jcolp@digium.com>
Thu, 21 Dec 2006 04:05:21 +0000 (04:05 +0000)
committerJoshua Colp <jcolp@digium.com>
Thu, 21 Dec 2006 04:05:21 +0000 (04:05 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48709 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/indications.h
main/indications.c

index a6c1d7c..7256181 100644 (file)
@@ -46,7 +46,7 @@ struct tone_zone_sound {
 };
 
 struct tone_zone {
-       struct tone_zone* next;                         /* next in list */
+       AST_RWLIST_ENTRY(tone_zone) list;
        char country[5];                                /* Country code */
        char alias[5];                                  /* is this an alias? */
        char description[40];                           /* Description */
index 359a590..f51b4ab 100644 (file)
@@ -37,12 +37,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <string.h>
 #include <math.h>
 
+#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"
 #include "asterisk/frame.h"
 #include "asterisk/options.h"
 #include "asterisk/channel.h"
 #include "asterisk/logger.h"
-#include "asterisk/lock.h"
 #include "asterisk/utils.h"
 
 static int midi_tohz[128] = {
@@ -103,20 +104,25 @@ struct playtones_state {
 static void playtones_release(struct ast_channel *chan, void *params)
 {
        struct playtones_state *ps = params;
-       if (chan) {
+
+       if (chan)
                ast_set_write_format(chan, ps->origwfmt);
-       }
-       if (ps->items) free(ps->items);
+       if (ps->items)
+               free(ps->items);
+
        free(ps);
 }
 
 static void * playtones_alloc(struct ast_channel *chan, void *params)
 {
        struct playtones_def *pd = params;
-       struct playtones_state *ps;
+       struct playtones_state *ps = NULL;
+
        if (!(ps = ast_calloc(1, sizeof(*ps))))
                return NULL;
+
        ps->origwfmt = chan->writeformat;
+
        if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
                ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
                playtones_release(NULL, ps);
@@ -128,11 +134,13 @@ static void * playtones_alloc(struct ast_channel *chan, void *params)
                ps->items = pd->items;
                ps->oldnpos = -1;
        }
+
        /* Let interrupts interrupt :) */
        if (pd->interruptible)
                ast_set_flag(chan, AST_FLAG_WRITE_INT);
        else
                ast_clear_flag(chan, AST_FLAG_WRITE_INT);
+
        return ps;
 }
 
@@ -329,103 +337,113 @@ void ast_playtones_stop(struct ast_channel *chan)
 
 /*--------------------------------------------*/
 
-static struct tone_zone *tone_zones;
+static AST_RWLIST_HEAD_STATIC(tone_zones, tone_zone);
 static struct tone_zone *current_tonezone;
 
-/* Protect the tone_zones list (highly unlikely that two things would change
- * it at the same time, but still! */
-AST_MUTEX_DEFINE_STATIC(tzlock);
-
 struct tone_zone *ast_walk_indications(const struct tone_zone *cur)
 {
-       struct tone_zone *tz;
+       struct tone_zone *tz = NULL;
+
+       AST_RWLIST_RDLOCK(&tone_zones);
+       /* If cur is not NULL, then we have to iterate through - otherwise just return the first entry */
+       if (cur) {
+               AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
+                       if (tz == cur)
+                               break;
+               }
+               tz = AST_RWLIST_NEXT(tz, list);
+       } else {
+               tz = AST_RWLIST_FIRST(&tone_zones);
+       }
+       AST_RWLIST_UNLOCK(&tone_zones);
 
-       if (cur == NULL)
-               return tone_zones;
-       ast_mutex_lock(&tzlock);
-       for (tz = tone_zones; tz; tz = tz->next)
-               if (tz == cur)
-                       break;
-       if (tz)
-               tz = tz->next;
-       ast_mutex_unlock(&tzlock);
        return tz;
 }
 
 /* Set global indication country */
 int ast_set_indication_country(const char *country)
 {
-       if (country) {
-               struct tone_zone *z = ast_get_indication_zone(country);
-               if (z) {
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n",country);
-                       current_tonezone = z;
-                       return 0;
-               }
-       }
-       return 1; /* not found */
+       struct tone_zone *zone = NULL;
+
+       /* If no country is specified or we are unable to find the zone, then return not found */
+       if (!country || !(zone = ast_get_indication_zone(country)))
+               return 1;
+       
+       if (option_verbose > 2)
+               ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n", country);
+
+       /* Protect the current tonezone using the tone_zones lock as well */
+       AST_RWLIST_WRLOCK(&tone_zones);
+       current_tonezone = zone;
+       AST_RWLIST_UNLOCK(&tone_zones);
+
+       /* Zone was found */
+       return 0;
 }
 
 /* locate tone_zone, given the country. if country == NULL, use the default country */
 struct tone_zone *ast_get_indication_zone(const char *country)
 {
-       struct tone_zone *tz;
+       struct tone_zone *tz = NULL;
        int alias_loop = 0;
 
-       /* we need some tonezone, pick the first */
-       if (country == NULL && current_tonezone)
-               return current_tonezone;        /* default country? */
-       if (country == NULL && tone_zones)
-               return tone_zones;              /* any country? */
-       if (country == NULL)
-               return 0;       /* not a single country insight */
-
-       ast_mutex_lock(&tzlock);
-       do {
-               for (tz=tone_zones; tz; tz=tz->next) {
-                       if (strcasecmp(country,tz->country)==0) {
-                               /* tone_zone found */
-                               if (tz->alias && tz->alias[0]) {
-                                       country = tz->alias;
+       AST_RWLIST_RDLOCK(&tone_zones);
+
+       if (!country) {
+               if (current_tonezone)
+                       tz = current_tonezone;
+               else
+                       tz = AST_LIST_FIRST(&tone_zones);
+       } else {
+               do {
+                       AST_RWLIST_TRAVERSE(&tone_zones, tz, list) {
+                               if (!strcasecmp(tz->country, country))
                                        break;
-                               }
-                               ast_mutex_unlock(&tzlock);
-                               return tz;
                        }
-               }
-       } while (++alias_loop<20 && tz);
-       ast_mutex_unlock(&tzlock);
-       if (alias_loop==20)
-               ast_log(LOG_NOTICE,"Alias loop for '%s' forcefull broken\n",country);
-       /* nothing found, sorry */
-       return 0;
+                       /* If this is an alias then we have to search yet again otherwise we have found the zonezone */
+                       if (tz->alias && tz->alias[0])
+                               country = tz->alias;
+                       else
+                               break;
+               } while ((++alias_loop < 20) && tz);
+       }
+
+       AST_RWLIST_UNLOCK(&tone_zones);
+
+       /* If we reached the maximum loops to find the proper country via alias, print out a notice */
+       if (alias_loop == 20)
+               ast_log(LOG_NOTICE, "Alias loop for '%s' is bonkers\n", country);
+
+       return tz;
 }
 
 /* locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
 struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
 {
-       struct tone_zone_sound *ts;
-
-       /* we need some tonezone, pick the first */
-       if (zone == NULL && current_tonezone)
-               zone = current_tonezone;        /* default country? */
-       if (zone == NULL && tone_zones)
-               zone = tone_zones;              /* any country? */
-       if (zone == NULL)
-               return 0;       /* not a single country insight */
-
-       ast_mutex_lock(&tzlock);
-       for (ts=zone->tones; ts; ts=ts->next) {
-               if (strcasecmp(indication,ts->name)==0) {
-                       /* found indication! */
-                       ast_mutex_unlock(&tzlock);
-                       return ts;
+       struct tone_zone_sound *ts = NULL;
+
+       AST_RWLIST_RDLOCK(&tone_zones);
+
+       /* If no zone is already specified we need to try to pick one */
+       if (!zone) {
+               if (current_tonezone) {
+                       zone = current_tonezone;
+               } else if (!(zone = AST_LIST_FIRST(&tone_zones))) {
+                       /* No zone has been found ;( */
+                       AST_RWLIST_UNLOCK(&tone_zones);
+                       return NULL;
                }
        }
-       /* nothing found, sorry */
-       ast_mutex_unlock(&tzlock);
-       return 0;
+
+       /* Look through list of tones in the zone searching for the right one */
+       for (ts = zone->tones; ts; ts = ts->next) {
+               if (!strcasecmp(ts->name, indication))
+                       break;
+       }
+
+       AST_RWLIST_UNLOCK(&tone_zones);
+
+       return ts;
 }
 
 /* helper function to delete a tone_zone in its entirety */
@@ -438,8 +456,10 @@ static inline void free_zone(struct tone_zone* zone)
                free(zone->tones);
                zone->tones = tmp;
        }
+
        if (zone->ringcadence)
                free(zone->ringcadence);
+
        free(zone);
 }
 
@@ -448,36 +468,33 @@ static inline void free_zone(struct tone_zone* zone)
 /* add a new country, if country exists, it will be replaced. */
 int ast_register_indication_country(struct tone_zone *zone)
 {
-       struct tone_zone *tz,*pz;
-
-       ast_mutex_lock(&tzlock);
-       for (pz=NULL,tz=tone_zones; tz; pz=tz,tz=tz->next) {
-               if (strcasecmp(zone->country,tz->country)==0) {
-                       /* tone_zone already there, replace */
-                       zone->next = tz->next;
-                       if (pz)
-                               pz->next = zone;
-                       else
-                               tone_zones = zone;
-                       /* if we are replacing the default zone, re-point it */
-                       if (tz == current_tonezone)
-                               current_tonezone = zone;
-                       /* now free the previous zone */
-                       free_zone(tz);
-                       ast_mutex_unlock(&tzlock);
-                       return 0;
-               }
+       struct tone_zone *tz = NULL;
+
+       AST_RWLIST_WRLOCK(&tone_zones);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
+               /* If this is not the same zone, then just continue to the next entry */
+               if (strcasecmp(zone->country, tz->country))
+                       continue;
+               /* If this zone we are going to remove is the current default then make the new zone the default */
+               if (tz == current_tonezone)
+                       current_tonezone = zone;
+               /* Remove from the linked list */
+               AST_RWLIST_REMOVE_CURRENT(&tone_zones, list);
+               /* Finally free the zone itself */
+               free_zone(tz);
+               break;
        }
-       /* country not there, add */
-       zone->next = NULL;
-       if (pz)
-               pz->next = zone;
-       else
-               tone_zones = zone;
-       ast_mutex_unlock(&tzlock);
+       AST_RWLIST_TRAVERSE_SAFE_END
+
+       /* Add zone to the list */
+       AST_RWLIST_INSERT_TAIL(&tone_zones, zone, list);
+
+       /* It's all over. */
+       AST_RWLIST_UNLOCK(&tone_zones);
 
        if (option_verbose > 2)
-               ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n",zone->country);
+               ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n", zone->country);
+
        return 0;
 }
 
@@ -485,41 +502,28 @@ int ast_register_indication_country(struct tone_zone *zone)
  * Also, all countries which are an alias for the specified country are removed. */
 int ast_unregister_indication_country(const char *country)
 {
-       struct tone_zone *tz, *pz = NULL, *tmp;
+       struct tone_zone *tz = NULL;
        int res = -1;
 
-       ast_mutex_lock(&tzlock);
-       tz = tone_zones;
-       while (tz) {
-               if (country==NULL ||
-                   (strcasecmp(country, tz->country)==0 ||
-                    strcasecmp(country, tz->alias)==0)) {
-                       /* tone_zone found, remove */
-                       tmp = tz->next;
-                       if (pz)
-                               pz->next = tmp;
-                       else
-                               tone_zones = tmp;
-                       /* if we are unregistering the default country, w'll notice */
-                       if (tz == current_tonezone) {
-                               ast_log(LOG_NOTICE,"Removed default indication country '%s'\n",tz->country);
-                               current_tonezone = NULL;
-                       }
-                       if (option_verbose > 2)
-                               ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n",tz->country);
-                       free_zone(tz);
-                       if (tone_zones == tz)
-                               tone_zones = tmp;
-                       tz = tmp;
-                       res = 0;
-               }
-               else {
-                       /* next zone please */
-                       pz = tz;
-                       tz = tz->next;
+       AST_RWLIST_WRLOCK(&tone_zones);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&tone_zones, tz, list) {
+               if (country && (strcasecmp(country, tz->country) && strcasecmp(country, tz->alias)))
+                       continue;
+               /* If this tonezone is the current default then unset it */
+               if (tz == current_tonezone) {
+                       ast_log(LOG_NOTICE,"Removed default indication country '%s'\n", tz->country);
+                       current_tonezone = NULL;
                }
+               /* Remove from the list */
+               AST_RWLIST_REMOVE_CURRENT(&tone_zones, list);
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n", tz->country);
+               free_zone(tz);
+               res = 0;
        }
-       ast_mutex_unlock(&tzlock);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&tone_zones);
+
        return res;
 }
 
@@ -527,13 +531,13 @@ int ast_unregister_indication_country(const char *country)
  * exists, it will be replaced. */
 int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist)
 {
-       struct tone_zone_sound *ts,*ps;
+       struct tone_zone_sound *ts, *ps;
 
        /* is it an alias? stop */
        if (zone->alias[0])
                return -1;
 
-       ast_mutex_lock(&tzlock);
+       AST_RWLIST_WRLOCK(&tone_zones);
        for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
                if (strcasecmp(indication,ts->name)==0) {
                        /* indication already there, replace */
@@ -545,20 +549,20 @@ int ast_register_indication(struct tone_zone *zone, const char *indication, cons
        if (!ts) {
                /* not there, we have to add */
                if (!(ts = ast_malloc(sizeof(*ts)))) {
-                       ast_mutex_unlock(&tzlock);
+                       AST_RWLIST_UNLOCK(&tone_zones);
                        return -2;
                }
                ts->next = NULL;
        }
        if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
-               ast_mutex_unlock(&tzlock);
+               AST_RWLIST_UNLOCK(&tone_zones);
                return -2;
        }
        if (ps)
                ps->next = ts;
        else
                zone->tones = ts;
-       ast_mutex_unlock(&tzlock);
+       AST_RWLIST_UNLOCK(&tone_zones);
        return 0;
 }
 
@@ -572,7 +576,7 @@ int ast_unregister_indication(struct tone_zone *zone, const char *indication)
        if (zone->alias[0])
                return -1;
 
-       ast_mutex_lock(&tzlock);
+       AST_RWLIST_WRLOCK(&tone_zones);
        ts = zone->tones;
        while (ts) {
                if (strcasecmp(indication,ts->name)==0) {
@@ -595,6 +599,6 @@ int ast_unregister_indication(struct tone_zone *zone, const char *indication)
                }
        }
        /* indication not found, goodbye */
-       ast_mutex_unlock(&tzlock);
+       AST_RWLIST_UNLOCK(&tone_zones);
        return res;
 }