diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 9828aa6bbc83bb50ea9f8e17fa7b0000aa16769d..f49eee16bdd9e614be1c792af908b42d19058a5d 100755 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -206,21 +206,27 @@ void ast_context_destroy(struct ast_context *con, const char *registrar); */ struct ast_context *ast_context_find(const char *name); +enum ast_pbx_result { + AST_PBX_SUCCESS = 0, + AST_PBX_FAILED = -1, + AST_PBX_CALL_LIMIT = -2, +}; + /*! Create a new thread and start the PBX (or whatever) */ /*! * \param c channel to start the pbx on - * Starts a pbx thread on a given channel - * It returns -1 on failure, and 0 on success + * \return Zero on success, non-zero on failure */ -int ast_pbx_start(struct ast_channel *c); +enum ast_pbx_result ast_pbx_start(struct ast_channel *c); /*! Execute the PBX in the current thread */ /*! * \param c channel to run the pbx on - * This executes the PBX on a given channel. It allocates a new + * \return Zero on success, non-zero on failure + * This executes the PBX on a given channel. It allocates a new * PBX structure for the channel, and provides all PBX functionality. */ -int ast_pbx_run(struct ast_channel *c); +enum ast_pbx_result ast_pbx_run(struct ast_channel *c); /*! * \param context context to add the extension to diff --git a/pbx.c b/pbx.c index a1eb07b99fec1b19358b8c195b0a1ae6fd10775b..6bae090ac8345a456e31853276c46c0c6ff1d98f 100755 --- a/pbx.c +++ b/pbx.c @@ -2407,56 +2407,87 @@ out: return 0; } +/* Returns 0 on success, non-zero if call limit was reached */ +static int increase_call_count(const struct ast_channel *c) +{ + int failed = 0; + + ast_mutex_lock(&maxcalllock); + if (option_maxcalls) { + if (countcalls >= option_maxcalls) { + ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name); + failed = -1; + } + } + if (!failed) + countcalls++; + ast_mutex_unlock(&maxcalllock); + + return failed; +} + +static void decrease_call_count(void) +{ + ast_mutex_lock(&maxcalllock); + if (countcalls > 0) + countcalls--; + ast_mutex_unlock(&maxcalllock); +} + static void *pbx_thread(void *data) { /* Oh joyeous kernel, we're a new thread, with nothing to do but answer this channel and get it going. */ + /* NOTE: + The launcher of this function _MUST_ increment 'countcalls' + before invoking the function; it will be decremented when the + PBX has finished running on the channel + */ struct ast_channel *c = data; - ast_pbx_run(c); + + __ast_pbx_run(c); + decrease_call_count(); + pthread_exit(NULL); + return NULL; } -int ast_pbx_start(struct ast_channel *c) +enum ast_pbx_result ast_pbx_start(struct ast_channel *c) { pthread_t t; pthread_attr_t attr; + if (!c) { ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n"); - return -1; + return AST_PBX_FAILED; } + if (increase_call_count(c)) + return AST_PBX_CALL_LIMIT; + /* Start a new thread, and get something handling this channel. */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (ast_pthread_create(&t, &attr, pbx_thread, c)) { ast_log(LOG_WARNING, "Failed to create new channel thread\n"); - return -1; + return AST_PBX_FAILED; } - return 0; + + return AST_PBX_SUCCESS; } -int ast_pbx_run(struct ast_channel *c) +enum ast_pbx_result ast_pbx_run(struct ast_channel *c) { - int res = 0; - ast_mutex_lock(&maxcalllock); - if (option_maxcalls) { - if (countcalls >= option_maxcalls) { - ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name); - res = -1; - } - } - if (!res) - countcalls++; - ast_mutex_unlock(&maxcalllock); - if (!res) { - res = __ast_pbx_run(c); - ast_mutex_lock(&maxcalllock); - if (countcalls > 0) - countcalls--; - ast_mutex_unlock(&maxcalllock); - } + enum ast_pbx_result res = AST_PBX_SUCCESS; + + if (increase_call_count(c)) + return AST_PBX_CALL_LIMIT; + + res = __ast_pbx_run(c); + decrease_call_count(); + return res; }