[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