From: Matt Caswell <matt@openssl.org>
Date: Thu, 19 Nov 2015 21:44:13 +0000 (+0000)
Subject: Implement windows async thread local variable support
X-Git-Tag: OpenSSL_1_1_0-pre1~206
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=22a34c2fab39c38cac4a22a0e15ab9a1fd98f57c;p=openssl

Implement windows async thread local variable support

Implements Thread Local Storage in the windows async port. This also has
some knock on effects to the posix and null implementations.

Reviewed-by: Rich Salz <rsalz@openssl.org>
---

diff --git a/crypto/async/arch/async_null.c b/crypto/async/arch/async_null.c
index dba159f309..b2dbfee7ec 100644
--- a/crypto/async/arch/async_null.c
+++ b/crypto/async/arch/async_null.c
@@ -76,10 +76,23 @@ int async_read1(OSSL_ASYNC_FD fd, void *buf)
     return -1;
 }
 
-int async_thread_local_init(void)
+int async_global_init(void)
 {
     return 0;
 }
 
+int async_local_init(void)
+{
+    return 0;
+}
+
+void async_local_cleanup(void)
+{
+}
+
+void async_global_cleanup(void)
+{
+}
+
 #endif
 
diff --git a/crypto/async/arch/async_posix.c b/crypto/async/arch/async_posix.c
index bd4b0c2f1b..77a2c33de6 100644
--- a/crypto/async/arch/async_posix.c
+++ b/crypto/async/arch/async_posix.c
@@ -66,7 +66,7 @@ pthread_key_t posixpool;
 
 #define STACKSIZE       32768
 
-int async_thread_local_init(void)
+int async_global_init(void)
 {
     if (pthread_key_create(&posixctx, NULL) != 0
             || pthread_key_create(&posixpool, NULL) != 0)
@@ -75,6 +75,22 @@ int async_thread_local_init(void)
     return 1;
 }
 
+int async_local_init(void)
+{
+    if (!async_set_ctx(NULL) || ! async_set_pool(NULL))
+        return 0;
+
+    return 1;
+}
+
+void async_local_cleanup(void)
+{
+}
+
+void async_global_cleanup(void)
+{
+}
+
 int async_fibre_init(async_fibre *fibre)
 {
     void *stack = NULL;
diff --git a/crypto/async/arch/async_win.c b/crypto/async/arch/async_win.c
index 4eb449d34f..20c8a09bc4 100644
--- a/crypto/async/arch/async_win.c
+++ b/crypto/async/arch/async_win.c
@@ -64,18 +64,80 @@ struct winpool {
     size_t max_size;
 };
 
+static DWORD asyncwinpool = 0;
+static DWORD asyncwinctx = 0;
+static DWORD asyncwindispatch = 0;
+
+
 void async_start_func(void);
 
+int async_global_init(void)
+{
+    asyncwinpool = TlsAlloc();
+    asyncwinctx = TlsAlloc();
+    asyncwindispatch = TlsAlloc();
+    if (asyncwinpool == TLS_OUT_OF_INDEXES || asyncwinctx == TLS_OUT_OF_INDEXES
+            || asyncwindispatch == TLS_OUT_OF_INDEXES) {
+        if (asyncwinpool != TLS_OUT_OF_INDEXES) {
+            TlsFree(asyncwinpool);
+        }
+        if (asyncwinctx != TLS_OUT_OF_INDEXES) {
+            TlsFree(asyncwinctx);
+        }
+        if (asyncwindispatch != TLS_OUT_OF_INDEXES) {
+            TlsFree(asyncwindispatch);
+        }
+        return 0;
+    }
+    return 1;
+}
+
+int async_local_init(void)
+{
+    return (TlsSetValue(asyncwinpool, NULL) != 0)
+        && (TlsSetValue(asyncwinctx, NULL) != 0)
+        && (TlsSetValue(asyncwindispatch, NULL) != 0);
+}
+
+void async_local_cleanup(void)
+{
+    async_ctx *ctx = async_get_ctx();
+    if (ctx != NULL) {
+        async_fibre *fibre = &ctx->dispatcher;
+        if(fibre != NULL && fibre->fibre != NULL && fibre->converted) {
+            ConvertFiberToThread();
+            fibre->fibre = NULL;
+        }
+    }
+}
+
+void async_global_cleanup(void)
+{
+    TlsFree(asyncwinpool);
+    TlsFree(asyncwinctx);
+    TlsFree(asyncwindispatch);
+    asyncwinpool = 0;
+    asyncwinctx = 0;
+    asyncwindispatch = 0;
+}
+
 int async_fibre_init_dispatcher(async_fibre *fibre)
 {
     LPVOID dispatcher;
 
-    dispatcher =
-        (LPVOID) CRYPTO_get_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_DISPATCH);
+    dispatcher = (LPVOID)TlsGetValue(asyncwindispatch);
     if (dispatcher == NULL) {
         fibre->fibre = ConvertThreadToFiber(NULL);
-        CRYPTO_set_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_DISPATCH,
-                                (void *)fibre->fibre);
+        if (fibre->fibre == NULL) {
+            fibre->converted = 0;
+            fibre->fibre = GetCurrentFiber();
+            if (fibre->fibre == NULL)
+                return 0;
+        } else {
+            fibre->converted = 1;
+        }
+        if (TlsSetValue(asyncwindispatch, (LPVOID)fibre->fibre) == 0)
+            return 0;
     } else {
         fibre->fibre = dispatcher;
     }
@@ -125,15 +187,23 @@ int async_read1(OSSL_ASYNC_FD fd, void *buf)
 
 async_pool *async_get_pool(void)
 {
-    return (async_pool *)
-            CRYPTO_get_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_POOL);
+    return (async_pool *)TlsGetValue(asyncwinpool);
 }
 
 
 int async_set_pool(async_pool *pool)
 {
-    CRYPTO_set_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_POOL, (void *)pool);
-    return 1;
+    return TlsSetValue(asyncwinpool, (LPVOID)pool) != 0;
+}
+
+async_ctx *async_get_ctx(void)
+{
+    return (async_ctx *)TlsGetValue(asyncwinctx);
+}
+
+int async_set_ctx(async_ctx *ctx)
+{
+    return TlsSetValue(asyncwinctx, (LPVOID)ctx) != 0;
 }
 
 #endif
diff --git a/crypto/async/arch/async_win.h b/crypto/async/arch/async_win.h
index 5e91732e87..77e41e405b 100644
--- a/crypto/async/arch/async_win.h
+++ b/crypto/async/arch/async_win.h
@@ -66,18 +66,18 @@
 
 typedef struct async_fibre_st {
     LPVOID fibre;
+    int converted;
 } async_fibre;
 
-# define async_set_ctx(nctx) \
-        (CRYPTO_set_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_CTX, (void *)(nctx)))
-# define async_get_ctx() \
-        ((async_ctx *)CRYPTO_get_thread_local(CRYPTO_THREAD_LOCAL_ASYNC_CTX))
 # define async_fibre_swapcontext(o,n,r) \
         (SwitchToFiber((n)->fibre), 1)
 # define async_fibre_makecontext(c) \
         ((c)->fibre = CreateFiber(0, async_start_func_win, 0))
 # define async_fibre_free(f)             (DeleteFiber((f)->fibre))
 
+async_ctx *async_get_ctx(void);
+int async_set_ctx(async_ctx *ctx);
+
 int async_fibre_init_dispatcher(async_fibre *fibre);
 VOID CALLBACK async_start_func_win(PVOID unused);
 
diff --git a/crypto/async/async.c b/crypto/async/async.c
index c18c5c4517..5664d990b6 100644
--- a/crypto/async/async.c
+++ b/crypto/async/async.c
@@ -330,7 +330,7 @@ static void async_empty_pool(async_pool *pool)
 
 int ASYNC_init(int init_thread, size_t max_size, size_t init_size)
 {
-    if (!async_thread_local_init())
+    if (!async_global_init())
         return 0;
 
     if (init_thread)
@@ -349,6 +349,10 @@ int ASYNC_init_thread(size_t max_size, size_t init_size)
         return 0;
     }
 
+    if (!async_local_init()) {
+        ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_INIT_FAILED);
+        return 0;
+    }
     pool = OPENSSL_zalloc(sizeof *pool);
     if (pool == NULL) {
         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ERR_R_MALLOC_FAILURE);
@@ -383,7 +387,6 @@ int ASYNC_init_thread(size_t max_size, size_t init_size)
         }
     }
     pool->curr_size = curr_size;
-
     if (!async_set_pool(pool)) {
         ASYNCerr(ASYNC_F_ASYNC_INIT_THREAD, ASYNC_R_FAILED_TO_SET_POOL);
         goto err;
@@ -404,6 +407,7 @@ static void async_free_pool_internal(async_pool *pool)
     sk_ASYNC_JOB_free(pool->jobs);
     OPENSSL_free(pool);
     (void)async_set_pool(NULL);
+    async_local_cleanup();
     async_ctx_free();
 }
 
diff --git a/crypto/async/async_err.c b/crypto/async/async_err.c
index 07a169ba86..6fe1f85dbb 100644
--- a/crypto/async/async_err.c
+++ b/crypto/async/async_err.c
@@ -83,6 +83,7 @@ static ERR_STRING_DATA ASYNC_str_reasons[] = {
     {ERR_REASON(ASYNC_R_CANNOT_CREATE_WAIT_PIPE), "cannot create wait pipe"},
     {ERR_REASON(ASYNC_R_FAILED_TO_SET_POOL), "failed to set pool"},
     {ERR_REASON(ASYNC_R_FAILED_TO_SWAP_CONTEXT), "failed to swap context"},
+    {ERR_REASON(ASYNC_R_INIT_FAILED), "init failed"},
     {ERR_REASON(ASYNC_R_INVALID_POOL_SIZE), "invalid pool size"},
     {ERR_REASON(ASYNC_R_POOL_ALREADY_INITED), "pool already inited"},
     {0, NULL}
diff --git a/crypto/async/async_locl.h b/crypto/async/async_locl.h
index 0a9c59fcfb..a463bf1c22 100644
--- a/crypto/async/async_locl.h
+++ b/crypto/async/async_locl.h
@@ -86,7 +86,10 @@ struct async_pool_st {
     size_t max_size;
 };
 
-int async_thread_local_init(void);
+int async_global_init(void);
+int async_local_init(void);
+void async_local_cleanup(void);
+void async_global_cleanup(void);
 void async_start_func(void);
 int async_pipe(OSSL_ASYNC_FD *pipefds);
 int async_close_fd(OSSL_ASYNC_FD fd);
diff --git a/include/openssl/async.h b/include/openssl/async.h
index 83bde16eba..de5ef89644 100644
--- a/include/openssl/async.h
+++ b/include/openssl/async.h
@@ -112,6 +112,7 @@ void ERR_load_ASYNC_strings(void);
 # define ASYNC_R_CANNOT_CREATE_WAIT_PIPE                  100
 # define ASYNC_R_FAILED_TO_SET_POOL                       101
 # define ASYNC_R_FAILED_TO_SWAP_CONTEXT                   102
+# define ASYNC_R_INIT_FAILED                              105
 # define ASYNC_R_INVALID_POOL_SIZE                        103
 # define ASYNC_R_POOL_ALREADY_INITED                      104
 
diff --git a/util/libeay.num b/util/libeay.num
index c61d83d249..0ff302c78f 100755
--- a/util/libeay.num
+++ b/util/libeay.num
@@ -4661,3 +4661,5 @@ ASYNC_get_wait_fd                       5020	EXIST::FUNCTION:
 ERR_load_ASYNC_strings                  5021	EXIST::FUNCTION:
 ASYNC_unblock_pause                     5022	EXIST::FUNCTION:
 ASYNC_block_pause                       5023	EXIST::FUNCTION:
+ASYNC_cleanup                           5024	EXIST::FUNCTION:
+ASYNC_init                              5025	EXIST::FUNCTION: