<p>Richard Mudgett has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/8753">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pjsip_scheduler.c: Fix ao2 usage errors.<br><br>* Removed several invalid uses of OBJ_NOLOCK.  These uses resulted in the<br>'tasks' container being accessed without a lock in a multi-threaded<br>environment.  A recipe for crashes.<br><br>* Removed needlessly obtaining schtd object references.  If the caller<br>providing you a pointer to an object doesn't have a valid reference then<br>you cannot safely get one from it.<br><br>* Getting a ref to 'tasks' when you aren't copying the pointer into<br>another location is useless.  The 'tasks' container pointer is global.<br><br>* Removed many unnecessary uses of RAII_VAR.<br><br>* Make ast_sip_schedule_task() name parameter const.<br><br>ASTERISK_26806<br><br>Change-Id: I5c62488e651314e2a1dbc01f5b078a15512d73db<br>---<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip/pjsip_scheduler.c<br>2 files changed, 56 insertions(+), 48 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/53/8753/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index 2643998..d3849ad 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -1673,7 +1673,7 @@<br>  *<br>  */<br> struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer,<br>-  int interval, ast_sip_task sip_task, char *name, void *task_data,<br>+    int interval, ast_sip_task sip_task, const char *name, void *task_data,<br>       enum ast_sip_scheduler_task_flags flags);<br> <br> /*!<br>diff --git a/res/res_pjsip/pjsip_scheduler.c b/res/res_pjsip/pjsip_scheduler.c<br>index e4459da..5b86a79 100644<br>--- a/res/res_pjsip/pjsip_scheduler.c<br>+++ b/res/res_pjsip/pjsip_scheduler.c<br>@@ -60,7 +60,7 @@<br>    enum ast_sip_scheduler_task_flags flags;<br>      /*! the serializer to be used (if any) */<br>     struct ast_taskprocessor *serializer;<br>-        /* A name to be associated with the task */<br>+  /*! A name to be associated with the task */<br>  char name[0];<br> };<br> <br>@@ -113,7 +113,7 @@<br>            delay = schtd->interval - (ast_tvdiff_ms(schtd->last_end, schtd->last_start) % schtd->interval);<br>  }<br> <br>- schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, (const void *)schtd);<br>+   schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, schtd);<br>  if (schtd->current_scheduler_id < 0) {<br>          schtd->interval = 0;<br>               ao2_unlock(schtd);<br>@@ -164,28 +164,28 @@<br> <br> int ast_sip_sched_task_cancel_by_name(const char *name)<br> {<br>-   RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup);<br>+     int res;<br>+     struct ast_sip_sched_task *schtd;<br> <br>  if (ast_strlen_zero(name)) {<br>          return -1;<br>    }<br> <br>- schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);<br>        if (!schtd) {<br>                 return -1;<br>    }<br> <br>- return ast_sip_sched_task_cancel(schtd);<br>+     res = ast_sip_sched_task_cancel(schtd);<br>+      ao2_ref(schtd, -1);<br>+  return res;<br> }<br> <br> <br> int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,<br>    struct timeval *queued, struct timeval *last_start, struct timeval *last_end)<br> {<br>-    if (!ao2_ref_and_lock(schtd)) {<br>-              return -1;<br>-   }<br>-<br>+ ao2_lock(schtd);<br>      if (queued) {<br>                 memcpy(queued, &schtd->when_queued, sizeof(struct timeval));<br>   }<br>@@ -195,8 +195,7 @@<br>        if (last_end) {<br>               memcpy(last_end, &schtd->last_end, sizeof(struct timeval));<br>    }<br>-<br>- ao2_unlock_and_unref(schtd);<br>+ ao2_unlock(schtd);<br> <br>         return 0;<br> }<br>@@ -204,18 +203,21 @@<br> int ast_sip_sched_task_get_times_by_name(const char *name,<br>     struct timeval *queued, struct timeval *last_start, struct timeval *last_end)<br> {<br>-    RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup);<br>+     int res;<br>+     struct ast_sip_sched_task *schtd;<br> <br>  if (ast_strlen_zero(name)) {<br>          return -1;<br>    }<br> <br>- schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);<br>        if (!schtd) {<br>                 return -1;<br>    }<br> <br>- return ast_sip_sched_task_get_times(schtd, queued, last_start, last_end);<br>+    res = ast_sip_sched_task_get_times(schtd, queued, last_start, last_end);<br>+     ao2_ref(schtd, -1);<br>+  return res;<br> }<br> <br> int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)<br>@@ -224,13 +226,9 @@<br>               return -1;<br>    }<br> <br>- if (!ao2_ref_and_lock(schtd)) {<br>-              return -1;<br>-   }<br>-<br>+ ao2_lock(schtd);<br>      ast_copy_string(name, schtd->name, maxlen);<br>-<br>-    ao2_unlock_and_unref(schtd);<br>+ ao2_unlock(schtd);<br> <br>         return 0;<br> }<br>@@ -241,9 +239,7 @@<br>    struct timeval since_when;<br>    struct timeval now;<br> <br>-       if (!ao2_ref_and_lock(schtd)) {<br>-              return -1;<br>-   }<br>+    ao2_lock(schtd);<br> <br>   if (schtd->interval) {<br>             delay = schtd->interval;<br>@@ -262,50 +258,52 @@<br>            delay = -1;<br>   }<br> <br>- ao2_unlock_and_unref(schtd);<br>+ ao2_unlock(schtd);<br> <br>         return delay;<br> }<br> <br> int ast_sip_sched_task_get_next_run_by_name(const char *name)<br> {<br>-     RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup);<br>+     int next_run;<br>+        struct ast_sip_sched_task *schtd;<br> <br>  if (ast_strlen_zero(name)) {<br>          return -1;<br>    }<br> <br>- schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);<br>        if (!schtd) {<br>                 return -1;<br>    }<br> <br>- return ast_sip_sched_task_get_next_run(schtd);<br>+       next_run = ast_sip_sched_task_get_next_run(schtd);<br>+   ao2_ref(schtd, -1);<br>+  return next_run;<br> }<br> <br> int ast_sip_sched_is_task_running(struct ast_sip_sched_task *schtd)<br> {<br>-    if (!schtd) {<br>-                return 0;<br>-    }<br>-<br>- return schtd->is_running;<br>+ return schtd ? schtd->is_running : 0;<br> }<br> <br> int ast_sip_sched_is_task_running_by_name(const char *name)<br> {<br>-    RAII_VAR(struct ast_sip_sched_task *, schtd, NULL, ao2_cleanup);<br>+     int is_running;<br>+      struct ast_sip_sched_task *schtd;<br> <br>  if (ast_strlen_zero(name)) {<br>          return 0;<br>     }<br> <br>- schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+  schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);<br>        if (!schtd) {<br>                 return 0;<br>     }<br> <br>- return schtd->is_running;<br>+ is_running = schtd->is_running;<br>+   ao2_ref(schtd, -1);<br>+  return is_running;<br> }<br> <br> static void schtd_destructor(void *data)<br>@@ -321,7 +319,8 @@<br> }<br> <br> struct ast_sip_sched_task *ast_sip_schedule_task(struct ast_taskprocessor *serializer,<br>-    int interval, ast_sip_task sip_task, char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)<br>+   int interval, ast_sip_task sip_task, const char *name, void *task_data,<br>+      enum ast_sip_scheduler_task_flags flags)<br> {<br> #define ID_LEN 13 /* task_deadbeef */<br>  struct ast_sip_sched_task *schtd;<br>@@ -352,7 +351,7 @@<br>        if (flags & AST_SIP_SCHED_TASK_DATA_AO2) {<br>                ao2_ref(task_data, +1);<br>       }<br>-    res = ast_sched_add(scheduler_context, interval, push_to_serializer, (const void *)schtd);<br>+   res = ast_sched_add(scheduler_context, interval, push_to_serializer, schtd);<br>  if (res < 0) {<br>             ao2_ref(schtd, -1);<br>           return NULL;<br>@@ -369,14 +368,14 @@<br> {<br>       struct ao2_iterator i;<br>        struct ast_sip_sched_task *schtd;<br>-    const char *log_format = ast_logger_get_dateformat();<br>+        const char *log_format;<br>       struct ast_tm tm;<br>     char queued[32];<br>      char last_start[32];<br>  char next_start[32];<br>  int datelen;<br>- struct timeval now = ast_tvnow();<br>-    const char *separator = "======================================";<br>+  struct timeval now;<br>+  static const char separator[] = "======================================";<br> <br>        switch (cmd) {<br>        case CLI_INIT:<br>@@ -392,6 +391,9 @@<br>           return CLI_SHOWUSAGE;<br>         }<br> <br>+ now = ast_tvnow();<br>+   log_format = ast_logger_get_dateformat();<br>+<br>  ast_localtime(&now, &tm, NULL);<br>       datelen = ast_strftime(queued, sizeof(queued), log_format, &tm);<br> <br>@@ -406,12 +408,16 @@<br>                datelen, separator, separator, datelen + 8, separator);<br> <br> <br>-        ao2_ref(tasks, +1);<br>   ao2_rdlock(tasks);<br>-   i = ao2_iterator_init(tasks, 0);<br>+     i = ao2_iterator_init(tasks, AO2_ITERATOR_DONTLOCK);<br>  while ((schtd = ao2_iterator_next(&i))) {<br>-                int next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000;<br>-            struct timeval next = ast_tvadd(now, (struct timeval) {next_run_sec, 0});<br>+            int next_run_sec;<br>+            struct timeval next;<br>+<br>+              ao2_lock(schtd);<br>+<br>+          next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000;<br>+                next = ast_tvadd(now, (struct timeval) {next_run_sec, 0});<br> <br>                 ast_localtime(&schtd->when_queued, &tm, NULL);<br>             ast_strftime(queued, sizeof(queued), log_format, &tm);<br>@@ -434,11 +440,12 @@<br>                     datelen, queued, last_start,<br>                  next_start,<br>                   next_run_sec);<br>+               ao2_unlock(schtd);<br>+<br>                 ao2_cleanup(schtd);<br>   }<br>     ao2_iterator_destroy(&i);<br>         ao2_unlock(tasks);<br>-   ao2_ref(tasks, -1);<br>   ast_cli(a->fd, "\n");<br> <br>         return CLI_SUCCESS;<br>@@ -461,8 +468,9 @@<br>              return -1;<br>    }<br> <br>- tasks = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,<br>-             TASK_BUCKETS, ast_sip_sched_task_hash_fn, ast_sip_sched_task_sort_fn, ast_sip_sched_task_cmp_fn);<br>+    tasks = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,<br>+          AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, TASK_BUCKETS, ast_sip_sched_task_hash_fn,<br>+               ast_sip_sched_task_sort_fn, ast_sip_sched_task_cmp_fn);<br>       if (!tasks) {<br>                 ast_log(LOG_ERROR, "Failed to allocate task container. Aborting load\n");<br>           ast_sched_context_destroy(scheduler_context);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8753">change 8753</a>. To unsubscribe, 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/8753"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I5c62488e651314e2a1dbc01f5b078a15512d73db </div>
<div style="display:none"> Gerrit-Change-Number: 8753 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Mudgett <rmudgett@digium.com> </div>