mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 02:26:23 +00:00
fix locking bug - lock instead of unlock (see commit to r7960 to branches/1.2)
store hint list using linked list macros git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@7962 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
158
pbx.c
158
pbx.c
@@ -192,7 +192,7 @@ struct ast_hint {
|
|||||||
struct ast_exten *exten; /*!< Extension */
|
struct ast_exten *exten; /*!< Extension */
|
||||||
int laststate; /*!< Last known state */
|
int laststate; /*!< Last known state */
|
||||||
struct ast_state_cb *callbacks; /*!< Callback list for this extension */
|
struct ast_state_cb *callbacks; /*!< Callback list for this extension */
|
||||||
struct ast_hint *next; /*!< Pointer to next hint in list */
|
AST_LIST_ENTRY(ast_hint) list; /*!< Pointer to next hint in list */
|
||||||
};
|
};
|
||||||
|
|
||||||
int ast_pbx_outgoing_cdr_failed(void);
|
int ast_pbx_outgoing_cdr_failed(void);
|
||||||
@@ -452,9 +452,8 @@ AST_MUTEX_DEFINE_STATIC(applock); /*!< Lock for the application list */
|
|||||||
struct ast_switch *switches = NULL;
|
struct ast_switch *switches = NULL;
|
||||||
AST_MUTEX_DEFINE_STATIC(switchlock); /*!< Lock for switches */
|
AST_MUTEX_DEFINE_STATIC(switchlock); /*!< Lock for switches */
|
||||||
|
|
||||||
AST_MUTEX_DEFINE_STATIC(hintlock); /*!< Lock for extension state notifys */
|
|
||||||
static int stateid = 1;
|
static int stateid = 1;
|
||||||
struct ast_hint *hints = NULL;
|
static AST_LIST_HEAD_STATIC(hints, ast_hint);
|
||||||
struct ast_state_cb *statecbs = NULL;
|
struct ast_state_cb *statecbs = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1829,9 +1828,9 @@ void ast_hint_state_changed(const char *device)
|
|||||||
char *cur;
|
char *cur;
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
|
||||||
for (hint = hints; hint; hint = hint->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
|
ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
|
||||||
parse = buf;
|
parse = buf;
|
||||||
for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
|
for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
|
||||||
@@ -1859,25 +1858,25 @@ void ast_hint_state_changed(const char *device)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief ast_extension_state_add: Add watcher for extension states */
|
/*! \brief ast_extension_state_add: Add watcher for extension states */
|
||||||
int ast_extension_state_add(const char *context, const char *exten,
|
int ast_extension_state_add(const char *context, const char *exten,
|
||||||
ast_state_cb_type callback, void *data)
|
ast_state_cb_type callback, void *data)
|
||||||
{
|
{
|
||||||
struct ast_hint *list;
|
struct ast_hint *hint;
|
||||||
struct ast_state_cb *cblist;
|
struct ast_state_cb *cblist;
|
||||||
struct ast_exten *e;
|
struct ast_exten *e;
|
||||||
|
|
||||||
/* If there's no context and extension: add callback to statecbs list */
|
/* If there's no context and extension: add callback to statecbs list */
|
||||||
if (!context && !exten) {
|
if (!context && !exten) {
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
|
||||||
for (cblist = statecbs; cblist; cblist = cblist->next) {
|
for (cblist = statecbs; cblist; cblist = cblist->next) {
|
||||||
if (cblist->callback == callback) {
|
if (cblist->callback == callback) {
|
||||||
cblist->data = data;
|
cblist->data = data;
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1885,7 +1884,7 @@ int ast_extension_state_add(const char *context, const char *exten,
|
|||||||
/* Now insert the callback */
|
/* Now insert the callback */
|
||||||
cblist = calloc(1, sizeof(struct ast_state_cb));
|
cblist = calloc(1, sizeof(struct ast_state_cb));
|
||||||
if (!cblist) {
|
if (!cblist) {
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cblist->id = 0;
|
cblist->id = 0;
|
||||||
@@ -1895,7 +1894,7 @@ int ast_extension_state_add(const char *context, const char *exten,
|
|||||||
cblist->next = statecbs;
|
cblist->next = statecbs;
|
||||||
statecbs = cblist;
|
statecbs = cblist;
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1909,46 +1908,46 @@ int ast_extension_state_add(const char *context, const char *exten,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find the hint in the list of hints */
|
/* Find the hint in the list of hints */
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
|
||||||
for (list = hints; list; list = list->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
if (list->exten == e)
|
if (hint->exten == e)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list) {
|
if (!hint) {
|
||||||
/* We have no hint, sorry */
|
/* We have no hint, sorry */
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now insert the callback in the callback list */
|
/* Now insert the callback in the callback list */
|
||||||
cblist = calloc(1, sizeof(struct ast_state_cb));
|
cblist = calloc(1, sizeof(struct ast_state_cb));
|
||||||
if (!cblist) {
|
if (!cblist) {
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cblist->id = stateid++; /* Unique ID for this callback */
|
cblist->id = stateid++; /* Unique ID for this callback */
|
||||||
cblist->callback = callback; /* Pointer to callback routine */
|
cblist->callback = callback; /* Pointer to callback routine */
|
||||||
cblist->data = data; /* Data for the callback */
|
cblist->data = data; /* Data for the callback */
|
||||||
|
|
||||||
cblist->next = list->callbacks;
|
cblist->next = hint->callbacks;
|
||||||
list->callbacks = cblist;
|
hint->callbacks = cblist;
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return cblist->id;
|
return cblist->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief ast_extension_state_del: Remove a watcher from the callback list */
|
/*! \brief ast_extension_state_del: Remove a watcher from the callback list */
|
||||||
int ast_extension_state_del(int id, ast_state_cb_type callback)
|
int ast_extension_state_del(int id, ast_state_cb_type callback)
|
||||||
{
|
{
|
||||||
struct ast_hint *list;
|
struct ast_hint *hint;
|
||||||
struct ast_state_cb *cblist, *cbprev;
|
struct ast_state_cb *cblist, *cbprev;
|
||||||
|
|
||||||
if (!id && !callback)
|
if (!id && !callback)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
|
||||||
/* id is zero is a callback without extension */
|
/* id is zero is a callback without extension */
|
||||||
if (!id) {
|
if (!id) {
|
||||||
@@ -1962,54 +1961,54 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
|
|||||||
|
|
||||||
free(cblist);
|
free(cblist);
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cbprev = cblist;
|
cbprev = cblist;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* id greater than zero is a callback with extension */
|
/* id greater than zero is a callback with extension */
|
||||||
/* Find the callback based on ID */
|
/* Find the callback based on ID */
|
||||||
for (list = hints; list; list = list->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
cbprev = NULL;
|
cbprev = NULL;
|
||||||
for (cblist = list->callbacks; cblist; cblist = cblist->next) {
|
for (cblist = hint->callbacks; cblist; cblist = cblist->next) {
|
||||||
if (cblist->id==id) {
|
if (cblist->id==id) {
|
||||||
if (!cbprev)
|
if (!cbprev)
|
||||||
list->callbacks = cblist->next;
|
hint->callbacks = cblist->next;
|
||||||
else
|
else
|
||||||
cbprev->next = cblist->next;
|
cbprev->next = cblist->next;
|
||||||
|
|
||||||
free(cblist);
|
free(cblist);
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cbprev = cblist;
|
cbprev = cblist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
|
/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
|
||||||
static int ast_add_hint(struct ast_exten *e)
|
static int ast_add_hint(struct ast_exten *e)
|
||||||
{
|
{
|
||||||
struct ast_hint *list;
|
struct ast_hint *hint;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
|
||||||
/* Search if hint exists, do nothing */
|
/* Search if hint exists, do nothing */
|
||||||
for (list = hints; list; list = list->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
if (list->exten == e) {
|
if (hint->exten == e) {
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
if (option_debug > 1)
|
if (option_debug > 1)
|
||||||
ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
|
ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2019,82 +2018,75 @@ static int ast_add_hint(struct ast_exten *e)
|
|||||||
if (option_debug > 1)
|
if (option_debug > 1)
|
||||||
ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
|
ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
|
||||||
|
|
||||||
list = calloc(1, sizeof(struct ast_hint));
|
hint = calloc(1, sizeof(struct ast_hint));
|
||||||
if (!list) {
|
if (!hint) {
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
if (option_debug > 1)
|
if (option_debug > 1)
|
||||||
ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
|
ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Initialize and insert new item at the top */
|
/* Initialize and insert new item at the top */
|
||||||
list->exten = e;
|
hint->exten = e;
|
||||||
list->laststate = ast_extension_state2(e);
|
hint->laststate = ast_extension_state2(e);
|
||||||
list->next = hints;
|
AST_LIST_INSERT_HEAD(&hints, hint, list);
|
||||||
hints = list;
|
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief ast_change_hint: Change hint for an extension */
|
/*! \brief ast_change_hint: Change hint for an extension */
|
||||||
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
|
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
|
||||||
{
|
{
|
||||||
struct ast_hint *list;
|
struct ast_hint *hint;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
for (list = hints; list; list = list->next) {
|
if (hint->exten == oe) {
|
||||||
if (list->exten == oe) {
|
hint->exten = ne;
|
||||||
list->exten = ne;
|
res = 0;
|
||||||
ast_mutex_unlock(&hintlock);
|
break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AST_LIST_UNLOCK(&hints);
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
return res;
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief ast_remove_hint: Remove hint from extension */
|
/*! \brief ast_remove_hint: Remove hint from extension */
|
||||||
static int ast_remove_hint(struct ast_exten *e)
|
static int ast_remove_hint(struct ast_exten *e)
|
||||||
{
|
{
|
||||||
/* Cleanup the Notifys if hint is removed */
|
/* Cleanup the Notifys if hint is removed */
|
||||||
struct ast_hint *list, *prev = NULL;
|
struct ast_hint *hint;
|
||||||
struct ast_state_cb *cblist, *cbprev;
|
struct ast_state_cb *cblist, *cbprev;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
|
AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
|
||||||
for (list = hints; list; list = list->next) {
|
if (hint->exten == e) {
|
||||||
if (list->exten == e) {
|
|
||||||
cbprev = NULL;
|
cbprev = NULL;
|
||||||
cblist = list->callbacks;
|
cblist = hint->callbacks;
|
||||||
while (cblist) {
|
while (cblist) {
|
||||||
/* Notify with -1 and remove all callbacks */
|
/* Notify with -1 and remove all callbacks */
|
||||||
cbprev = cblist;
|
cbprev = cblist;
|
||||||
cblist = cblist->next;
|
cblist = cblist->next;
|
||||||
cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
|
cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
|
||||||
free(cbprev);
|
free(cbprev);
|
||||||
}
|
}
|
||||||
list->callbacks = NULL;
|
hint->callbacks = NULL;
|
||||||
|
AST_LIST_REMOVE_CURRENT(&hints, list);
|
||||||
if (!prev)
|
free(hint);
|
||||||
hints = list->next;
|
res = 0;
|
||||||
else
|
break;
|
||||||
prev->next = list->next;
|
|
||||||
free(list);
|
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
prev = list;
|
|
||||||
}
|
}
|
||||||
|
AST_LIST_TRAVERSE_SAFE_END
|
||||||
|
AST_LIST_UNLOCK(&hints);
|
||||||
|
|
||||||
ast_mutex_unlock(&hintlock);
|
return res;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3020,17 +3012,17 @@ static int handle_show_hints(int fd, int argc, char *argv[])
|
|||||||
int watchers;
|
int watchers;
|
||||||
struct ast_state_cb *watcher;
|
struct ast_state_cb *watcher;
|
||||||
|
|
||||||
if (!hints) {
|
if (AST_LIST_EMPTY(&hints)) {
|
||||||
ast_cli(fd, "There are no registered dialplan hints\n");
|
ast_cli(fd, "There are no registered dialplan hints\n");
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
/* ... we have hints ... */
|
/* ... we have hints ... */
|
||||||
ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
|
ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
|
||||||
if (ast_mutex_lock(&hintlock)) {
|
if (AST_LIST_LOCK(&hints)) {
|
||||||
ast_log(LOG_ERROR, "Unable to lock hints\n");
|
ast_log(LOG_ERROR, "Unable to lock hints\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (hint = hints; hint; hint = hint->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
watchers = 0;
|
watchers = 0;
|
||||||
for (watcher = hint->callbacks; watcher; watcher = watcher->next)
|
for (watcher = hint->callbacks; watcher; watcher = watcher->next)
|
||||||
watchers++;
|
watchers++;
|
||||||
@@ -3041,7 +3033,7 @@ static int handle_show_hints(int fd, int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
ast_cli(fd, "----------------\n");
|
ast_cli(fd, "----------------\n");
|
||||||
ast_cli(fd, "- %d hints registered\n", num);
|
ast_cli(fd, "- %d hints registered\n", num);
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3590,8 +3582,8 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
|
|||||||
|
|
||||||
/* preserve all watchers for hints associated with this registrar */
|
/* preserve all watchers for hints associated with this registrar */
|
||||||
AST_LIST_HEAD_INIT(&store);
|
AST_LIST_HEAD_INIT(&store);
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
for (hint = hints; hint; hint = hint->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
|
if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
|
||||||
length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
|
length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
|
||||||
this = calloc(1, length);
|
this = calloc(1, length);
|
||||||
@@ -3609,7 +3601,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
|
|||||||
AST_LIST_INSERT_HEAD(&store, this, list);
|
AST_LIST_INSERT_HEAD(&store, this, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
|
|
||||||
tmp = *extcontexts;
|
tmp = *extcontexts;
|
||||||
ast_mutex_lock(&conlock);
|
ast_mutex_lock(&conlock);
|
||||||
@@ -3640,8 +3632,8 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
|
|||||||
while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
|
while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
|
||||||
exten = ast_hint_extension(NULL, this->context, this->exten);
|
exten = ast_hint_extension(NULL, this->context, this->exten);
|
||||||
/* Find the hint in the list of hints */
|
/* Find the hint in the list of hints */
|
||||||
ast_mutex_lock(&hintlock);
|
AST_LIST_LOCK(&hints);
|
||||||
for (hint = hints; hint; hint = hint->next) {
|
AST_LIST_TRAVERSE(&hints, hint, list) {
|
||||||
if (hint->exten == exten)
|
if (hint->exten == exten)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3663,7 +3655,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
|
|||||||
hint->callbacks = this->callbacks;
|
hint->callbacks = this->callbacks;
|
||||||
hint->laststate = this->laststate;
|
hint->laststate = this->laststate;
|
||||||
}
|
}
|
||||||
ast_mutex_unlock(&hintlock);
|
AST_LIST_UNLOCK(&hints);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user