Implement new multi-threading API

Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
This commit is contained in:
Alessandro Ghedini 2015-10-25 17:43:55 +01:00 committed by Matt Caswell
parent bdcd83e127
commit 71a04cfca0
14 changed files with 976 additions and 162 deletions

View File

@ -34,9 +34,11 @@ LIB= $(TOP)/libcrypto.a
SHARED_LIB= libcrypto$(SHLIB_EXT)
LIBSRC= cryptlib.c mem.c mem_clr.c mem_dbg.c cversion.c ex_data.c cpt_err.c \
ebcdic.c uid.c o_time.c o_str.c o_dir.c thr_id.c lock.c \
threads_pthread.c threads_win.c threads_none.c \
o_init.c o_fips.c mem_sec.c init.c
LIBOBJ= cryptlib.o mem.o mem_dbg.o cversion.o ex_data.o cpt_err.o \
ebcdic.o uid.o o_time.o o_str.o o_dir.o thr_id.o lock.o \
threads_pthread.o threads_win.o threads_none.o \
o_init.o o_fips.o mem_sec.o init.o $(CPUID_OBJ)
SRC= $(LIBSRC)

View File

@ -3,6 +3,7 @@ LIBS=../libcrypto
SOURCE[../libcrypto]=\
cryptlib.c mem.c mem_dbg.c cversion.c ex_data.c cpt_err.c \
ebcdic.c uid.c o_time.c o_str.c o_dir.c thr_id.c lock.c \
threads_pthread.c threads_win.c threads_none.c \
o_init.c o_fips.c mem_sec.c init.c {- $target{cpuid_asm_src} -}
EXTRA= ../ms/uplink-x86.pl ../ms/uplink.c ../ms/applink.c \
x86cpuid.pl x86_64cpuid.pl ia64cpuid.S \

165
crypto/threads_none.c Normal file
View File

@ -0,0 +1,165 @@
/* ====================================================================
* Copyright (c) 2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/crypto.h>
#include "internal/threads.h"
#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
{
CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(unsigned int));
if (lock == NULL)
return NULL;
*(unsigned int *)lock = 1;
return lock;
}
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
{
OPENSSL_assert(*(unsigned int *)lock == 1);
return 1;
}
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
{
OPENSSL_assert(*(unsigned int *)lock == 1);
return 1;
}
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
{
OPENSSL_assert(*(unsigned int *)lock == 1);
return 1;
}
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock) {
if (lock == NULL)
return;
*(unsigned int *)lock = 0;
OPENSSL_free(lock);
return;
}
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
{
if (*once != 0)
return 1;
init();
*once = 1;
return 1;
}
#define OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX 256
static void *thread_local_storage[OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX];
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
{
static unsigned int thread_local_key = 0;
if (thread_local_key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
return 0;
*key = thread_local_key++;
thread_local_storage[*key] = NULL;
return 1;
}
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
{
if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
return NULL;
return thread_local_storage[*key];
}
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
{
if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
return 0;
thread_local_storage[*key] = val;
return 1;
}
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
{
*key = OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX + 1;
return 1;
}
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
{
return 0;
}
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
{
return (a == b);
}
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
{
*val += amount;
*ret = *val;
return 1;
}
#endif

167
crypto/threads_pthread.c Normal file
View File

@ -0,0 +1,167 @@
/* ====================================================================
* Copyright (c) 2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/crypto.h>
#include "internal/threads.h"
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
{
CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t));
if (lock == NULL)
return NULL;
if (pthread_rwlock_init(lock, NULL) != 0)
return NULL;
return lock;
}
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
{
if (pthread_rwlock_rdlock(lock) != 0)
return 0;
return 1;
}
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
{
if (pthread_rwlock_wrlock(lock) != 0)
return 0;
return 1;
}
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
{
if (pthread_rwlock_unlock(lock) != 0)
return 0;
return 1;
}
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
{
if (lock == NULL)
return;
pthread_rwlock_destroy(lock);
OPENSSL_free(lock);
return;
}
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
{
if (pthread_once(once, init) != 0)
return 0;
return 1;
}
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
{
if (pthread_key_create(key, cleanup) != 0)
return 0;
return 1;
}
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
{
return pthread_getspecific(*key);
}
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
{
if (pthread_setspecific(*key, val) != 0)
return 0;
return 1;
}
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
{
if (pthread_key_delete(*key) != 0)
return 0;
return 1;
}
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
{
return pthread_self();
}
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
{
return pthread_equal(a, b);
}
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
{
#ifdef __ATOMIC_RELAXED
*ret = __atomic_add_fetch(val, amount, __ATOMIC_RELAXED);
#else
if (!CRYPTO_THREAD_write_lock(lock))
return 0;
*val += amount;
*ret = *val;
if (!CRYPTO_THREAD_unlock(lock))
return 0;
#endif
return 1;
}
#endif

190
crypto/threads_win.c Normal file
View File

@ -0,0 +1,190 @@
/* ====================================================================
* Copyright (c) 2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/crypto.h>
#include "internal/threads.h"
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && defined(OPENSSL_SYS_WINDOWS)
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
{
CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(CRITICAL_SECTION));
if (lock == NULL)
return NULL;
/* 0x400 is the spin count value suggested in the documentation */
if (!InitializeCriticalSectionAndSpinCount(lock, 0x400))
return NULL;
return lock;
}
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
{
EnterCriticalSection(lock);
return 1;
}
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
{
EnterCriticalSection(lock);
return 1;
}
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
{
LeaveCriticalSection(lock);
return 1;
}
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
{
if (lock == NULL)
return;
DeleteCriticalSection(lock);
OPENSSL_free(lock);
return;
}
# if _WIN32_WINNT < 0x0600
# define ONCE_UNINITED 0
# define ONCE_ININIT 1
# define ONCE_DONE 2
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
{
LONG volatile *lock = (LONG *)once;
LONG result;
if (*lock == ONCE_DONE)
return 1;
do {
result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED);
if (result == ONCE_UNINITED) {
init();
*lock = ONCE_DONE;
return 1;
}
} while (result == ONCE_ININIT);
return (*lock == ONCE_DONE);
}
# else
BOOL CALLBACK once_cb(PINIT_ONCE once, PVOID p, PVOID *pp)
{
void (*init)(void) = p;
init();
return TRUE;
}
void CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
{
if (InitOnceExecuteOnce(once, once_cb, init, NULL))
return 0;
return 1;
}
# endif
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
{
*key = TlsAlloc();
if (*key == TLS_OUT_OF_INDEXES)
return 0;
return 1;
}
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
{
return TlsGetValue(*key);
}
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
{
if (TlsSetValue(*key, val) == 0)
return 0;
return 1;
}
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
{
if (TlsFree(*key) == 0)
return 0;
return 1;
}
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
{
return GetCurrentThreadId();
}
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
{
return (a == b);
}
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
{
*ret = InterlockedExchangeAdd(val, amount) + amount;
return 1;
}
#endif

View File

@ -2,176 +2,66 @@
=head1 NAME
CRYPTO_THREADID_set_callback, CRYPTO_THREADID_get_callback,
CRYPTO_THREADID_current, CRYPTO_THREADID_cmp, CRYPTO_THREADID_cpy,
CRYPTO_THREADID_hash, CRYPTO_set_locking_callback, CRYPTO_num_locks,
CRYPTO_set_dynlock_create_callback, CRYPTO_set_dynlock_lock_callback,
CRYPTO_set_dynlock_destroy_callback, CRYPTO_get_new_dynlockid,
CRYPTO_destroy_dynlockid, CRYPTO_lock - OpenSSL thread support
CRYPTO_THREAD_lock_new, CRYPTO_THREAD_read_lock, CRYPTO_THREAD_write_lock,
CRYPTO_THREAD_unlock, CRYPTO_THREAD_lock_free, CRYPTO_atomic_add - OpenSSL thread support
=head1 SYNOPSIS
#include <openssl/crypto.h>
/* Don't use this structure directly. */
typedef struct crypto_threadid_st
{
void *ptr;
unsigned long val;
} CRYPTO_THREADID;
/* Only use CRYPTO_THREADID_set_[numeric|pointer]() within callbacks */
void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val);
void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr);
int CRYPTO_THREADID_set_callback(void (*threadid_func)(CRYPTO_THREADID *));
void (*CRYPTO_THREADID_get_callback(void))(CRYPTO_THREADID *);
void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a,
const CRYPTO_THREADID *b);
void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest,
const CRYPTO_THREADID *src);
unsigned long CRYPTO_THREADID_hash(const CRYPTO_THREADID *id);
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void);
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock);
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock);
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock);
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock);
int CRYPTO_num_locks(void);
/* struct CRYPTO_dynlock_value needs to be defined by the user */
struct CRYPTO_dynlock_value;
void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *
(*dyn_create_function)(const char *file, int line));
void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)
(int mode, struct CRYPTO_dynlock_value *l,
const char *file, int line));
void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)
(struct CRYPTO_dynlock_value *l, const char *file, int line));
int CRYPTO_get_new_dynlockid(void);
void CRYPTO_destroy_dynlockid(int i);
void CRYPTO_lock(int mode, int n, const char *file, int line);
#define CRYPTO_w_lock(type) \
CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,OPENSSL_FILE,OPENSSL_LINE)
#define CRYPTO_w_unlock(type) \
CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,OPENSSL_FILE,OPENSSL_LINE)
#define CRYPTO_r_lock(type) \
CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,OPENSSL_FILE,OPENSSL_LINE)
#define CRYPTO_r_unlock(type) \
CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,OPENSSL_FILE,OPENSSL_LINE)
#define CRYPTO_add(addr,amount,type) \
CRYPTO_add_lock(addr,amount,type,OPENSSL_FILE,OPENSSL_LINE)
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock);
=head1 DESCRIPTION
OpenSSL can safely be used in multi-threaded applications provided
that at least two callback functions are set, locking_function and
threadid_func.
OpenSSL can be safely used in multi-threaded applications provided that
support for the underlying OS threading API is built-in. Currently, OpenSSL
supports the pthread and Windows APIs. OpenSSL can also be built without
any multi-threading support, for example on platforms that don't provide
any threading support or that provide a threading API that is not yet
supported by OpenSSL.
locking_function(int mode, int n, const char *file, int line) is
needed to perform locking on shared data structures.
(Note that OpenSSL uses a number of global data structures that
will be implicitly shared whenever multiple threads use OpenSSL.)
Multi-threaded applications will crash at random if it is not set.
locking_function() must be able to handle up to CRYPTO_num_locks()
different mutex locks. It sets the B<n>-th lock if B<mode> &
B<CRYPTO_LOCK>, and releases it otherwise.
B<file> and B<line> are the file number of the function setting the
lock. They can be useful for debugging.
threadid_func(CRYPTO_THREADID *id) is needed to record the currently-executing
thread's identifier into B<id>. The implementation of this callback should not
fill in B<id> directly, but should use CRYPTO_THREADID_set_numeric() if thread
IDs are numeric, or CRYPTO_THREADID_set_pointer() if they are pointer-based.
The B<id> must be unique for the duration of the execution of the program.
If the application does not register such a callback using
CRYPTO_THREADID_set_callback(), then a default implementation is used - on
Windows this uses the system's default thread identifying APIs, and on
all other platforms it uses the address of B<errno>. The latter is satisfactory
for thread-safety if and only if the platform has a thread-local error number
facility.
Once threadid_func() is registered, or if the built-in default implementation is
to be used;
The following multi-threading function are provided:
=over 4
=item *
CRYPTO_THREADID_current() records the currently-executing thread ID into the
given B<id> object.
CRYPTO_THREAD_lock_new() allocates, initializes and returns a new read/write
lock.
=item *
CRYPTO_THREADID_cmp() compares two thread IDs (returning zero for equality, ie.
the same semantics as memcmp()).
CRYPTO_THREAD_read_lock() locks the provided B<lock> for reading.
=item *
CRYPTO_THREADID_cpy() duplicates a thread ID value,
CRYPTO_THREAD_write_lock() locks the provided B<lock> for writing.
=item *
CRYPTO_THREADID_hash() returns a numeric value usable as a hash-table key. This
is usually the exact numeric or pointer-based thread ID used internally, however
this also handles the unusual case where pointers are larger than 'long'
variables and the platform's thread IDs are pointer-based - in this case, mixing
is done to attempt to produce a unique numeric value even though it is not as
wide as the platform's true thread IDs.
CRYPTO_THREAD_unlock() unlocks the previously locked B<lock>.
=item *
CRYPTO_THREAD_lock_frees() frees the provided B<lock>.
=item *
CRYPTO_atomic_add() atomically adds B<amount> to B<val> and returns the
result of the operation in B<ret>. B<lock> will be locked, unless atomic
operations are supported on the specific platform. Because of this, if a
variable is modified by CRYPTO_atomic_add() then CRYPTO_atomic_add() must
be the only way that the variable is modified.
=back
Additionally, OpenSSL supports dynamic locks, and sometimes, some parts
of OpenSSL need it for better performance. To enable this, the following
is required:
=over 4
=item *
Three additional callback function, dyn_create_function, dyn_lock_function
and dyn_destroy_function.
=item *
A structure defined with the data that each lock needs to handle.
=back
struct CRYPTO_dynlock_value has to be defined to contain whatever structure
is needed to handle locks.
dyn_create_function(const char *file, int line) is needed to create a
lock. Multi-threaded applications might crash at random if it is not set.
dyn_lock_function(int mode, CRYPTO_dynlock *l, const char *file, int line)
is needed to perform locking off dynamic lock numbered n. Multi-threaded
applications might crash at random if it is not set.
dyn_destroy_function(CRYPTO_dynlock *l, const char *file, int line) is
needed to destroy the lock l. Multi-threaded applications might crash at
random if it is not set.
CRYPTO_get_new_dynlockid() is used to create locks. It will call
dyn_create_function for the actual creation.
CRYPTO_destroy_dynlockid() is used to destroy locks. It will call
dyn_destroy_function for the actual destruction.
CRYPTO_lock() is used to lock and unlock the locks. mode is a bitfield
describing what should be done with the lock. n is the number of the
lock as returned from CRYPTO_get_new_dynlockid(). mode can be combined
from the following values. These values are pairwise exclusive, with
undefined behaviour if misused (for example, CRYPTO_READ and CRYPTO_WRITE
should not be used together):
CRYPTO_LOCK 0x01
CRYPTO_UNLOCK 0x02
CRYPTO_READ 0x04
CRYPTO_WRITE 0x08
=head1 RETURN VALUES
CRYPTO_num_locks() returns the required number of locks.
CRYPTO_THREAD_lock_new() returns the allocated lock, or NULL on error.
CRYPTO_get_new_dynlockid() returns the index to the newly created lock.
CRYPTO_THREAD_lock_frees() returns no value.
The other functions return no values.
The other functions return 1 on success or 0 on error.
=head1 NOTES
@ -185,21 +75,6 @@ You can find out if OpenSSL was configured with thread support:
// no thread support
#endif
Also, dynamic locks are currently not used internally by OpenSSL, but
may do so in the future.
=head1 EXAMPLES
B<crypto/threads/mttest.c> shows examples of the callback functions on
Solaris, Irix and Win32.
=head1 HISTORY
B<CRYPTO_THREADID> and associated functions were introduced in OpenSSL 1.0.0
to replace (actually, deprecate) the previous CRYPTO_set_id_callback(),
CRYPTO_get_id_callback(), and CRYPTO_thread_id() functions which assumed
thread IDs to always be represented by 'unsigned long'.
=head1 SEE ALSO
L<crypto(3)>

View File

@ -0,0 +1,92 @@
/* ====================================================================
* Copyright (c) 2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* licensing@OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HEADER_INTERNAL_THREADS_H
# define HEADER_INTERNAL_THREADS_H
#include "e_os.h"
# if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
typedef unsigned int CRYPTO_ONCE;
typedef unsigned int CRYPTO_THREAD_LOCAL;
typedef unsigned int CRYPTO_THREAD_ID;
# define CRYPTO_ONCE_STATIC_INIT 0
# elif defined(OPENSSL_SYS_WINDOWS)
# include <windows.h>
typedef DWORD CRYPTO_THREAD_LOCAL;
typedef DWORD CRYPTO_THREAD_ID;
# if _WIN32_WINNT < 0x0600
typedef LONG CRYPTO_ONCE;
# define CRYPTO_ONCE_STATIC_INIT 0
# else
typedef INIT_ONCE CRYPTO_ONCE;
# define CRYPTO_ONCE_STATIC_INIT INIT_ONCE_STATIC_INIT
# endif
# else
# include <pthread.h>
typedef pthread_once_t CRYPTO_ONCE;
typedef pthread_key_t CRYPTO_THREAD_LOCAL;
typedef pthread_t CRYPTO_THREAD_ID;
# define CRYPTO_ONCE_STATIC_INIT PTHREAD_ONCE_INIT
# endif
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void));
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *));
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key);
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val);
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key);
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void);
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b);
#endif

View File

@ -245,6 +245,16 @@ typedef struct {
struct CRYPTO_dynlock_value *data;
} CRYPTO_dynlock;
typedef void CRYPTO_RWLOCK;
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void);
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock);
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock);
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock);
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock);
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock);
/*
* The following can be used to detect memory leaks in the library. If
* used, it turns on malloc checking

View File

@ -82,6 +82,7 @@ SSLSKEWITH0PTEST= sslskewith0ptest
ASYNCTEST= asynctest
DTLSV1LISTENTEST = dtlsv1listentest
CTTEST= ct_test
THREADSTEST= threadstest
TESTS= alltests
@ -103,7 +104,7 @@ EXE= $(NPTEST)$(EXE_EXT) $(MEMLEAKTEST)$(EXE_EXT) \
$(HEARTBEATTEST)$(EXE_EXT) $(P5_CRPT2_TEST)$(EXE_EXT) \
$(CONSTTIMETEST)$(EXE_EXT) $(VERIFYEXTRATEST)$(EXE_EXT) \
$(CLIENTHELLOTEST)$(EXE_EXT) $(PACKETTEST)$(EXE_EXT) $(ASYNCTEST)$(EXE_EXT) \
$(DTLSV1LISTENTEST)$(EXE_EXT) $(CTTEST)$(EXE_EXT)
$(DTLSV1LISTENTEST)$(EXE_EXT) $(CTTEST)$(EXE_EXT) $(THREADSTEST)$(EXE_EXT)
# $(METHTEST)$(EXE_EXT)
@ -120,7 +121,8 @@ OBJ= $(NPTEST).o $(MEMLEAKTEST).o \
$(EVPTEST).o $(EVPEXTRATEST).o $(IGETEST).o $(V3NAMETEST).o \
$(HEARTBEATTEST).o $(P5_CRPT2_TEST).o \
$(CONSTTIMETEST).o $(VERIFYEXTRATEST).o $(CLIENTHELLOTEST).o \
$(PACKETTEST).o $(ASYNCTEST).o $(DTLSV1LISTENTEST).o $(CTTEST).o testutil.o
$(PACKETTEST).o $(ASYNCTEST).o $(DTLSV1LISTENTEST).o $(CTTEST).o \
$(THREADSTEST).o testutil.o
SRC= $(NPTEST).c $(MEMLEAKTEST).c \
$(BNTEST).c $(ECTEST).c \
@ -134,7 +136,8 @@ SRC= $(NPTEST).c $(MEMLEAKTEST).c \
$(EVPTEST).c $(EVPEXTRATEST).c $(IGETEST).c $(V3NAMETEST).c \
$(HEARTBEATTEST).c $(P5_CRPT2_TEST).c \
$(CONSTTIMETEST).c $(VERIFYEXTRATEST).c $(CLIENTHELLOTEST).c \
$(PACKETTEST).c $(ASYNCTEST).c $(DTLSV1LISTENTEST).c $(CTTEST).c testutil.c
$(PACKETTEST).c $(ASYNCTEST).c $(DTLSV1LISTENTEST).c $(CTTEST).c \
$(THREADSTEST).c testutil.c
HEADER= testutil.h
@ -373,6 +376,9 @@ $(DTLSV1LISTENTEST)$(EXE_EXT): $(DTLSV1LISTENTEST).o
$(CTTEST)$(EXE_EXT): $(CTTEST).o testutil.o
@target=$(CTTEST) testutil=testutil.o; $(BUILD_CMD)
$(THREADSTEST)$(EXE_EXT): $(THREADSTEST).o $(DLIBCRYPTO)
@target=$(THREADSTEST) $(BUILD_CMD)
dummytest$(EXE_EXT): dummytest.o $(DLIBCRYPTO)
@target=dummytest; $(BUILD_CMD)

View File

@ -13,7 +13,7 @@ PROGRAMS=\
danetest heartbeat_test p5_crpt2_test \
constant_time_test verify_extra_test clienthellotest \
packettest asynctest secmemtest srptest memleaktest \
dtlsv1listentest ct_test
dtlsv1listentest ct_test threadstest
SOURCE[nptest]=nptest.c
INCLUDE[nptest]={- rel2abs(catdir($builddir,"../include")) -} ../include
@ -206,3 +206,7 @@ DEPEND[dtlsv1listentest]=../libssl
SOURCE[ct_test]=ct_test.c
INCLUDE[ct_test]={- rel2abs(catdir($builddir,"../include")) -} ../include
DEPEND[ct_test]=../libcrypto
SOURCE[threadstest]=threadstest.c
INCLUDE[threadstest]={- rel2abs(catdir($builddir,"../include")) -} .. ../include
DEPEND[threadstest]=../libcrypto

5
test/recipes/90-test_threads.t Executable file
View File

@ -0,0 +1,5 @@
#! /usr/bin/perl
use OpenSSL::Test::Simple;
simple_test("test_threads", "threadstest");

283
test/threadstest.c Normal file
View File

@ -0,0 +1,283 @@
/* ====================================================================
* Copyright (c) 2016 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <stdio.h>
#include <openssl/crypto.h>
#include "internal/threads.h"
#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
typedef unsigned int thread_t;
static int run_thread(thread_t *t, void (*f)(void))
{
f();
return 1;
}
static int wait_for_thread(thread_t thread)
{
return 1;
}
#elif defined(OPENSSL_SYS_WINDOWS)
typedef HANDLE thread_t;
static DWORD WINAPI thread_run(LPVOID arg)
{
void (*f)(void);
*(void **) (&f) = arg;
f();
return 0;
}
static int run_thread(thread_t *t, void (*f)(void))
{
*t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL);
return *t != NULL;
}
static int wait_for_thread(thread_t thread)
{
return WaitForSingleObject(thread, INFINITE) == 0;
}
#else
typedef pthread_t thread_t;
static void *thread_run(void *arg)
{
void (*f)(void);
*(void **) (&f) = arg;
f();
return NULL;
}
static int run_thread(thread_t *t, void (*f)(void))
{
return pthread_create(t, NULL, thread_run, *(void **) &f) == 0;
}
static int wait_for_thread(thread_t thread)
{
return pthread_join(thread, NULL) == 0;
}
#endif
static int test_lock(void)
{
CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
if (!CRYPTO_THREAD_read_lock(lock)) {
fprintf(stderr, "CRYPTO_THREAD_read_lock() failed\n");
return 0;
}
if (!CRYPTO_THREAD_unlock(lock)) {
fprintf(stderr, "CRYPTO_THREAD_unlock() failed\n");
return 0;
}
CRYPTO_THREAD_lock_free(lock);
return 1;
}
static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
static unsigned once_run_count = 0;
static void once_do_run(void)
{
once_run_count++;
}
static void once_run_thread_cb(void)
{
CRYPTO_THREAD_run_once(&once_run, once_do_run);
}
static int test_once(void)
{
thread_t thread;
if (!run_thread(&thread, once_run_thread_cb) ||
!wait_for_thread(thread))
{
fprintf(stderr, "run_thread() failed\n");
return 0;
}
if (!CRYPTO_THREAD_run_once(&once_run, once_do_run)) {
fprintf(stderr, "CRYPTO_THREAD_run_once() failed\n");
return 0;
}
if (once_run_count != 1) {
fprintf(stderr, "once run %u times\n", once_run_count);
return 0;
}
return 1;
}
static CRYPTO_THREAD_LOCAL thread_local_key;
static unsigned destructor_run_count = 0;
static int thread_local_thread_cb_ok = 0;
static void thread_local_destructor(void *arg)
{
unsigned *count;
if (arg == NULL)
return;
count = arg;
(*count)++;
}
static void thread_local_thread_cb(void)
{
void *ptr;
ptr = CRYPTO_THREAD_get_local(&thread_local_key);
if (ptr != NULL) {
fprintf(stderr, "ptr not NULL\n");
return;
}
if (!CRYPTO_THREAD_set_local(&thread_local_key, &destructor_run_count)) {
fprintf(stderr, "CRYPTO_THREAD_set_local() failed\n");
return;
}
ptr = CRYPTO_THREAD_get_local(&thread_local_key);
if (ptr != &destructor_run_count) {
fprintf(stderr, "invalid ptr\n");
return;
}
thread_local_thread_cb_ok = 1;
}
static int test_thread_local(void)
{
thread_t thread;
void *ptr = NULL;
if (!CRYPTO_THREAD_init_local(&thread_local_key, thread_local_destructor)) {
fprintf(stderr, "CRYPTO_THREAD_init_local() failed\n");
return 0;
}
ptr = CRYPTO_THREAD_get_local(&thread_local_key);
if (ptr != NULL) {
fprintf(stderr, "ptr not NULL\n");
return 0;
}
if (!run_thread(&thread, thread_local_thread_cb) ||
!wait_for_thread(thread))
{
fprintf(stderr, "run_thread() failed\n");
return 0;
}
if (thread_local_thread_cb_ok != 1) {
fprintf(stderr, "thread-local thread callback failed\n");
return 0;
}
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
ptr = CRYPTO_THREAD_get_local(&thread_local_key);
if (ptr != NULL) {
fprintf(stderr, "ptr not NULL\n");
return 0;
}
# if !defined(OPENSSL_SYS_WINDOWS)
if (destructor_run_count != 1) {
fprintf(stderr, "thread-local destructor run %u times\n",
destructor_run_count);
return 0;
}
# endif
#endif
if (!CRYPTO_THREAD_cleanup_local(&thread_local_key)) {
fprintf(stderr, "CRYPTO_THREAD_cleanup_local() failed\n");
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
if (!test_lock())
return 1;
if (!test_once())
return 1;
if (!test_thread_local())
return 1;
printf("PASS\n");
return 0;
}

View File

@ -4713,3 +4713,16 @@ OPENSSL_INIT_free 5216 1_1_0 EXIST::FUNCTION:
OPENSSL_INIT_set_config_filename 5217 1_1_0 EXIST::FUNCTION:
SRP_user_pwd_free 5218 1_1_0 EXIST::FUNCTION:SRP
SRP_VBASE_get1_by_user 5219 1_1_0 EXIST::FUNCTION:SRP
CRYPTO_THREAD_lock_new 5220 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_lock_free 5221 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_read_lock 5222 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_write_lock 5223 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_unlock 5224 1_1_0 EXIST::FUNCTION:
CRYPTO_atomic_add 5225 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_init_local 5226 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_cleanup_local 5227 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_set_local 5228 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_get_local 5229 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_get_current_id 5230 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_compare_id 5231 1_1_0 EXIST::FUNCTION:
CRYPTO_THREAD_run_once 5232 1_1_0 EXIST::FUNCTION:

View File

@ -236,6 +236,7 @@ $ssl.=" include/openssl/srtp.h";
my $crypto ="include/openssl/crypto.h";
$crypto.=" include/internal/o_dir.h";
$crypto.=" include/internal/o_str.h";
$crypto.=" include/internal/threads.h";
$crypto.=" include/openssl/des.h" ; # unless $no_des;
$crypto.=" include/openssl/idea.h" ; # unless $no_idea;
$crypto.=" include/openssl/rc4.h" ; # unless $no_rc4;