diff options
| -rw-r--r-- | libglusterfs/src/syncop.c | 73 | ||||
| -rw-r--r-- | libglusterfs/src/syncop.h | 3 | 
2 files changed, 73 insertions, 3 deletions
diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index a4250330dfd..1b968d5164a 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -442,10 +442,24 @@ synctask_create (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk,  {          struct synctask *newtask = NULL;          xlator_t        *this    = THIS; +        int             destroymode = 0;          VALIDATE_OR_GOTO (env, err);          VALIDATE_OR_GOTO (fn, err); +        /* Check if the syncenv is in destroymode i.e. destroy is SET. +         * If YES, then don't allow any new synctasks on it. Return NULL. +         */ +        pthread_mutex_lock (&env->mutex); +        { +                destroymode = env->destroy; +        } +        pthread_mutex_unlock (&env->mutex); + +        /* syncenv is in DESTROY mode, return from here */ +        if (destroymode) +                return NULL; +          newtask = CALLOC (1, sizeof (*newtask));          if (!newtask)                  return NULL; @@ -576,11 +590,25 @@ syncenv_task (struct syncproc *proc)                                                        &sleep_till);                          if (!list_empty (&env->runq))                                  break; -                        if ((ret == ETIMEDOUT) && -                            (env->procs > env->procmin)) { +                        /* If either of the conditions are met then exit +                         * the current thread: +                         * 1. syncenv has to scale down(procs > procmin) +                         * 2. syncenv is in destroy mode and no tasks in +                         *    either waitq or runq. +                         * +                         * At any point in time, a task can be either in runq, +                         * or in executing state or in the waitq. Once the +                         * destroy mode is set, no new synctask creates will +                         * be allowed, but whatever in waitq or runq should be +                         * allowed to finish before exiting any of the syncenv +                         * processor threads. +                         */ +                        if (((ret == ETIMEDOUT) && (env->procs > env->procmin)) +                            || (env->destroy && list_empty (&env->waitq))) {                                  task = NULL;                                  env->procs--;                                  memset (proc, 0, sizeof (*proc)); +                                pthread_cond_broadcast (&env->cond);                                  goto unlock;                          }                  } @@ -701,11 +729,50 @@ unlock:          pthread_mutex_unlock (&env->mutex);  } - +/* The syncenv threads are cleaned up in this routine. + */  void  syncenv_destroy (struct syncenv *env)  { +        if (env == NULL) +                return; + +        /* SET the 'destroy' in syncenv structure to prohibit any +         * further synctask(s) on this syncenv which is in destroy mode. +         * +         * If syncenv threads are in pthread cond wait with no tasks in +         * their run or wait queue, then the threads are woken up by +         * broadcasting the cond variable and if destroy field is set, +         * the infinite loop in syncenv_processor is broken and the +         * threads return. +         * +         * If syncenv threads have tasks in runq or waitq, the tasks are +         * completed and only then the thread returns. +         */ +        pthread_mutex_lock (&env->mutex); +        { +                env->destroy = 1; +                /* This broadcast will wake threads in pthread_cond_wait +                 * in syncenv_task +                 */ +                pthread_cond_broadcast (&env->cond); + +                /* when the syncenv_task() thread is exiting, it broadcasts to +                 * wake the below wait. +                 */ +                while (env->procs != 0) { +                        pthread_cond_wait (&env->cond, &env->mutex); +                } +        } +        pthread_mutex_unlock (&env->mutex); + +        pthread_mutex_destroy (&env->mutex); +        pthread_cond_destroy (&env->cond); + +        FREE (env); + +        return;  } diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index e3b51018307..ec0d8a917e8 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -108,6 +108,9 @@ struct syncenv {          pthread_cond_t      cond;          size_t              stacksize; + +        int                 destroy; /* FLAG to mark syncenv is in destroy mode +                                        so that no more synctasks are accepted*/  };  | 
