From 1dd04a0fe2ffc4104db5198543ed0ec5895e9651 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Wed, 22 Feb 2023 19:15:16 +0000 Subject: [PATCH] QUIC Thread Assisted Mode: Support Windows XP Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/20348) --- crypto/build.info | 1 + crypto/thread/arch/thread_none.c | 9 ++ crypto/thread/arch/thread_posix.c | 8 ++ crypto/thread/arch/thread_win.c | 141 +++++++++++++++++++++++------- include/internal/thread_arch.h | 4 + ssl/quic/quic_thread_assist.c | 8 +- test/quic_tserver_test.c | 3 +- 7 files changed, 137 insertions(+), 37 deletions(-) diff --git a/crypto/build.info b/crypto/build.info index 5c45cd703b..36856561ba 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -110,6 +110,7 @@ SOURCE[../libcrypto]=$UTIL_COMMON \ punycode.c passphrase.c sleep.c deterministic_nonce.c quic_vlint.c \ time.c SOURCE[../providers/libfips.a]=$UTIL_COMMON +SOURCE[../providers/libfips.a]=time.c SOURCE[../libcrypto]=$UPLINKSRC DEFINE[../libcrypto]=$UPLINKDEF diff --git a/crypto/thread/arch/thread_none.c b/crypto/thread/arch/thread_none.c index c9c047c8e7..675944bc52 100644 --- a/crypto/thread/arch/thread_none.c +++ b/crypto/thread/arch/thread_none.c @@ -62,10 +62,19 @@ void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex) { } +void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex, + OSSL_TIME deadline) +{ +} + void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) { } +void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv) +{ +} + void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) { } diff --git a/crypto/thread/arch/thread_posix.c b/crypto/thread/arch/thread_posix.c index ae79fe579c..0ab27b1230 100644 --- a/crypto/thread/arch/thread_posix.c +++ b/crypto/thread/arch/thread_posix.c @@ -204,6 +204,14 @@ void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) pthread_cond_broadcast(cv_p); } +void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv) +{ + pthread_cond_t *cv_p; + + cv_p = (pthread_cond_t *)cv; + pthread_cond_signal(cv_p); +} + void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) { pthread_cond_t **cv_p; diff --git a/crypto/thread/arch/thread_win.c b/crypto/thread/arch/thread_win.c index 38a3e9a75b..cfda50f0be 100644 --- a/crypto/thread/arch/thread_win.c +++ b/crypto/thread/arch/thread_win.c @@ -26,7 +26,7 @@ static DWORD __stdcall thread_start_thunk(LPVOID vthread) ossl_crypto_mutex_lock(thread->statelock); CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_FINISHED); thread->retval = ret; - ossl_crypto_condvar_broadcast(thread->condvar); + ossl_crypto_condvar_signal(thread->condvar); ossl_crypto_mutex_unlock(thread->statelock); return 0; @@ -142,6 +142,97 @@ void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex) *mutex = NULL; } +static int determine_timeout(OSSL_TIME deadline, DWORD *w_timeout_p) +{ + OSSL_TIME now, delta; + uint64_t ms; + + if (ossl_time_is_infinite(deadline)) { + *w_timeout_p = INFINITE; + return 1; + } + + now = ossl_time_now(); + delta = ossl_time_subtract(deadline, now); + + if (ossl_time_is_zero(delta)) + return 0; + + ms = ossl_time2ms(delta); + + + /* + * Amount of time we want to wait is too long for the 32-bit argument to + * the Win32 API, so just wait as long as possible. + */ + if (ms > (uint64_t)(INFINITE - 1)) + *w_timeout_p = INFINITE - 1; + else + *w_timeout_p = (DWORD)ms; + + return 1; +} + +# if defined(OPENSSL_THREADS_WINNT_LEGACY) + +CRYPTO_CONDVAR *ossl_crypto_condvar_new(void) +{ + HANDLE h; + + if ((h = CreateEventA(NULL, FALSE, FALSE, NULL)) == NULL) + return NULL; + + return (CRYPTO_CONDVAR *)h; +} + +void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex) +{ + ossl_crypto_mutex_unlock(mutex); + WaitForSingleObject((HANDLE)cv, INFINITE); + ossl_crypto_mutex_lock(mutex); +} + +void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex, + OSSL_TIME deadline) +{ + DWORD timeout; + + fprintf(stderr, "# wt\n"); fflush(stderr); + if (!determine_timeout(deadline, &timeout)) + timeout = 1; + + ossl_crypto_mutex_unlock(mutex); + WaitForSingleObject((HANDLE)cv, timeout); + fprintf(stderr, "# wtd\n"); fflush(stderr); + ossl_crypto_mutex_lock(mutex); + fprintf(stderr, "# wtd2\n"); fflush(stderr); +} + +void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) +{ + /* Not supported */ +} + +void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv) +{ + HANDLE *cv_p = (HANDLE *)cv; + + SetEvent(cv_p); +} + +void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) +{ + HANDLE **cv_p; + + cv_p = (HANDLE **)cv; + if (*cv_p != NULL) + CloseHandle(*cv_p); + + *cv_p = NULL; +} + +# else + CRYPTO_CONDVAR *ossl_crypto_condvar_new(void) { CONDITION_VARIABLE *cv_p; @@ -163,41 +254,16 @@ void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex) } void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex, - OSSL_TIME deadline, int *timeout_expired) + OSSL_TIME deadline) { DWORD timeout; CONDITION_VARIABLE *cv_p = (CONDITION_VARIABLE *)cv; CRITICAL_SECTION *mutex_p = (CRITICAL_SECTION *)mutex; - if (ossl_time_is_infinite(deadline)) { - timeout = INFINITE; - } else { - OSSL_TIME now = ossl_time_now(); - OSSL_TIME delta = ossl_time_subtract(deadline, now); - uint64_t ms; - - if (ossl_time_is_zero(delta)) { - if (timeout_expired != NULL) - *timeout_expired = 1; - - return; - } - - ms = ossl_time2ms(delta); - - /* - * Amount of time we want to wait is too long for the 32-bit argument to - * the Win32 API, so just wait as long as possible. - */ - if (ms > (uint64_t)(INFINITE - 1)) - timeout = INFINITE - 1; - else - timeout = (DWORD)ms; - } + if (!determine_timeout(deadline, &timeout)) + timeout = 1; - if (!SleepConditionVariableCS(cv_p, mutex_p, timeout) - && timeout_expired != NULL) - *timeout_expired = 1; + SleepConditionVariableCS(cv_p, mutex_p, timeout); } void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) @@ -208,6 +274,14 @@ void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv) WakeAllConditionVariable(cv_p); } +void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv) +{ + CONDITION_VARIABLE *cv_p; + + cv_p = (CONDITION_VARIABLE *)cv; + WakeConditionVariable(cv_p); +} + void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) { CONDITION_VARIABLE **cv_p; @@ -218,3 +292,10 @@ void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv) } #endif + +void ossl_crypto_mem_barrier(void) +{ + MemoryBarrier(); +} + +#endif diff --git a/include/internal/thread_arch.h b/include/internal/thread_arch.h index c8607d50a4..24280d9706 100644 --- a/include/internal/thread_arch.h +++ b/include/internal/thread_arch.h @@ -25,6 +25,9 @@ defined(_WIN32_WINNT) # if _WIN32_WINNT >= 0x0600 # define OPENSSL_THREADS_WINNT +# elif _WIN32_WINNT >= 0x0501 +# define OPENSSL_THREADS_WINNT +# define OPENSSL_THREADS_WINNT_LEGACY # else # define OPENSSL_THREADS_NONE # endif @@ -48,6 +51,7 @@ void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex); void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex, OSSL_TIME deadline); void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv); +void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv); void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv); typedef uint32_t CRYPTO_THREAD_RETVAL; diff --git a/ssl/quic/quic_thread_assist.c b/ssl/quic/quic_thread_assist.c index 3e2ff1bc6f..93d246ea8e 100644 --- a/ssl/quic/quic_thread_assist.c +++ b/ssl/quic/quic_thread_assist.c @@ -85,7 +85,7 @@ int ossl_quic_thread_assist_stop_async(QUIC_THREAD_ASSIST *qta) { if (!qta->teardown) { qta->teardown = 1; - ossl_crypto_condvar_broadcast(qta->cv); + ossl_crypto_condvar_signal(qta->cv); } return 1; @@ -133,11 +133,7 @@ int ossl_quic_thread_assist_notify_deadline_changed(QUIC_THREAD_ASSIST *qta) if (qta->teardown) return 0; - /* - * Wake-one would be better here but as there is only one listening thread - * this does not actually matter. - */ - ossl_crypto_condvar_broadcast(qta->cv); + ossl_crypto_condvar_signal(qta->cv); return 1; } diff --git a/test/quic_tserver_test.c b/test/quic_tserver_test.c index e5391648a3..359b66c1b2 100644 --- a/test/quic_tserver_test.c +++ b/test/quic_tserver_test.c @@ -324,9 +324,10 @@ static int do_test(int use_thread_assist, int use_fake_time, int use_inject) * This is inefficient because we spin until things work without * blocking but this is just a test. */ - if (!c_start_idle_test || c_done_idle_test) + if (!c_start_idle_test || c_done_idle_test) { /* Inhibit manual ticking during idle test to test TA mode. */ SSL_tick(c_ssl); + } ossl_quic_tserver_tick(tserver); -- 2.34.1