Adding in curl and openssl repos

This commit is contained in:
2025-08-14 12:09:30 -04:00
parent af2117b574
commit 0ace93e303
21174 changed files with 3607720 additions and 2 deletions

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/configuration.h>
#include <openssl/thread.h>
#include <internal/thread.h>
uint32_t OSSL_get_thread_support_flags(void)
{
int support = 0;
#if !defined(OPENSSL_NO_THREAD_POOL)
support |= OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL;
#endif
#if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
support |= OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN;
#endif
return support;
}
#if defined(OPENSSL_NO_THREAD_POOL) || defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
int OSSL_set_max_threads(OSSL_LIB_CTX *ctx, uint64_t max_threads)
{
return 0;
}
uint64_t OSSL_get_max_threads(OSSL_LIB_CTX *ctx)
{
return 0;
}
#else
uint64_t OSSL_get_max_threads(OSSL_LIB_CTX *ctx)
{
uint64_t ret = 0;
OSSL_LIB_CTX_THREADS *tdata = OSSL_LIB_CTX_GET_THREADS(ctx);
if (tdata == NULL)
goto fail;
ossl_crypto_mutex_lock(tdata->lock);
ret = tdata->max_threads;
ossl_crypto_mutex_unlock(tdata->lock);
fail:
return ret;
}
int OSSL_set_max_threads(OSSL_LIB_CTX *ctx, uint64_t max_threads)
{
OSSL_LIB_CTX_THREADS *tdata;
tdata = OSSL_LIB_CTX_GET_THREADS(ctx);
if (tdata == NULL)
return 0;
ossl_crypto_mutex_lock(tdata->lock);
tdata->max_threads = max_threads;
ossl_crypto_mutex_unlock(tdata->lock);
return 1;
}
#endif

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/configuration.h>
#include <internal/thread_arch.h>
CRYPTO_THREAD *ossl_crypto_thread_native_start(CRYPTO_THREAD_ROUTINE routine,
void *data, int joinable)
{
CRYPTO_THREAD *handle;
if (routine == NULL)
return NULL;
handle = OPENSSL_zalloc(sizeof(*handle));
if (handle == NULL)
return NULL;
if ((handle->lock = ossl_crypto_mutex_new()) == NULL)
goto fail;
if ((handle->statelock = ossl_crypto_mutex_new()) == NULL)
goto fail;
if ((handle->condvar = ossl_crypto_condvar_new()) == NULL)
goto fail;
handle->data = data;
handle->routine = routine;
handle->joinable = joinable;
if (ossl_crypto_thread_native_spawn(handle) == 1)
return handle;
fail:
ossl_crypto_condvar_free(&handle->condvar);
ossl_crypto_mutex_free(&handle->statelock);
ossl_crypto_mutex_free(&handle->lock);
OPENSSL_free(handle);
return NULL;
}
int ossl_crypto_thread_native_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
{
uint64_t req_state_mask;
if (thread == NULL)
return 0;
ossl_crypto_mutex_lock(thread->statelock);
req_state_mask = CRYPTO_THREAD_FINISHED | CRYPTO_THREAD_JOINED;
while (!CRYPTO_THREAD_GET_STATE(thread, req_state_mask))
ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
goto pass;
/* Await concurrent join completion, if any. */
while (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT)) {
if (!CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
goto pass;
}
CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
ossl_crypto_mutex_unlock(thread->statelock);
if (ossl_crypto_thread_native_perform_join(thread, retval) == 0)
goto fail;
ossl_crypto_mutex_lock(thread->statelock);
pass:
CRYPTO_THREAD_UNSET_ERROR(thread, CRYPTO_THREAD_JOINED);
CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOINED);
/*
* Signal join completion. It is important to signal even if we haven't
* performed an actual join. Multiple threads could be awaiting the
* CRYPTO_THREAD_JOIN_AWAIT -> CRYPTO_THREAD_JOINED transition, but signal
* on actual join would wake only one. Signalling here will always wake one.
*/
ossl_crypto_condvar_signal(thread->condvar);
ossl_crypto_mutex_unlock(thread->statelock);
if (retval != NULL)
*retval = thread->retval;
return 1;
fail:
ossl_crypto_mutex_lock(thread->statelock);
CRYPTO_THREAD_SET_ERROR(thread, CRYPTO_THREAD_JOINED);
/* Have another thread that's awaiting join retry to avoid that
* thread deadlock. */
CRYPTO_THREAD_UNSET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
ossl_crypto_condvar_signal(thread->condvar);
ossl_crypto_mutex_unlock(thread->statelock);
return 0;
}
int ossl_crypto_thread_native_clean(CRYPTO_THREAD *handle)
{
uint64_t req_state_mask;
if (handle == NULL)
return 0;
req_state_mask = 0;
req_state_mask |= CRYPTO_THREAD_FINISHED;
req_state_mask |= CRYPTO_THREAD_JOINED;
ossl_crypto_mutex_lock(handle->statelock);
if (CRYPTO_THREAD_GET_STATE(handle, req_state_mask) == 0) {
ossl_crypto_mutex_unlock(handle->statelock);
return 0;
}
ossl_crypto_mutex_unlock(handle->statelock);
ossl_crypto_mutex_free(&handle->lock);
ossl_crypto_mutex_free(&handle->statelock);
ossl_crypto_condvar_free(&handle->condvar);
OPENSSL_free(handle->handle);
OPENSSL_free(handle);
return 1;
}

View File

@@ -0,0 +1,11 @@
crypto/thread/arch/libcrypto-lib-thread_none.o: \
crypto/thread/arch/thread_none.c include/internal/thread_arch.h \
include/openssl/configuration.h include/openssl/e_os2.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/opensslv.h include/internal/time.h \
include/internal/e_os.h include/openssl/crypto.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/types.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/numbers.h \
include/internal/safe_math.h

View File

@@ -0,0 +1,11 @@
crypto/thread/arch/libcrypto-lib-thread_posix.o: \
crypto/thread/arch/thread_posix.c include/internal/thread_arch.h \
include/openssl/configuration.h include/openssl/e_os2.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/opensslv.h include/internal/time.h \
include/internal/e_os.h include/openssl/crypto.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/types.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/numbers.h \
include/internal/safe_math.h

View File

@@ -0,0 +1,11 @@
crypto/thread/arch/libcrypto-lib-thread_win.o: \
crypto/thread/arch/thread_win.c include/internal/thread_arch.h \
include/openssl/configuration.h include/openssl/e_os2.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/opensslv.h include/internal/time.h \
include/internal/e_os.h include/openssl/crypto.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/types.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/numbers.h \
include/internal/safe_math.h

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <internal/thread_arch.h>
#if defined(OPENSSL_THREADS_NONE)
int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
{
return 0;
}
int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
{
return 0;
}
int ossl_crypto_thread_native_exit(void)
{
return 0;
}
int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
{
return 0;
}
CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
{
return NULL;
}
void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
{
}
int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
{
return 0;
}
void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
{
}
void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
{
}
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
return NULL;
}
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)
{
}
#endif

View File

@@ -0,0 +1,233 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <internal/thread_arch.h>
#if defined(OPENSSL_THREADS_POSIX)
# define _GNU_SOURCE
# include <errno.h>
# include <sys/types.h>
# include <unistd.h>
static void *thread_start_thunk(void *vthread)
{
CRYPTO_THREAD *thread;
CRYPTO_THREAD_RETVAL ret;
thread = (CRYPTO_THREAD *)vthread;
ret = thread->routine(thread->data);
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_mutex_unlock(thread->statelock);
return NULL;
}
int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
{
int ret;
pthread_attr_t attr;
pthread_t *handle;
handle = OPENSSL_zalloc(sizeof(*handle));
if (handle == NULL)
goto fail;
pthread_attr_init(&attr);
if (!thread->joinable)
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(handle, &attr, thread_start_thunk, thread);
pthread_attr_destroy(&attr);
if (ret != 0)
goto fail;
thread->handle = handle;
return 1;
fail:
thread->handle = NULL;
OPENSSL_free(handle);
return 0;
}
int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
{
void *thread_retval;
pthread_t *handle;
if (thread == NULL || thread->handle == NULL)
return 0;
handle = (pthread_t *) thread->handle;
if (pthread_join(*handle, &thread_retval) != 0)
return 0;
/*
* Join return value may be non-NULL when the thread has been cancelled,
* as indicated by thread_retval set to PTHREAD_CANCELLED.
*/
if (thread_retval != NULL)
return 0;
return 1;
}
int ossl_crypto_thread_native_exit(void)
{
pthread_exit(NULL);
return 1;
}
int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
{
return pthread_equal(*(pthread_t *)thread->handle, pthread_self());
}
CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
{
pthread_mutex_t *mutex;
if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL)
return NULL;
if (pthread_mutex_init(mutex, NULL) != 0) {
OPENSSL_free(mutex);
return NULL;
}
return (CRYPTO_MUTEX *)mutex;
}
int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
{
pthread_mutex_t *mutex_p;
mutex_p = (pthread_mutex_t *)mutex;
if (pthread_mutex_trylock(mutex_p) == EBUSY)
return 0;
return 1;
}
void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
{
int rc;
pthread_mutex_t *mutex_p;
mutex_p = (pthread_mutex_t *)mutex;
rc = pthread_mutex_lock(mutex_p);
OPENSSL_assert(rc == 0);
}
void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
{
int rc;
pthread_mutex_t *mutex_p;
mutex_p = (pthread_mutex_t *)mutex;
rc = pthread_mutex_unlock(mutex_p);
OPENSSL_assert(rc == 0);
}
void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
{
pthread_mutex_t **mutex_p;
if (mutex == NULL)
return;
mutex_p = (pthread_mutex_t **)mutex;
if (*mutex_p != NULL)
pthread_mutex_destroy(*mutex_p);
OPENSSL_free(*mutex_p);
*mutex = NULL;
}
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
pthread_cond_t *cv_p;
if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL)
return NULL;
if (pthread_cond_init(cv_p, NULL) != 0) {
OPENSSL_free(cv_p);
return NULL;
}
return (CRYPTO_CONDVAR *) cv_p;
}
void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
{
pthread_cond_t *cv_p;
pthread_mutex_t *mutex_p;
cv_p = (pthread_cond_t *)cv;
mutex_p = (pthread_mutex_t *)mutex;
pthread_cond_wait(cv_p, mutex_p);
}
void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
OSSL_TIME deadline)
{
pthread_cond_t *cv_p = (pthread_cond_t *)cv;
pthread_mutex_t *mutex_p = (pthread_mutex_t *)mutex;
if (ossl_time_is_infinite(deadline)) {
/*
* No deadline. Some pthread implementations allow
* pthread_cond_timedwait to work the same as pthread_cond_wait when
* abstime is NULL, but it is unclear whether this is POSIXly correct.
*/
pthread_cond_wait(cv_p, mutex_p);
} else {
struct timespec deadline_ts;
deadline_ts.tv_sec
= ossl_time2seconds(deadline);
deadline_ts.tv_nsec
= (ossl_time2ticks(deadline) % OSSL_TIME_SECOND) / OSSL_TIME_NS;
pthread_cond_timedwait(cv_p, mutex_p, &deadline_ts);
}
}
void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
{
pthread_cond_t *cv_p;
cv_p = (pthread_cond_t *)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;
if (cv == NULL)
return;
cv_p = (pthread_cond_t **)cv;
if (*cv_p != NULL)
pthread_cond_destroy(*cv_p);
OPENSSL_free(*cv_p);
*cv_p = NULL;
}
#endif

View File

@@ -0,0 +1,599 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <internal/thread_arch.h>
#if defined(OPENSSL_THREADS_WINNT)
# include <process.h>
# include <windows.h>
static unsigned __stdcall thread_start_thunk(LPVOID vthread)
{
CRYPTO_THREAD *thread;
CRYPTO_THREAD_RETVAL ret;
thread = (CRYPTO_THREAD *)vthread;
thread->thread_id = GetCurrentThreadId();
ret = thread->routine(thread->data);
ossl_crypto_mutex_lock(thread->statelock);
CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_FINISHED);
thread->retval = ret;
ossl_crypto_condvar_signal(thread->condvar);
ossl_crypto_mutex_unlock(thread->statelock);
return 0;
}
int ossl_crypto_thread_native_spawn(CRYPTO_THREAD *thread)
{
HANDLE *handle;
handle = OPENSSL_zalloc(sizeof(*handle));
if (handle == NULL)
goto fail;
*handle = (HANDLE)_beginthreadex(NULL, 0, &thread_start_thunk, thread, 0, NULL);
if (*handle == NULL)
goto fail;
thread->handle = handle;
return 1;
fail:
thread->handle = NULL;
OPENSSL_free(handle);
return 0;
}
int ossl_crypto_thread_native_perform_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
{
DWORD thread_retval;
HANDLE *handle;
if (thread == NULL || thread->handle == NULL)
return 0;
handle = (HANDLE *) thread->handle;
if (WaitForSingleObject(*handle, INFINITE) != WAIT_OBJECT_0)
return 0;
if (GetExitCodeThread(*handle, &thread_retval) == 0)
return 0;
/*
* GetExitCodeThread call followed by this check is to make sure that
* the thread exited properly. In particular, thread_retval may be
* non-zero when exited via explicit ExitThread/TerminateThread or
* if the thread is still active (returns STILL_ACTIVE (259)).
*/
if (thread_retval != 0)
return 0;
if (CloseHandle(*handle) == 0)
return 0;
return 1;
}
int ossl_crypto_thread_native_exit(void)
{
_endthreadex(0);
return 1;
}
int ossl_crypto_thread_native_is_self(CRYPTO_THREAD *thread)
{
return thread->thread_id == GetCurrentThreadId();
}
CRYPTO_MUTEX *ossl_crypto_mutex_new(void)
{
CRITICAL_SECTION *mutex;
if ((mutex = OPENSSL_zalloc(sizeof(*mutex))) == NULL)
return NULL;
InitializeCriticalSection(mutex);
return (CRYPTO_MUTEX *)mutex;
}
void ossl_crypto_mutex_lock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
EnterCriticalSection(mutex_p);
}
int ossl_crypto_mutex_try_lock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
if (TryEnterCriticalSection(mutex_p))
return 1;
return 0;
}
void ossl_crypto_mutex_unlock(CRYPTO_MUTEX *mutex)
{
CRITICAL_SECTION *mutex_p;
mutex_p = (CRITICAL_SECTION *)mutex;
LeaveCriticalSection(mutex_p);
}
void ossl_crypto_mutex_free(CRYPTO_MUTEX **mutex)
{
CRITICAL_SECTION **mutex_p;
mutex_p = (CRITICAL_SECTION **)mutex;
if (*mutex_p != NULL)
DeleteCriticalSection(*mutex_p);
OPENSSL_free(*mutex_p);
*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)
# include <assert.h>
/*
* Win32, before Vista, did not have an OS-provided condition variable
* construct. This leads to the need to construct our own condition variable
* construct in order to support Windows XP.
*
* It is difficult to construct a condition variable construct using the
* OS-provided primitives in a way that is both correct (avoiding race
* conditions where broadcasts get lost) and fair.
*
* CORRECTNESS:
* A blocked thread is a thread which is calling wait(), between the
* precise instants at which the external mutex passed to wait() is
* unlocked and the instant at which it is relocked.
*
* a)
* - If broadcast() is called, ALL blocked threads MUST be unblocked.
* - If signal() is called, at least one blocked thread MUST be unblocked.
*
* (i.e.: a signal or broadcast must never get 'lost')
*
* b)
* - If broadcast() or signal() is called, this must not cause a thread
* which is not blocked to return immediately from a subsequent
* call to wait().
*
* FAIRNESS:
* If broadcast() is called at time T1, all blocked threads must be unblocked
* before any thread which subsequently calls wait() at time T2 > T1 is
* unblocked.
*
* An example of an implementation which lacks fairness is as follows:
*
* t1 enters wait()
* t2 enters wait()
*
* tZ calls broadcast()
*
* t1 exits wait()
* t1 enters wait()
*
* tZ calls broadcast()
*
* t1 exits wait()
*
* IMPLEMENTATION:
*
* The most suitable primitives available to us in Windows XP are semaphores,
* auto-reset events and manual-reset events. A solution based on semaphores
* is chosen.
*
* PROBLEM. Designing a solution based on semaphores is non-trivial because,
* while it is easy to track the number of waiters in an interlocked data
* structure and then add that number to the semaphore, this does not
* guarantee fairness or correctness. Consider the following situation:
*
* - t1 enters wait(), adding 1 to the wait counter & blocks on the semaphore
* - t2 enters wait(), adding 1 to the wait counter & blocks on the semaphore
* - tZ calls broadcast(), finds the wait counter is 2, adds 2 to the semaphore
*
* - t1 exits wait()
* - t1 immediately reenters wait() and blocks on the semaphore
* - The semaphore is still positive due to also having been signalled
* for t2, therefore it is decremented
* - t1 exits wait() immediately; t2 is never woken
*
* GENERATION COUNTERS. One naive solution to this is to use a generation
* counter. Each broadcast() invocation increments a generation counter. If
* the generation counter has not changed during a semaphore wait operation
* inside wait(), this indicates that no broadcast() call has been made in
* the meantime; therefore, the successful semaphore decrement must have
* 'stolen' a wakeup from another thread which was waiting to wakeup from the
* prior broadcast() call but which had not yet had a chance to do so. The
* semaphore can then be reincremented and the wait() operation repeated.
*
* However, this suffers from the obvious problem that without OS guarantees
* as to how semaphore readiness events are distributed amongst threads,
* there is no particular guarantee that the semaphore readiness event will
* not be immediately redistributed back to the same thread t1.
*
* SOLUTION. A solution is chosen as follows. In its initial state, a
* condition variable can accept waiters, who wait for the semaphore
* normally. However, once broadcast() is called, the condition
* variable becomes 'closed'. Any existing blocked threads are unblocked,
* but any new calls to wait() will instead enter a blocking pre-wait stage.
* Pre-wait threads are not considered to be waiting (and the external
* mutex remains held). A call to wait() in pre-wait cannot progress
* to waiting until all threads due to be unblocked by the prior broadcast()
* call have returned and had a chance to execute.
*
* This pre-wait does not affect a thread if it does not call wait()
* again until after all threads have had a chance to execute.
*
* RESOURCE USAGE. Aside from an allocation for the condition variable
* structure, this solution uses two Win32 semaphores.
*
* FUTURE OPTIMISATIONS:
*
* An optimised multi-generation implementation is possible at the cost of
* higher Win32 resource usage. Multiple 'buckets' could be defined, with
* usage rotating between buckets internally as buckets become closed.
* This would avoid the need for the prewait in more cases, depending
* on intensity of usage.
*
*/
typedef struct legacy_condvar_st {
CRYPTO_MUTEX *int_m; /* internal mutex */
HANDLE sema; /* main wait semaphore */
HANDLE prewait_sema; /* prewait semaphore */
/*
* All of the following fields are protected by int_m.
*
* num_wake only ever increases by virtue of a corresponding decrease in
* num_wait. num_wait can decrease for other reasons (for example due to a
* wait operation timing out).
*/
size_t num_wait; /* Num. threads currently blocked */
size_t num_wake; /* Num. threads due to wake up */
size_t num_prewait; /* Num. threads in prewait */
size_t gen; /* Prewait generation */
int closed; /* Is closed? */
} LEGACY_CONDVAR;
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
LEGACY_CONDVAR *cv;
if ((cv = OPENSSL_malloc(sizeof(LEGACY_CONDVAR))) == NULL)
return NULL;
if ((cv->int_m = ossl_crypto_mutex_new()) == NULL) {
OPENSSL_free(cv);
return NULL;
}
if ((cv->sema = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL)) == NULL) {
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
return NULL;
}
if ((cv->prewait_sema = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL)) == NULL) {
CloseHandle(cv->sema);
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
return NULL;
}
cv->num_wait = 0;
cv->num_wake = 0;
cv->num_prewait = 0;
cv->closed = 0;
return (CRYPTO_CONDVAR *)cv;
}
void ossl_crypto_condvar_free(CRYPTO_CONDVAR **cv_p)
{
if (*cv_p != NULL) {
LEGACY_CONDVAR *cv = *(LEGACY_CONDVAR **)cv_p;
CloseHandle(cv->sema);
CloseHandle(cv->prewait_sema);
ossl_crypto_mutex_free(&cv->int_m);
OPENSSL_free(cv);
}
*cv_p = NULL;
}
static uint32_t obj_wait(HANDLE h, OSSL_TIME deadline)
{
DWORD timeout;
if (!determine_timeout(deadline, &timeout))
timeout = 1;
return WaitForSingleObject(h, timeout);
}
void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv_, CRYPTO_MUTEX *ext_m,
OSSL_TIME deadline)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
int closed, set_prewait = 0, have_orig_gen = 0;
uint32_t rc;
size_t orig_gen;
/* Admission control - prewait until we can enter our actual wait phase. */
do {
ossl_crypto_mutex_lock(cv->int_m);
closed = cv->closed;
/*
* Once prewait is over the prewait semaphore is signalled and
* num_prewait is set to 0. Use a generation counter to track if we need
* to remove a value we added to num_prewait when exiting (e.g. due to
* timeout or failure of WaitForSingleObject).
*/
if (!have_orig_gen) {
orig_gen = cv->gen;
have_orig_gen = 1;
} else if (cv->gen != orig_gen) {
set_prewait = 0;
orig_gen = cv->gen;
}
if (!closed) {
/* We can now be admitted. */
++cv->num_wait;
if (set_prewait) {
--cv->num_prewait;
set_prewait = 0;
}
} else if (!set_prewait) {
++cv->num_prewait;
set_prewait = 1;
}
ossl_crypto_mutex_unlock(cv->int_m);
if (closed)
if (obj_wait(cv->prewait_sema, deadline) != WAIT_OBJECT_0) {
/*
* If we got WAIT_OBJECT_0 we are safe - num_prewait has been
* set to 0 and the semaphore has been consumed. On the other
* hand if we timed out, there may be a residual posting that
* was made just after we timed out. However in the worst case
* this will just cause an internal spurious wakeup here in the
* future, so we do not care too much about this. We treat
* failure and timeout cases as the same, and simply exit in
* this case.
*/
ossl_crypto_mutex_lock(cv->int_m);
if (set_prewait && cv->gen == orig_gen)
--cv->num_prewait;
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
} while (closed);
/*
* Unlock external mutex. Do not do this until we have been admitted, as we
* must guarantee we wake if broadcast is called at any time after ext_m is
* unlocked.
*/
ossl_crypto_mutex_unlock(ext_m);
for (;;) {
/* Wait. */
rc = obj_wait(cv->sema, deadline);
/* Reacquire internal mutex and probe state. */
ossl_crypto_mutex_lock(cv->int_m);
if (cv->num_wake > 0) {
/*
* A wake token is available, so we can wake up. Consume the token
* and get out of here. We don't care what WaitForSingleObject
* returned here (e.g. if it timed out coincidentally). In the
* latter case a signal might be left in the semaphore which causes
* a future WaitForSingleObject call to return immediately, but in
* this case we will just loop again.
*/
--cv->num_wake;
if (cv->num_wake == 0 && cv->closed) {
/*
* We consumed the last wake token, so we can now open the
* condition variable for new admissions.
*/
cv->closed = 0;
if (cv->num_prewait > 0) {
ReleaseSemaphore(cv->prewait_sema, (LONG)cv->num_prewait, NULL);
cv->num_prewait = 0;
++cv->gen;
}
}
} else if (rc == WAIT_OBJECT_0) {
/*
* We got a wakeup from the semaphore but we did not have any wake
* tokens. This ideally does not happen, but might if during a
* previous wait() call the semaphore is posted just after
* WaitForSingleObject returns due to a timeout (such that the
* num_wake > 0 case is taken above). Just spin again. (It is worth
* noting that repeated WaitForSingleObject calls is the only method
* documented for decrementing a Win32 semaphore, so this is
* basically the best possible strategy.)
*/
ossl_crypto_mutex_unlock(cv->int_m);
continue;
} else {
/*
* Assume we timed out. The WaitForSingleObject call may also have
* failed for some other reason, which we treat as a timeout.
*/
assert(cv->num_wait > 0);
--cv->num_wait;
}
break;
}
ossl_crypto_mutex_unlock(cv->int_m);
ossl_crypto_mutex_lock(ext_m);
}
void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *ext_m)
{
ossl_crypto_condvar_wait_timeout(cv, ext_m, ossl_time_infinite());
}
void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv_)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
size_t num_wake;
ossl_crypto_mutex_lock(cv->int_m);
num_wake = cv->num_wait;
if (num_wake == 0) {
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
cv->num_wake += num_wake;
cv->num_wait -= num_wake;
cv->closed = 1;
ossl_crypto_mutex_unlock(cv->int_m);
ReleaseSemaphore(cv->sema, num_wake, NULL);
}
void ossl_crypto_condvar_signal(CRYPTO_CONDVAR *cv_)
{
LEGACY_CONDVAR *cv = (LEGACY_CONDVAR *)cv_;
ossl_crypto_mutex_lock(cv->int_m);
if (cv->num_wait == 0) {
ossl_crypto_mutex_unlock(cv->int_m);
return;
}
/*
* We do not close the condition variable when merely signalling, as there
* are no guaranteed fairness semantics here, unlike for a broadcast.
*/
--cv->num_wait;
++cv->num_wake;
ossl_crypto_mutex_unlock(cv->int_m);
ReleaseSemaphore(cv->sema, 1, NULL);
}
# else
CRYPTO_CONDVAR *ossl_crypto_condvar_new(void)
{
CONDITION_VARIABLE *cv_p;
if ((cv_p = OPENSSL_zalloc(sizeof(*cv_p))) == NULL)
return NULL;
InitializeConditionVariable(cv_p);
return (CRYPTO_CONDVAR *)cv_p;
}
void ossl_crypto_condvar_wait(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex)
{
CONDITION_VARIABLE *cv_p;
CRITICAL_SECTION *mutex_p;
cv_p = (CONDITION_VARIABLE *)cv;
mutex_p = (CRITICAL_SECTION *)mutex;
SleepConditionVariableCS(cv_p, mutex_p, INFINITE);
}
void ossl_crypto_condvar_wait_timeout(CRYPTO_CONDVAR *cv, CRYPTO_MUTEX *mutex,
OSSL_TIME deadline)
{
DWORD timeout;
CONDITION_VARIABLE *cv_p = (CONDITION_VARIABLE *)cv;
CRITICAL_SECTION *mutex_p = (CRITICAL_SECTION *)mutex;
if (!determine_timeout(deadline, &timeout))
timeout = 1;
SleepConditionVariableCS(cv_p, mutex_p, timeout);
}
void ossl_crypto_condvar_broadcast(CRYPTO_CONDVAR *cv)
{
CONDITION_VARIABLE *cv_p;
cv_p = (CONDITION_VARIABLE *)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;
cv_p = (CONDITION_VARIABLE **)cv;
OPENSSL_free(*cv_p);
*cv_p = NULL;
}
# endif
void ossl_crypto_mem_barrier(void)
{
MemoryBarrier();
}
#endif

View File

@@ -0,0 +1,21 @@
LIBS=../../libcrypto
$THREADS_ARCH=\
arch.c \
arch/thread_win.c arch/thread_posix.c arch/thread_none.c
IF[{- !$disabled{'thread-pool'} -}]
IF[{- !$disabled{quic} -}]
SHARED_SOURCE[../../libssl]=$THREADS_ARCH
ENDIF
$THREADS=\
api.c internal.c $THREADS_ARCH
ELSE
IF[{- !$disabled{quic} -}]
SOURCE[../../libssl]=$THREADS_ARCH
ENDIF
$THREADS=api.c arch/thread_win.c
ENDIF
SOURCE[../../libcrypto]=$THREADS
SOURCE[../../providers/libfips.a]=$THREADS

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/configuration.h>
#include <openssl/e_os2.h>
#include <openssl/types.h>
#include <openssl/crypto.h>
#include <internal/thread.h>
#include <internal/thread_arch.h>
#if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
static ossl_inline uint64_t _ossl_get_avail_threads(OSSL_LIB_CTX_THREADS *tdata)
{
/* assumes that tdata->lock is taken */
return tdata->max_threads - tdata->active_threads;
}
uint64_t ossl_get_avail_threads(OSSL_LIB_CTX *ctx)
{
uint64_t retval = 0;
OSSL_LIB_CTX_THREADS *tdata = OSSL_LIB_CTX_GET_THREADS(ctx);
if (tdata == NULL)
return retval;
ossl_crypto_mutex_lock(tdata->lock);
retval = _ossl_get_avail_threads(tdata);
ossl_crypto_mutex_unlock(tdata->lock);
return retval;
}
void *ossl_crypto_thread_start(OSSL_LIB_CTX *ctx, CRYPTO_THREAD_ROUTINE start,
void *data)
{
CRYPTO_THREAD *thread;
OSSL_LIB_CTX_THREADS *tdata = OSSL_LIB_CTX_GET_THREADS(ctx);
if (tdata == NULL)
return NULL;
ossl_crypto_mutex_lock(tdata->lock);
if (tdata == NULL || tdata->max_threads == 0) {
ossl_crypto_mutex_unlock(tdata->lock);
return NULL;
}
while (_ossl_get_avail_threads(tdata) == 0)
ossl_crypto_condvar_wait(tdata->cond_finished, tdata->lock);
tdata->active_threads++;
ossl_crypto_mutex_unlock(tdata->lock);
thread = ossl_crypto_thread_native_start(start, data, 1);
if (thread == NULL) {
ossl_crypto_mutex_lock(tdata->lock);
tdata->active_threads--;
ossl_crypto_mutex_unlock(tdata->lock);
goto fail;
}
thread->ctx = ctx;
fail:
return (void *) thread;
}
int ossl_crypto_thread_join(void *vhandle, CRYPTO_THREAD_RETVAL *retval)
{
CRYPTO_THREAD *handle = vhandle;
OSSL_LIB_CTX_THREADS *tdata;
if (vhandle == NULL)
return 0;
tdata = OSSL_LIB_CTX_GET_THREADS(handle->ctx);
if (tdata == NULL)
return 0;
if (ossl_crypto_thread_native_join(handle, retval) == 0)
return 0;
ossl_crypto_mutex_lock(tdata->lock);
tdata->active_threads--;
ossl_crypto_condvar_signal(tdata->cond_finished);
ossl_crypto_mutex_unlock(tdata->lock);
return 1;
}
int ossl_crypto_thread_clean(void *vhandle)
{
CRYPTO_THREAD *handle = vhandle;
return ossl_crypto_thread_native_clean(handle);
}
#else
ossl_inline uint64_t ossl_get_avail_threads(OSSL_LIB_CTX *ctx)
{
return 0;
}
void *ossl_crypto_thread_start(OSSL_LIB_CTX *ctx, CRYPTO_THREAD_ROUTINE start,
void *data)
{
return NULL;
}
int ossl_crypto_thread_join(void *vhandle, CRYPTO_THREAD_RETVAL *retval)
{
return 0;
}
int ossl_crypto_thread_clean(void *vhandle)
{
return 0;
}
#endif
void *ossl_threads_ctx_new(OSSL_LIB_CTX *ctx)
{
struct openssl_threads_st *t = OPENSSL_zalloc(sizeof(*t));
if (t == NULL)
return NULL;
t->lock = ossl_crypto_mutex_new();
t->cond_finished = ossl_crypto_condvar_new();
if (t->lock == NULL || t->cond_finished == NULL)
goto fail;
return t;
fail:
ossl_threads_ctx_free((void *)t);
return NULL;
}
void ossl_threads_ctx_free(void *vdata)
{
OSSL_LIB_CTX_THREADS *t = (OSSL_LIB_CTX_THREADS *) vdata;
if (t == NULL)
return;
ossl_crypto_mutex_free(&t->lock);
ossl_crypto_condvar_free(&t->cond_finished);
OPENSSL_free(t);
}

View File

@@ -0,0 +1,16 @@
crypto/thread/libcrypto-lib-api.o: crypto/thread/api.c \
include/openssl/configuration.h include/openssl/thread.h \
include/openssl/types.h include/openssl/e_os2.h include/openssl/macros.h \
include/openssl/opensslconf.h include/openssl/opensslv.h \
include/openssl/safestack.h include/openssl/stack.h \
include/internal/thread.h include/internal/thread_arch.h \
include/internal/time.h include/internal/e_os.h include/openssl/crypto.h \
include/openssl/cryptoerr.h include/openssl/symhacks.h \
include/openssl/cryptoerr_legacy.h include/openssl/core.h \
include/internal/numbers.h include/internal/safe_math.h \
include/internal/cryptlib.h include/internal/common.h \
include/internal/nelem.h include/openssl/buffer.h \
include/openssl/buffererr.h include/openssl/bio.h \
include/openssl/bioerr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/openssl/err.h include/openssl/lhash.h include/crypto/context.h

View File

@@ -0,0 +1,10 @@
crypto/thread/libcrypto-lib-arch.o: crypto/thread/arch.c \
include/openssl/configuration.h include/internal/thread_arch.h \
include/openssl/e_os2.h include/openssl/macros.h \
include/openssl/opensslconf.h include/openssl/opensslv.h \
include/internal/time.h include/internal/e_os.h include/openssl/crypto.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/types.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/numbers.h \
include/internal/safe_math.h

View File

@@ -0,0 +1,16 @@
crypto/thread/libcrypto-lib-internal.o: crypto/thread/internal.c \
include/openssl/configuration.h include/openssl/e_os2.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/opensslv.h include/openssl/types.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/crypto.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/thread.h \
include/internal/thread_arch.h include/internal/time.h \
include/internal/e_os.h include/internal/numbers.h \
include/internal/safe_math.h include/internal/cryptlib.h \
include/internal/common.h include/internal/nelem.h \
include/openssl/buffer.h include/openssl/buffererr.h \
include/openssl/bio.h include/openssl/bioerr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/openssl/err.h include/openssl/lhash.h include/crypto/context.h