[PATCH 4/4] kdf: handle errors from thread dispatch/wait functions

Jussi Kivilinna jussi.kivilinna at iki.fi
Fri Jan 28 20:06:16 CET 2022


* cipher/kdf.c (argon2_compute): Handle failed job dispatch/wait.
* tests/t-kdf.c (pthread_jobs_launch_job)
(wait_all_jobs_completion): Handle errors returned from pthread functions.
--

This allows thread helpers to return error code, which causes
KDF processing to stop.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/kdf.c  | 15 ++++++++++++---
 tests/t-kdf.c | 24 ++++++++++++++++++++----
 2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/cipher/kdf.c b/cipher/kdf.c
index 74c5b753..79dc6cd8 100644
--- a/cipher/kdf.c
+++ b/cipher/kdf.c
@@ -706,6 +706,7 @@ argon2_compute (argon2_ctx_t a, const struct gcry_kdf_thread_ops *ops)
   unsigned int r;
   unsigned int s;
   unsigned int l;
+  int ret;
 
   ec = argon2_fill_first_blocks (a);
   if (ec)
@@ -726,14 +727,22 @@ argon2_compute (argon2_ctx_t a, const struct gcry_kdf_thread_ops *ops)
             thread_data->lane = l;
 
             if (ops)
-              ops->dispatch_job (ops->jobs_context,
-                                 argon2_compute_segment, thread_data);
+	      {
+		ret = ops->dispatch_job (ops->jobs_context,
+					 argon2_compute_segment, thread_data);
+		if (ret < 0)
+		  return GPG_ERR_CANCELED;
+	      }
             else
               argon2_compute_segment (thread_data);
           }
 
         if (ops)
-          ops->wait_all_jobs (ops->jobs_context);
+	  {
+	    ret = ops->wait_all_jobs (ops->jobs_context);
+	    if (ret < 0)
+	      return GPG_ERR_CANCELED;
+	  }
       }
 
   return 0;
diff --git a/tests/t-kdf.c b/tests/t-kdf.c
index 8844e111..4c82fed8 100644
--- a/tests/t-kdf.c
+++ b/tests/t-kdf.c
@@ -1270,25 +1270,38 @@ job_thread (void *p)
   pthread_exit (NULL);
 }
 
+static int
+wait_all_jobs_completion (void *jobs_context);
+
 static int
 pthread_jobs_launch_job (void *jobs_context, gcry_kdf_job_fn_t job,
 			 void *job_priv)
 {
   struct user_defined_threads_ctx *ctx = jobs_context;
+  int ret;
 
   if (ctx->next_thread_idx == ctx->oldest_thread_idx)
     {
       assert (ctx->num_threads_running == MAX_THREADS);
       /* thread limit reached, join a thread */
-      pthread_join (ctx->thread[ctx->oldest_thread_idx], NULL);
+      ret = pthread_join (ctx->thread[ctx->oldest_thread_idx], NULL);
+      if (ret)
+	return -1;
       ctx->oldest_thread_idx = (ctx->oldest_thread_idx + 1) % MAX_THREADS;
       ctx->num_threads_running--;
     }
 
   ctx->work[ctx->next_thread_idx].job = job;
   ctx->work[ctx->next_thread_idx].priv = job_priv;
-  pthread_create (&ctx->thread[ctx->next_thread_idx], &ctx->attr,
-                  job_thread, &ctx->work[ctx->next_thread_idx]);
+  ret = pthread_create (&ctx->thread[ctx->next_thread_idx], &ctx->attr,
+			job_thread, &ctx->work[ctx->next_thread_idx]);
+  if (ret)
+    {
+      /* could not create new thread. */
+      (void)wait_all_jobs_completion (jobs_context);
+      return -1;
+    }
+
   if (ctx->oldest_thread_idx < 0)
     ctx->oldest_thread_idx = ctx->next_thread_idx;
   ctx->next_thread_idx = (ctx->next_thread_idx + 1) % MAX_THREADS;
@@ -1301,11 +1314,14 @@ wait_all_jobs_completion (void *jobs_context)
 {
   struct user_defined_threads_ctx *ctx = jobs_context;
   int i, idx;
+  int ret;
 
   for (i = 0; i < ctx->num_threads_running; i++)
     {
       idx = (ctx->oldest_thread_idx + i) % MAX_THREADS;
-      pthread_join (ctx->thread[idx], NULL);
+      ret = pthread_join (ctx->thread[idx], NULL);
+      if (ret)
+	return -1;
     }
 
   /* reset context for next round of parallel work */
-- 
2.32.0




More information about the Gcrypt-devel mailing list