diff options
author | Christof Schmitt <cs@samba.org> | 2017-11-28 10:59:06 -0700 |
---|---|---|
committer | Christof Schmitt <cs@samba.org> | 2017-12-08 09:43:12 +0100 |
commit | 065fb5d94d25d19fc85832bb85aa9e379e8551cc (patch) | |
tree | 64877730677840b247047d6489b4564ac1212d27 | |
parent | 949ccc3ea9073a3d38bff28345f644d39177256f (diff) | |
download | samba-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>
-rw-r--r-- | lib/pthreadpool/pthreadpool.c | 28 |
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); |