Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[asterisk/asterisk.git] / main / autochan.c
index c7e5c00..68aeaf8 100644 (file)
@@ -46,15 +46,18 @@ struct ast_autochan *ast_autochan_setup(struct ast_channel *chan)
        if (!(autochan = ast_calloc(1, sizeof(*autochan)))) {
                return NULL;
        }
+       ast_mutex_init(&autochan->lock);
 
        autochan->chan = ast_channel_ref(chan);
 
-       ast_channel_lock(autochan->chan); /* autochan is still private, no need for ast_autochan_channel_lock() */
+       ast_debug(1, "Created autochan %p to hold channel %s (%p)\n",
+               autochan, ast_channel_name(chan), chan);
+
+       /* autochan is still private, no need for ast_autochan_channel_lock() */
+       ast_channel_lock(autochan->chan);
        AST_LIST_INSERT_TAIL(ast_channel_autochans(autochan->chan), autochan, list);
        ast_channel_unlock(autochan->chan);
 
-       ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, ast_channel_name(chan), chan);
-
        return autochan;
 }
 
@@ -75,6 +78,8 @@ void ast_autochan_destroy(struct ast_autochan *autochan)
 
        autochan->chan = ast_channel_unref(autochan->chan);
 
+       ast_mutex_destroy(&autochan->lock);
+
        ast_free(autochan);
 }
 
@@ -84,13 +89,16 @@ void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *
 
        AST_LIST_APPEND_LIST(ast_channel_autochans(new_chan), ast_channel_autochans(old_chan), list);
 
+       /* Deadlock avoidance is not needed since the channels are already locked. */
        AST_LIST_TRAVERSE(ast_channel_autochans(new_chan), autochan, list) {
+               ast_mutex_lock(&autochan->lock);
                if (autochan->chan == old_chan) {
-                       autochan->chan = ast_channel_unref(old_chan);
                        autochan->chan = ast_channel_ref(new_chan);
+                       ast_channel_unref(old_chan);
 
                        ast_debug(1, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n",
                                        autochan, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
                }
+               ast_mutex_unlock(&autochan->lock);
        }
 }