aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>2019-01-10 14:12:48 +0000
committerWill Deacon <will.deacon@arm.com>2019-01-22 06:55:26 +0000
commit7a7f45421f3a04e25d274c207ddd110af69da1bb (patch)
tree1662ce0587fc786881a0c8ee488a7ce08f76d3eb
parent6730b51f1d128910f628c43bb0d2fb655c7ceefe (diff)
downloadkvmtool-7a7f45421f3a04e25d274c207ddd110af69da1bb.tar.gz
threadpool: Add cancel() function
When resetting a virtqueue, it is often necessary to make sure that the associated threadpool job isn't running anymore. Add a function to cancel a job. A threadpool job has three states: idle, queued and running. A job is queued when it is in the job list. It is running when it is out the list, but its signal count is greater than zero. It is idle when it is both out of the list and its signal count is zero. The cancel() function simply waits for the job to be idle. It is up to the caller to make sure that the job isn't queued concurrently. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> Signed-off-by: Julien Thierry <julien.thierry@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--include/kvm/threadpool.h2
-rw-r--r--util/threadpool.c25
2 files changed, 26 insertions, 1 deletions
diff --git a/include/kvm/threadpool.h b/include/kvm/threadpool.h
index bacb2434..880487a3 100644
--- a/include/kvm/threadpool.h
+++ b/include/kvm/threadpool.h
@@ -28,11 +28,13 @@ static inline void thread_pool__init_job(struct thread_pool__job *job, struct kv
.data = data,
.mutex = MUTEX_INITIALIZER,
};
+ INIT_LIST_HEAD(&job->queue);
}
int thread_pool__init(struct kvm *kvm);
int thread_pool__exit(struct kvm *kvm);
void thread_pool__do_job(struct thread_pool__job *job);
+void thread_pool__cancel_job(struct thread_pool__job *job);
#endif
diff --git a/util/threadpool.c b/util/threadpool.c
index e64aa26d..1dc3bf7e 100644
--- a/util/threadpool.c
+++ b/util/threadpool.c
@@ -25,7 +25,7 @@ static struct thread_pool__job *thread_pool__job_pop_locked(void)
return NULL;
job = list_first_entry(&head, struct thread_pool__job, queue);
- list_del(&job->queue);
+ list_del_init(&job->queue);
return job;
}
@@ -173,3 +173,26 @@ void thread_pool__do_job(struct thread_pool__job *job)
pthread_cond_signal(&job_cond);
mutex_unlock(&job_mutex);
}
+
+void thread_pool__cancel_job(struct thread_pool__job *job)
+{
+ bool running;
+
+ /*
+ * If the job is queued but not running, remove it. Otherwise, wait for
+ * the signalcount to drop to 0, indicating that it has finished
+ * running. We assume that nobody is queueing this job -
+ * thread_pool__do_job() isn't called - while this function is running.
+ */
+ do {
+ mutex_lock(&job_mutex);
+ if (list_empty(&job->queue)) {
+ running = job->signalcount > 0;
+ } else {
+ list_del_init(&job->queue);
+ job->signalcount = 0;
+ running = false;
+ }
+ mutex_unlock(&job_mutex);
+ } while (running);
+}