From 22a34c2fab39c38cac4a22a0e15ab9a1fd98f57c Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 19 Nov 2015 21:44:13 +0000 Subject: [PATCH] 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 --- crypto/async/arch/async_null.c | 15 +++++- crypto/async/arch/async_posix.c | 18 ++++++- crypto/async/arch/async_win.c | 86 ++++++++++++++++++++++++++++++--- crypto/async/arch/async_win.h | 8 +-- crypto/async/async.c | 8 ++- crypto/async/async_err.c | 1 + crypto/async/async_locl.h | 5 +- include/openssl/async.h | 1 + util/libeay.num | 2 + 9 files changed, 127 insertions(+), 17 deletions(-) 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: -- 2.34.1