mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
taskprocessor: Prevent race creating new taskprocessor.
Task processors are retrieved using a 'get or create' pattern. The singleton container was unlocked between the get and create steps so it's possible that two threads could create task processors with the same name at the same time. Change-Id: Id64fae94a6a1e940ddf38fde622dcd4391635382
This commit is contained in:
@@ -731,6 +731,17 @@ static void *default_listener_pvt_alloc(void)
|
||||
return pvt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Allocate a task processor structure
|
||||
*
|
||||
* \param name Name of the task processor.
|
||||
* \param listener Listener to associate with the task processor.
|
||||
*
|
||||
* \return The newly allocated task processor.
|
||||
*
|
||||
* \pre tps_singletons must be locked by the caller.
|
||||
*/
|
||||
static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, struct ast_taskprocessor_listener *listener)
|
||||
{
|
||||
struct ast_taskprocessor *p;
|
||||
@@ -755,17 +766,23 @@ static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, stru
|
||||
ao2_ref(p, +1);
|
||||
listener->tps = p;
|
||||
|
||||
if (!(ao2_link(tps_singletons, p))) {
|
||||
if (!(ao2_link_flags(tps_singletons, p, OBJ_NOLOCK))) {
|
||||
ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name);
|
||||
listener->tps = NULL;
|
||||
ao2_ref(p, -2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (p->listener->callbacks->start(p->listener)) {
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct ast_taskprocessor *__start_taskprocessor(struct ast_taskprocessor *p)
|
||||
{
|
||||
if (p && p->listener->callbacks->start(p->listener)) {
|
||||
ast_log(LOG_ERROR, "Unable to start taskprocessor listener for taskprocessor %s\n",
|
||||
p->name);
|
||||
ast_taskprocessor_unreference(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -785,40 +802,51 @@ struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_o
|
||||
ast_log(LOG_ERROR, "requesting a nameless taskprocessor!!!\n");
|
||||
return NULL;
|
||||
}
|
||||
p = ao2_find(tps_singletons, name, OBJ_KEY);
|
||||
if (p) {
|
||||
ao2_lock(tps_singletons);
|
||||
p = ao2_find(tps_singletons, name, OBJ_KEY | OBJ_NOLOCK);
|
||||
if (p || (create & TPS_REF_IF_EXISTS)) {
|
||||
/* calling function does not want a new taskprocessor to be created if it doesn't already exist */
|
||||
ao2_unlock(tps_singletons);
|
||||
return p;
|
||||
}
|
||||
if (create & TPS_REF_IF_EXISTS) {
|
||||
/* calling function does not want a new taskprocessor to be created if it doesn't already exist */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a new taskprocessor. Start by creating a default listener */
|
||||
pvt = default_listener_pvt_alloc();
|
||||
if (!pvt) {
|
||||
ao2_unlock(tps_singletons);
|
||||
return NULL;
|
||||
}
|
||||
listener = ast_taskprocessor_listener_alloc(&default_listener_callbacks, pvt);
|
||||
if (!listener) {
|
||||
ao2_unlock(tps_singletons);
|
||||
default_listener_pvt_destroy(pvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = __allocate_taskprocessor(name, listener);
|
||||
|
||||
ao2_unlock(tps_singletons);
|
||||
p = __start_taskprocessor(p);
|
||||
ao2_ref(listener, -1);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener)
|
||||
{
|
||||
struct ast_taskprocessor *p = ao2_find(tps_singletons, name, OBJ_KEY);
|
||||
struct ast_taskprocessor *p;
|
||||
|
||||
ao2_lock(tps_singletons);
|
||||
p = ao2_find(tps_singletons, name, OBJ_KEY | OBJ_NOLOCK);
|
||||
if (p) {
|
||||
ao2_unlock(tps_singletons);
|
||||
ast_taskprocessor_unreference(p);
|
||||
return NULL;
|
||||
}
|
||||
return __allocate_taskprocessor(name, listener);
|
||||
|
||||
p = __allocate_taskprocessor(name, listener);
|
||||
ao2_unlock(tps_singletons);
|
||||
|
||||
return __start_taskprocessor(p);
|
||||
}
|
||||
|
||||
void ast_taskprocessor_set_local(struct ast_taskprocessor *tps,
|
||||
|
Reference in New Issue
Block a user