From 3fc35313f09f534e8eed770ab5f583af05c7af4c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 28 Nov 2017 10:59:06 -0700 Subject: [PATCH] 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 Reviewed-by: Volker Lendecke (cherry picked from commit 065fb5d94d25d19fc85832bb85aa9e379e8551cc) --- source3/lib/pthreadpool/pthreadpool.c | 28 +++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/source3/lib/pthreadpool/pthreadpool.c b/source3/lib/pthreadpool/pthreadpool.c index 4e1e5d41fca..309aba98866 100644 --- a/source3/lib/pthreadpool/pthreadpool.c +++ b/source3/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); -- 2.47.2