From: Joshua Colp Date: Fri, 20 Apr 2018 23:12:53 +0000 (+0000) Subject: stream: Make the topology a reference counted object. X-Git-Tag: 15.5.0-rc1~78^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0ad4d2301c9f14f8797cc8a388a8b01d55fc1456;p=thirdparty%2Fasterisk.git stream: Make the topology a reference counted object. The stream topology has no lock of its own resulting in another lock protecting it in some way (for example the channel lock). If multiple channels are being juggled at the same time this can be problematic. This change makes the topology a reference counted object instead which guarantees it will remain valid even without the channel lock being held. Change-Id: I4f4d3dd856a033ed55fe218c3a4fab364afedb03 --- diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 23dc548467..46b27f1042 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -2159,15 +2159,7 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st ast_bridge_channel_lock(participant); ast_channel_lock(participant->chan); - topology = ast_channel_get_stream_topology(participant->chan); - if (topology) { - /* - * Sigh. We have to clone to avoid deadlock in - * map_source_to_destinations() because topology - * is not an ao2 object. - */ - topology = ast_stream_topology_clone(topology); - } + topology = ao2_bump(ast_channel_get_stream_topology(participant->chan)); if (!topology) { /* Oh, my, we are in trouble. */ ast_channel_unlock(participant->chan); diff --git a/include/asterisk/stream.h b/include/asterisk/stream.h index 99998c7e33..30001e0a60 100644 --- a/include/asterisk/stream.h +++ b/include/asterisk/stream.h @@ -274,6 +274,8 @@ int ast_stream_get_position(const struct ast_stream *stream); * \retval NULL failure * * \since 15 + * + * \note This returns an ao2 refcounted object */ struct ast_stream_topology *ast_stream_topology_alloc(void); @@ -286,6 +288,8 @@ struct ast_stream_topology *ast_stream_topology_alloc(void); * \retval NULL failure * * \since 15 + * + * \note This returns an ao2 refcounted object */ struct ast_stream_topology *ast_stream_topology_clone( const struct ast_stream_topology *topology); @@ -305,7 +309,7 @@ int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right); /*! - * \brief Destroy a stream topology + * \brief Unreference and destroy a stream topology * * \param topology The topology of streams * diff --git a/main/stream.c b/main/stream.c index 5d4970a856..1c46e17182 100644 --- a/main/stream.c +++ b/main/stream.c @@ -297,18 +297,26 @@ int ast_stream_get_position(const struct ast_stream *stream) return stream->position; } +static void stream_topology_destroy(void *data) +{ + struct ast_stream_topology *topology = data; + + AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free); + AST_VECTOR_FREE(&topology->streams); +} + #define TOPOLOGY_INITIAL_STREAM_COUNT 2 struct ast_stream_topology *ast_stream_topology_alloc(void) { struct ast_stream_topology *topology; - topology = ast_calloc(1, sizeof(*topology)); + topology = ao2_alloc_options(sizeof(*topology), stream_topology_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!topology) { return NULL; } if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) { - ast_free(topology); + ao2_ref(topology, -1); topology = NULL; } @@ -393,13 +401,7 @@ int ast_stream_topology_equal(const struct ast_stream_topology *left, void ast_stream_topology_free(struct ast_stream_topology *topology) { - if (!topology) { - return; - } - - AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free); - AST_VECTOR_FREE(&topology->streams); - ast_free(topology); + ao2_cleanup(topology); } int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)