summaryrefslogtreecommitdiff
path: root/lib/pthreadpool
diff options
context:
space:
mode:
authorChristof Schmitt <cs@samba.org>2017-11-28 10:59:06 -0700
committerChristof Schmitt <cs@samba.org>2017-12-08 09:43:12 +0100
commit065fb5d94d25d19fc85832bb85aa9e379e8551cc (patch)
tree64877730677840b247047d6489b4564ac1212d27 /lib/pthreadpool
parent949ccc3ea9073a3d38bff28345f644d39177256f (diff)
downloadsamba-065fb5d94d25d19fc85832bb85aa9e379e8551cc.tar.gz
pthreadpool: Undo put_job when returning error
When an error is returned to the caller of pthreadpool_add_job, the job should not be kept in the internal job array. Otherwise the caller might free the data structure and a later worker thread would still reference it. When it is not possible to create a single worker thread, the system might be out of resources or hitting a configured limit. In this case fall back to calling the job function synchronously instead of raising the error to the caller and possibly back to the SMB client. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13170 Signed-off-by: Christof Schmitt <cs@samba.org> Reviewed-by: Volker Lendecke <vl@samba.org>
Diffstat (limited to 'lib/pthreadpool')
-rw-r--r--lib/pthreadpool/pthreadpool.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/lib/pthreadpool/pthreadpool.c b/lib/pthreadpool/pthreadpool.c
index 4e1e5d41fca..309aba98866 100644
--- a/lib/pthreadpool/pthreadpool.c
+++ b/lib/pthreadpool/pthreadpool.c
@@ -429,6 +429,11 @@ static bool pthreadpool_put_job(struct pthreadpool *p,
return true;
}
+static void pthreadpool_undo_put_job(struct pthreadpool *p)
+{
+ p->num_jobs -= 1;
+}
+
static void *pthreadpool_server(void *arg)
{
struct pthreadpool *pool = (struct pthreadpool *)arg;
@@ -599,6 +604,9 @@ int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
* We have idle threads, wake one.
*/
res = pthread_cond_signal(&pool->condvar);
+ if (res != 0) {
+ pthreadpool_undo_put_job(pool);
+ }
pthread_mutex_unlock(&pool->mutex);
return res;
}
@@ -614,8 +622,24 @@ int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
res = pthreadpool_create_thread(pool);
if (res != 0) {
- pthread_mutex_unlock(&pool->mutex);
- return res;
+ if (pool->num_threads == 0) {
+ /*
+ * No thread could be created to run job,
+ * fallback to sync call.
+ */
+ pthreadpool_undo_put_job(pool);
+ pthread_mutex_unlock(&pool->mutex);
+
+ fn(private_data);
+ return pool->signal_fn(job_id, fn, private_data,
+ pool->signal_fn_private_data);
+ }
+
+ /*
+ * At least one thread is still available, let
+ * that one run the queued job.
+ */
+ res = 0;
}
pthread_mutex_unlock(&pool->mutex);