]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix a few rare race conditions that could lead to a lockup
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 13 Mar 2013 21:10:36 +0000 (16:10 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 13 Mar 2013 21:10:42 +0000 (16:10 -0500)
src/switch_core_sqldb.c
src/switch_scheduler.c

index cdea61ab256896e82cfb8a262a1a58ed2029d887..1b607910c351dfb3cbdc907ec0ab51b45be68d68 100644 (file)
@@ -1250,6 +1250,7 @@ struct switch_sql_queue_manager {
        int thread_running;
        switch_thread_cond_t *cond;
        switch_mutex_t *cond_mutex;
+       switch_mutex_t *cond2_mutex;
        switch_mutex_t *mutex;
        char *pre_trans_execute;
        char *post_trans_execute;
@@ -1262,10 +1263,26 @@ struct switch_sql_queue_manager {
 
 static int qm_wake(switch_sql_queue_manager_t *qm)
 {
-       if (switch_mutex_trylock(qm->cond_mutex) == SWITCH_STATUS_SUCCESS) {
+       switch_status_t status;
+       int tries = 0;
+
+ top:
+       
+       status = switch_mutex_trylock(qm->cond_mutex);
+
+       if (status == SWITCH_STATUS_SUCCESS) {
                switch_thread_cond_signal(qm->cond);
                switch_mutex_unlock(qm->cond_mutex);
                return 1;
+       } else {
+               if (switch_mutex_trylock(qm->cond2_mutex) == SWITCH_STATUS_SUCCESS) {
+                       switch_mutex_unlock(qm->cond2_mutex);
+               } else {
+                       if (++tries < 10) {
+                               switch_cond_next();
+                               goto top;
+                       }
+               }
        }
 
        return 0;
@@ -1407,6 +1424,7 @@ SWITCH_DECLARE(switch_status_t) switch_sql_queue_manager_stop(switch_sql_queue_m
 
        if (qm->thread) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Stopping SQL thread.\n", qm->name);
+               qm_wake(qm);
                switch_thread_join(&status, qm->thread);
                qm->thread = NULL;
                status = SWITCH_STATUS_SUCCESS;
@@ -1596,6 +1614,7 @@ SWITCH_DECLARE(switch_status_t) switch_sql_queue_manager_init_name(const char *n
        qm->max_trans = max_trans;
 
        switch_mutex_init(&qm->cond_mutex, SWITCH_MUTEX_NESTED, qm->pool);
+       switch_mutex_init(&qm->cond2_mutex, SWITCH_MUTEX_NESTED, qm->pool);
        switch_mutex_init(&qm->mutex, SWITCH_MUTEX_NESTED, qm->pool);
        switch_thread_cond_create(&qm->cond, qm->pool);
        
@@ -1850,7 +1869,9 @@ static void *SWITCH_THREAD_FUNC switch_user_sql_thread(switch_thread_t *thread,
        check:
 
                if ((lc = qm_ttl(qm)) == 0) {
+                       switch_mutex_lock(qm->cond2_mutex);
                        switch_thread_cond_wait(qm->cond, qm->cond_mutex);
+                       switch_mutex_unlock(qm->cond2_mutex);
                }
 
                i = 40;
index d6f501e45372a997176044883c68f57072a1354c..d59a7608e32870b654b6ad90d6355cd8dc026edd 100644 (file)
@@ -37,6 +37,7 @@ struct switch_scheduler_task_container {
        int64_t executed;
        int in_thread;
        int destroyed;
+       int running;
        switch_scheduler_func_t func;
        switch_memory_pool_t *pool;
        uint32_t flags;
@@ -124,7 +125,11 @@ static int task_thread_loop(int done)
                                        tp->in_thread = 1;
                                        switch_thread_create(&thread, thd_attr, task_own_thread, tp, tp->pool);
                                } else {
+                                       tp->running = 1;
+                                       switch_mutex_unlock(globals.task_mutex);
                                        switch_scheduler_execute(tp);
+                                       switch_mutex_lock(globals.task_mutex);
+                                       tp->running = 0;
                                }
                        }
                }
@@ -238,6 +243,13 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_id(uint32_t task_id)
                                                                  tp->task.task_id, tp->task.group);
                                break;
                        }
+
+                       if (tp->running) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Attempt made to delete running task #%u (group %s)\n",
+                                                                 tp->task.task_id, tp->task.group);
+                               break;
+                       }
+
                        tp->destroyed++;
                        if (switch_event_create(&event, SWITCH_EVENT_DEL_SCHEDULE) == SWITCH_STATUS_SUCCESS) {
                                switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Task-ID", "%u", tp->task.task_id);