<p>Michael Bradeen has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/17999">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">taskprocessor.c: Prevent crash on graceful shutdown<br><br>When tps_shutdown is called as part of the cleanup process there is a<br>chance that one of the taskprocessors that references the<br>tps_singletons object is still running. The change is to allow for<br>tps_shutdown to check tps_singleton's container count and give the<br>running taskprocessors a chance to finish. If after<br>AST_TASKPROCESSOR_SHUTDOWN_MAX_WAIT (10) seconds there are still<br>container references we shutdown anyway as this is most likely a bug<br>due to a taskprocessor not being unreferenced.<br><br>ASTERISK-29365<br><br>Change-Id: Ia932fc003d316389b9c4fd15ad6594458c9727f1<br>---<br>M main/taskprocessor.c<br>1 file changed, 67 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/99/17999/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/main/taskprocessor.c b/main/taskprocessor.c</span><br><span>index 0209852..c5f3558 100644</span><br><span>--- a/main/taskprocessor.c</span><br><span>+++ b/main/taskprocessor.c</span><br><span>@@ -156,6 +156,9 @@</span><br><span> static char *cli_tps_reset_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);</span><br><span> static char *cli_tps_reset_stats_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int tps_sort_cb(const void *obj_left, const void *obj_right, int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct ast_cli_entry taskprocessor_clis[] = {</span><br><span> AST_CLI_DEFINE(cli_tps_ping, "Ping a named task processor"),</span><br><span> AST_CLI_DEFINE(cli_tps_report, "List instantiated task processors and statistics"),</span><br><span>@@ -284,12 +287,76 @@</span><br><span> .dtor = default_listener_pvt_dtor,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief How many seconds to wait for running taskprocessors to finish on shutdown. */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_TASKPROCESSOR_SHUTDOWN_MAX_WAIT 10</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span> * \internal</span><br><span> * \brief Clean up resources on Asterisk shutdown</span><br><span> */</span><br><span> static void tps_shutdown(void)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ int objcount;</span><br><span style="color: hsl(120, 100%, 40%);">+ int tries;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_container *sorted_tps;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_taskprocessor *tps;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_iterator iter;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timespec delay = {1, 0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* During shutdown there may still be taskprocessor threads running and those</span><br><span style="color: hsl(120, 100%, 40%);">+ * tasprocessors reference tps_singletons. When those taskprocessors finish</span><br><span style="color: hsl(120, 100%, 40%);">+ * they will call ast_taskprocessor_unreference, creating a race condition which</span><br><span style="color: hsl(120, 100%, 40%);">+ * can result in tps_singletons being referenced after being deleted. To try and</span><br><span style="color: hsl(120, 100%, 40%);">+ * avoid this we check the container count and if greater than zero, give the</span><br><span style="color: hsl(120, 100%, 40%);">+ * running taskprocessors a chance to finish */</span><br><span style="color: hsl(120, 100%, 40%);">+ objcount = ao2_container_count(tps_singletons);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (objcount > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "waiting for taskprocessor shutdown, %d tps object(s) still allocated.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ objcount);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* give the running taskprocessors a chance to finish, up to</span><br><span style="color: hsl(120, 100%, 40%);">+ * AST_TASKPROCESSOR_SHUTDOWN_MAX_WAIT seconds */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (tries = 0; tries < AST_TASKPROCESSOR_SHUTDOWN_MAX_WAIT; tries++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ while (nanosleep(&delay, &delay));</span><br><span style="color: hsl(120, 100%, 40%);">+ objcount = ao2_container_count(tps_singletons);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* if count is 0, we are done waiting */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (objcount == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ delay.tv_sec = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ delay.tv_nsec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "waiting for taskprocessor shutdown, %d tps object(s) still allocated.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ objcount);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* rather than try forever, risk an assertion on shutdown. This probably indicates</span><br><span style="color: hsl(120, 100%, 40%);">+ * a taskprocessor was not cleaned up somewhere */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (objcount > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Asertion may occur, the following taskprocessors are still runing:\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ sorted_tps = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, tps_sort_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!sorted_tps || ao2_container_dup(sorted_tps, tps_singletons, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "unable to get sorted list of taskprocessors");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ iter = ao2_iterator_init(sorted_tps, AO2_ITERATOR_UNLINK);</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((tps = ao2_iterator_next(&iter))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "taskprocessor '%s'\n", tps->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(sorted_tps);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "All waiting taskprocessors cleared!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ast_cli_unregister_multiple(taskprocessor_clis, ARRAY_LEN(taskprocessor_clis));</span><br><span> AST_VECTOR_CALLBACK_VOID(&overloaded_subsystems, ast_free);</span><br><span> AST_VECTOR_RW_FREE(&overloaded_subsystems);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/17999">change 17999</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/17999"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 19 </div>
<div style="display:none"> Gerrit-Change-Id: Ia932fc003d316389b9c4fd15ad6594458c9727f1 </div>
<div style="display:none"> Gerrit-Change-Number: 17999 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Michael Bradeen <mbradeen@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>