From 3318097204119e550a5e9691d7c3f11ea64fc8a8 Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 13 Aug 2018 17:32:58 +0200 Subject: Schedule destruction of channel during destruction of other channel --- src/rps/gnunet-service-rps.c | 55 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 18b9b792b..e0301af6b 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -275,6 +275,13 @@ struct ChannelCtx * @brief The peer context associated with the channel */ struct PeerContext *peer_ctx; + + /** + * @brief When channel destruction needs to be delayed (because it is called + * from within the cadet routine of another channel destruction) this task + * refers to the respective _SCHEDULER_Task. + */ + struct GNUNET_SCHEDULER_Task *destruction_task; }; /** @@ -304,7 +311,6 @@ static struct GNUNET_CONTAINER_MultiPeerMap *peer_map; static struct GNUNET_CADET_Handle *cadet_handle; - /** * @brief Get the #PeerContext associated with a peer * @@ -864,13 +870,47 @@ destroy_channel (struct ChannelCtx *channel_ctx) { struct PeerContext *peer_ctx = channel_ctx->peer_ctx; - GNUNET_assert (channel_ctx == peer_ctx->send_channel_ctx || - channel_ctx == peer_ctx->recv_channel_ctx); - + if (NULL != channel_ctx->destruction_task) + { + GNUNET_SCHEDULER_cancel (channel_ctx->destruction_task); + channel_ctx->destruction_task = NULL; + } GNUNET_CADET_channel_destroy (channel_ctx->channel); + channel_ctx->channel = NULL; remove_channel_ctx (channel_ctx); } +/** + * @brief Destroy a cadet channel. + * + * This satisfies the function signature of #GNUNET_SCHEDULER_TaskCallback. + * + * @param cls + */ +static void +destroy_channel_cb (void *cls) +{ + struct ChannelCtx *channel_ctx = cls; + channel_ctx->destruction_task = NULL; + destroy_channel (channel_ctx); +} + +/** + * @brief Schedule the destruction of a channel for immediately afterwards. + * + * In case a channel is to be destroyed from within the callback to the + * destruction of another channel (send channel), we cannot call + * GNUNET_CADET_channel_destroy directly, but need to use this scheduling + * construction. + * + * @param channel_ctx channel to be destroyed. + */ +static void +schedule_channel_destruction (struct ChannelCtx *channel_ctx) +{ + channel_ctx->destruction_task = + GNUNET_SCHEDULER_add_now (destroy_channel_cb, channel_ctx); +} /** * @brief Remove peer @@ -937,11 +977,13 @@ destroy_peer (struct PeerContext *peer_ctx) if (NULL != peer_ctx->send_channel_ctx) { - destroy_channel (peer_ctx->send_channel_ctx); + /* This is possibly called from within channel destruction */ + schedule_channel_destruction (peer_ctx->send_channel_ctx); } if (NULL != peer_ctx->recv_channel_ctx) { - destroy_channel (peer_ctx->recv_channel_ctx); + /* This is possibly called from within channel destruction */ + schedule_channel_destruction (peer_ctx->recv_channel_ctx); } if (GNUNET_YES != @@ -3874,6 +3916,7 @@ shutdown_task (void *cls) RPS_sampler_destroy (client_sampler); GNUNET_CADET_close_port (cadet_port); GNUNET_CADET_disconnect (cadet_handle); + cadet_handle = NULL; View_destroy (); CustomPeerMap_destroy (push_map); CustomPeerMap_destroy (pull_map); -- cgit v1.2.3