[asterisk-commits] russell: branch russell/ast_channel_refcount r82293 - in /team/russell/ast_ch...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Sep 12 16:44:44 CDT 2007


Author: russell
Date: Wed Sep 12 16:44:44 2007
New Revision: 82293

URL: http://svn.digium.com/view/asterisk?view=rev&rev=82293
Log:
Add some functions which can be used in place of all of the functions that used
channel_find_locked() internally.  That would be any of the channel_find_locked
or channel_walk_locked family of functions.

I haven't documented any of these yet, but the performance should be _significantly_
better.  Also, none of these functions return the channel locked.  They simply
return a reference, and the caller must lock it if needed.

Modified:
    team/russell/ast_channel_refcount/include/asterisk/channel.h
    team/russell/ast_channel_refcount/main/channel.c

Modified: team/russell/ast_channel_refcount/include/asterisk/channel.h
URL: http://svn.digium.com/view/asterisk/team/russell/ast_channel_refcount/include/asterisk/channel.h?view=diff&rev=82293&r1=82292&r2=82293
==============================================================================
--- team/russell/ast_channel_refcount/include/asterisk/channel.h (original)
+++ team/russell/ast_channel_refcount/include/asterisk/channel.h Wed Sep 12 16:44:44 2007
@@ -117,7 +117,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/compiler.h"
-
+#include "asterisk/astobj2.h"
 
 #define AST_MAX_FDS		8
 /*
@@ -624,8 +624,12 @@
 /*! \brief Change channel name */
 void ast_change_name(struct ast_channel *chan, char *newname);
 
-/*! \brief Free a channel structure */
-void  ast_channel_free(struct ast_channel *);
+/*! 
+ * \brief Free a channel structure 
+ *
+ * \return NULL, useful to clear invalid pointers
+ */ 
+struct ast_channel *ast_channel_free(struct ast_channel *);
 
 /*! \brief Requests a channel 
  * \param type type of channel to request
@@ -1367,8 +1371,6 @@
  */
 void ast_channel_whisper_stop(struct ast_channel *chan);
 
-
-
 /*!
   \brief return an english explanation of the code returned thru __ast_request_and_dial's 'outstate' argument
   \param reason  The integer argument, usually taken from AST_CONTROL_ macros
@@ -1380,6 +1382,24 @@
 #define ast_channel_unlock(c) ao2_unlock(c)
 #define ast_channel_trylock(c) ao2_trylock(c)
 
+struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i);
+
+struct ast_channel_iterator *ast_channel_iterator_byexten_new(const char *exten, 
+	const char *context);
+
+struct ast_channel_iterator *ast_channel_iterator_byname_new(const char *name, 
+	size_t name_len);
+
+struct ast_channel_iterator *ast_channel_iterator_all_new(void);
+
+struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i);
+
+struct ast_channel *ast_channel_get_byname(const char *name);
+
+struct ast_channel *ast_channel_get_byname_prefix(const char *name, size_t name_len);
+
+struct ast_channel *ast_channel_get_byexten(const char *exten, const char *context);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/russell/ast_channel_refcount/main/channel.c
URL: http://svn.digium.com/view/asterisk/team/russell/ast_channel_refcount/main/channel.c?view=diff&rev=82293&r1=82292&r2=82293
==============================================================================
--- team/russell/ast_channel_refcount/main/channel.c (original)
+++ team/russell/ast_channel_refcount/main/channel.c Wed Sep 12 16:44:44 2007
@@ -69,6 +69,7 @@
 #include "asterisk/sha1.h"
 #include "asterisk/threadstorage.h"
 #include "asterisk/slinfactory.h"
+#include "asterisk/astobj2.h"
 
 struct channel_spy_trans {
 	int last_format;
@@ -128,7 +129,7 @@
 #else
 #define MAX_CHANNEL_BUCKETS 1567
 #endif
-static ao2_container *channels;
+static struct ao2_container *channels;
 
 /*! map AST_CAUSE's to readable string representations */
 const struct ast_cause {
@@ -441,11 +442,11 @@
 	return b2;
 }
 
-static ast_channel_softhangup_cb(void *obj, void *arg, int flags)
+static int ast_channel_softhangup_cb(void *obj, void *arg, int flags)
 {
 	struct ast_channel *chan = obj;
 
-	ast_softhangup(chan);
+	ast_softhangup(chan, AST_SOFTHANGUP_SHUTDOWN);
 
 	return 0;
 }
@@ -453,8 +454,8 @@
 /*! \brief Initiate system shutdown */
 void ast_begin_shutdown(int hangup)
 {
-	struct ast_channel *c;
 	shutting_down = 1;
+
 	if (hangup)
 		ao2_callback(channels, OBJ_NODATA, ast_channel_softhangup_cb, NULL);
 }
@@ -726,6 +727,94 @@
 	return NULL;
 }
 
+static void free_cid(struct ast_callerid *cid)
+{
+	if (cid->cid_dnid)
+		free(cid->cid_dnid);
+	if (cid->cid_num)
+		free(cid->cid_num);	
+	if (cid->cid_name)
+		free(cid->cid_name);	
+	if (cid->cid_ani)
+		free(cid->cid_ani);
+	if (cid->cid_rdnis)
+		free(cid->cid_rdnis);
+}
+
+static void ast_channel_destructor(void *data)
+{
+	struct ast_channel *chan = data;
+	int fd;
+	struct ast_var_t *vardata;
+	struct ast_frame *f;
+	struct varshead *headp;
+	struct ast_datastore *datastore = NULL;
+	char name[AST_CHANNEL_NAME];
+	
+	headp = &chan->varshead;
+	
+	if (chan->tech_pvt) {
+		ast_log(LOG_ERROR, "Channel '%s' may not have been hung up properly\n", chan->name);
+		free(chan->tech_pvt);
+	}
+
+	if (chan->sched)
+		sched_context_destroy(chan->sched);
+
+	ast_copy_string(name, chan->name, sizeof(name));
+
+	/* Stop monitoring */
+	if (chan->monitor)
+		chan->monitor->stop( chan, 0 );
+
+	/* If there is native format music-on-hold state, free it */
+	if (chan->music_state)
+		ast_moh_cleanup(chan);
+
+	/* if someone is whispering on the channel, stop them */
+	if (chan->whisper)
+		ast_channel_whisper_stop(chan);
+
+	/* Free translators */
+	if (chan->readtrans)
+		ast_translator_free_path(chan->readtrans);
+	if (chan->writetrans)
+		ast_translator_free_path(chan->writetrans);
+	if (chan->pbx)
+		ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
+	free_cid(&chan->cid);
+	ast_mutex_destroy(&chan->lock);
+	/* Close pipes if appropriate */
+	if ((fd = chan->alertpipe[0]) > -1)
+		close(fd);
+	if ((fd = chan->alertpipe[1]) > -1)
+		close(fd);
+	if ((fd = chan->timingfd) > -1)
+		close(fd);
+	while ((f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list)))
+		ast_frfree(f);
+	
+	/* Get rid of each of the data stores on the channel */
+	while ((datastore = AST_LIST_REMOVE_HEAD(&chan->datastores, entry)))
+		/* Free the data store */
+		ast_channel_datastore_free(datastore);
+	AST_LIST_HEAD_INIT_NOLOCK(&chan->datastores);
+
+	/* loop over the variables list, freeing all data and deleting list items */
+	/* no need to lock the list, as the channel is already locked */
+	
+	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
+		ast_var_delete(vardata);
+
+	ast_app_group_discard(chan);
+
+	ast_jb_destroy(chan);
+
+	ast_string_field_free_pools(chan);
+
+	ast_device_state_changed_literal(name);
+}
+
 /*! \brief Create a new channel structure */
 struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const int amaflag, const char *name_fmt, ...)
 {
@@ -999,6 +1088,7 @@
 		ast_clear_flag(chan, AST_FLAG_DEFER_DTMF);
 }
 
+#if 0
 /*!
  * \brief Helper function to find channels.
  *
@@ -1142,20 +1232,136 @@
 {
 	return channel_find_locked(chan, NULL, 0, context, exten);
 }
-
-/*
- * These operations must be implemented ...
- *
- * Get a channel by:
- *  - name
- *  - name prefix
- *  - exten (and optional context)
- *
- * Walk channels that match:
- *  - all channels
- *  - name prefix
- *  - exten (and optional context)
- */
+#endif
+
+struct ast_channel_iterator {
+	struct ao2_iterator _i;
+	const char *_name;
+	size_t _name_len;
+	const char *_exten;
+	const char *_context;
+};
+
+struct ast_channel_iterator *ast_channel_iterator_destroy(struct ast_channel_iterator *i)
+{
+	if (i->_name)
+		ast_free((void *) i->_name);
+	if (i->_exten)
+		ast_free((void *) i->_exten);
+	if (i->_context)
+		ast_free((void *) i->_context);
+	ast_free(i);
+
+	return NULL;
+}
+
+static struct ast_channel_iterator *ast_channel_iterator_new(const char *name, 
+	size_t name_len, const char *exten, const char *context)
+{
+	struct ast_channel_iterator *i;
+
+	if (!(i = ast_calloc(1, sizeof(*i))))
+		return NULL;
+
+	if (!ast_strlen_zero(exten) && !(i->_exten = ast_strdup(exten)))
+		goto return_error;
+
+	if (!ast_strlen_zero(context) && !(i->_context = ast_strdup(context)))
+		goto return_error;
+
+	if (!ast_strlen_zero(name) && !(i->_name = ast_strdup(name)))
+		goto return_error;
+
+	i->_name_len = name_len;
+
+	i->_i = ao2_iterator_init(channels, 0);
+
+	return i;
+
+return_error:
+	if (i->_exten)
+		ast_free((void *) i->_exten);
+	if (i->_context)
+		ast_free((void *) i->_context);
+	ast_free(i);
+
+	return NULL;
+}
+
+struct ast_channel_iterator *ast_channel_iterator_byexten_new(const char *exten, 
+	const char *context)
+{
+	return ast_channel_iterator_new(NULL, 0, exten, context);
+}
+
+struct ast_channel_iterator *ast_channel_iterator_byname_new(const char *name, 
+	size_t name_len)
+{
+	return ast_channel_iterator_new(name, name_len, NULL, NULL);
+}
+
+struct ast_channel_iterator *ast_channel_iterator_all_new(void)
+{
+	return ast_channel_iterator_new(NULL, 0, NULL, NULL);
+}
+
+struct ast_channel *ast_channel_iterator_next(struct ast_channel_iterator *i)
+{
+	struct ast_channel *chan = NULL;
+
+	for (; (chan = ao2_iterator_next(&i->_i)); ast_channel_unref(chan)) {
+		if (i->_name) { /* match by name */
+			if ((!i->_name_len && strcasecmp(chan->name, i->_name)) ||
+				(i->_name_len && strncasecmp(chan->name, i->_name, i->_name_len)))
+				continue; /* name match failed */
+		} else if (i->_exten) {
+			if (i->_context && strcasecmp(chan->context, i->_context) &&
+				strcasecmp(chan->macrocontext, i->_context))
+				continue; /* context match failed */
+			if (strcasecmp(chan->exten, i->_exten) &&
+				strcasecmp(chan->macroexten, i->_exten))
+				continue; /* exten match failed */
+		}
+		break; /* chan points to the next chan desired. */
+	}
+
+	return chan;
+}
+
+static struct ast_channel *ast_channel_get_full(const char *name, size_t name_len,
+	const char *exten, const char *context)
+{
+	struct ast_channel tmp_chan = {
+		.name = name,
+		/* This is sort of a hack.  Basically, we're using an arbitrary field
+		 * in ast_channel to pass the name_len for a prefix match.  If this
+		 * gets changed, then the compare callback must be changed, too. */
+		.rings = name_len,
+	};
+
+	if (exten)
+		ast_copy_string(tmp_chan.exten, exten, sizeof(tmp_chan.exten));
+
+	if (context)
+		ast_copy_string(tmp_chan.context, context, sizeof(tmp_chan.context));
+
+	return ao2_find(channels, &tmp_chan, OBJ_POINTER);
+}
+
+struct ast_channel *ast_channel_get_byname(const char *name)
+{
+	return ast_channel_get_full(name, 0, NULL, NULL);
+}
+
+struct ast_channel *ast_channel_get_byname_prefix(const char *name, size_t name_len)
+{
+	return ast_channel_get_full(name, name_len, NULL, NULL);
+}
+
+struct ast_channel *ast_channel_get_byexten(const char *exten, const char *context)
+{
+	return ast_channel_get_full(NULL, 0, exten, context);
+}
 
 /*! \brief Wait, look for hangups and condition arg */
 int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data)
@@ -1184,20 +1390,6 @@
 	return ast_safe_sleep_conditional(chan, ms, NULL, NULL);
 }
 
-static void free_cid(struct ast_callerid *cid)
-{
-	if (cid->cid_dnid)
-		free(cid->cid_dnid);
-	if (cid->cid_num)
-		free(cid->cid_num);	
-	if (cid->cid_name)
-		free(cid->cid_name);	
-	if (cid->cid_ani)
-		free(cid->cid_ani);
-	if (cid->cid_rdnis)
-		free(cid->cid_rdnis);
-}
-
 /*! 
  * \brief Unlink a channel from the channels container and also release
  *        this reference
@@ -1210,79 +1402,6 @@
 	/* This is safe, even if it the object has already been unlinked */
 	ao2_unlink(channels, chan);
 	return ast_channel_unref(chan);
-}
-
-void ast_channel_destructor(struct ast_channel *chan)
-{
-	int fd;
-	struct ast_var_t *vardata;
-	struct ast_frame *f;
-	struct varshead *headp;
-	struct ast_datastore *datastore = NULL;
-	char name[AST_CHANNEL_NAME];
-	
-	headp = &chan->varshead;
-	
-	if (chan->tech_pvt) {
-		ast_log(LOG_ERROR, "Channel '%s' may not have been hung up properly\n", chan->name);
-		free(chan->tech_pvt);
-	}
-
-	if (chan->sched)
-		sched_context_destroy(chan->sched);
-
-	ast_copy_string(name, chan->name, sizeof(name));
-
-	/* Stop monitoring */
-	if (chan->monitor)
-		chan->monitor->stop( chan, 0 );
-
-	/* If there is native format music-on-hold state, free it */
-	if (chan->music_state)
-		ast_moh_cleanup(chan);
-
-	/* if someone is whispering on the channel, stop them */
-	if (chan->whisper)
-		ast_channel_whisper_stop(chan);
-
-	/* Free translators */
-	if (chan->readtrans)
-		ast_translator_free_path(chan->readtrans);
-	if (chan->writetrans)
-		ast_translator_free_path(chan->writetrans);
-	if (chan->pbx)
-		ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
-	free_cid(&chan->cid);
-	ast_mutex_destroy(&chan->lock);
-	/* Close pipes if appropriate */
-	if ((fd = chan->alertpipe[0]) > -1)
-		close(fd);
-	if ((fd = chan->alertpipe[1]) > -1)
-		close(fd);
-	if ((fd = chan->timingfd) > -1)
-		close(fd);
-	while ((f = AST_LIST_REMOVE_HEAD(&chan->readq, frame_list)))
-		ast_frfree(f);
-	
-	/* Get rid of each of the data stores on the channel */
-	while ((datastore = AST_LIST_REMOVE_HEAD(&chan->datastores, entry)))
-		/* Free the data store */
-		ast_channel_datastore_free(datastore);
-	AST_LIST_HEAD_INIT_NOLOCK(&chan->datastores);
-
-	/* loop over the variables list, freeing all data and deleting list items */
-	/* no need to lock the list, as the channel is already locked */
-	
-	while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries)))
-		ast_var_delete(vardata);
-
-	ast_app_group_discard(chan);
-
-	ast_jb_destroy(chan);
-
-	ast_string_field_free_pools(chan);
-
-	ast_device_state_changed_literal(name);
 }
 
 struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, char *uid)
@@ -4610,6 +4729,11 @@
 {
 	const struct ast_channel *chan = obj;
 
+	/* If the name isn't set, return 0 so that the ao2_find() search will
+	 * start in the first bucket. */
+	if (ast_strlen_zero(chan->name))
+		return 0;
+
 	return ast_str_hash(chan->name);
 }
 
@@ -4618,16 +4742,37 @@
  */
 static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
 {
-	struct ast_channel *chan = obj, *chan2 = arg;
-
-	return !strcasecmp(chan->name, chan2->name) ? CMP_MATCH : 0;
+	struct ast_channel *chan = obj, *cmp_args = arg;
+	size_t name_len;
+	int ret = CMP_MATCH;
+
+	/* This is sort of a hack.  Basically, we're using an arbitrary field
+	 * in ast_channel to pass the name_len for a prefix match.  If this
+	 * gets changed, then the uses of ao2_find() must be changed, too. */
+	name_len = cmp_args->rings;
+
+	if (cmp_args->name) { /* match by name */
+		if ((!name_len && strcasecmp(chan->name, cmp_args->name)) ||
+			(name_len && strncasecmp(chan->name, cmp_args->name, name_len)))
+			ret = 0; /* name match failed */
+	} else if (cmp_args->exten) {
+		if (cmp_args->context && strcasecmp(chan->context, cmp_args->context) &&
+			strcasecmp(chan->macrocontext, cmp_args->context))
+			ret = 0; /* context match failed */
+		if (ret && strcasecmp(chan->exten, cmp_args->exten) &&
+			strcasecmp(chan->macroexten, cmp_args->exten))
+			ret = 0; /* exten match failed */
+	}
+
+	return ret;
 }
 
 void ast_channels_init(void)
 {
-	channels = ao2_container_alloc(MAX_CHANNEL_BUCKETS, ast_channel_hash, ast_channel_cmp);
-
-	ast_cli_register_multiple(cli_channel, sizeof(cli_channel) / sizeof(struct ast_cli_entry));
+	channels = ao2_container_alloc(MAX_CHANNEL_BUCKETS, 
+		ast_channel_hash_cb, ast_channel_cmp_cb);
+
+	ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
 }
 
 /*! \brief Print call group and pickup group ---*/




More information about the asterisk-commits mailing list