summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/syncop.c73
-rw-r--r--libglusterfs/src/syncop.h3
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*/
};