Use read/write locking on Windows

Fixes #13914

The "SRWLock" synchronization primitive is available in Windows Vista
and later.  CRYPTO_THREAD functions now use SRWLock functions when the
target operating system supports them.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14381)
This commit is contained in:
Vincent Drake 2021-03-01 14:38:02 -05:00 committed by Matt Caswell
parent 1aa7ecd0d3
commit f70863d9dd
2 changed files with 53 additions and 2 deletions

View File

@ -23,6 +23,11 @@ OpenSSL 3.0
### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
* Windows thread synchronization uses read/write primitives (SRWLock) when
supported by the OS, otherwise CriticalSection continues to be used.
*Vincent Drake*
* Add filter BIO BIO_f_readbuffer() that allows BIO_tell() and BIO_seek() to
work on read only BIO source/sinks that do not support these functions.
This allows piping or redirection of a file BIO using stdin to be buffered

View File

@ -9,29 +9,49 @@
#if defined(_WIN32)
# include <windows.h>
# if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
# include <synchapi.h>
# define USE_RWLOCK
# endif
#endif
#include <openssl/crypto.h>
#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && defined(OPENSSL_SYS_WINDOWS)
# ifdef USE_RWLOCK
typedef struct {
SRWLOCK lock;
int exclusive;
} CRYPTO_win_rwlock;
# endif
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
{
CRYPTO_RWLOCK *lock;
# ifdef USE_RWLOCK
CRYPTO_win_rwlock *rwlock;
if ((lock = OPENSSL_zalloc(sizeof(CRYPTO_win_rwlock))) == NULL)
return NULL;
rwlock = lock;
InitializeSRWLock(&rwlock->lock);
# else
if ((lock = OPENSSL_zalloc(sizeof(CRITICAL_SECTION))) == NULL) {
/* Don't set error, to avoid recursion blowup. */
return NULL;
}
# if !defined(_WIN32_WCE)
# if !defined(_WIN32_WCE)
/* 0x400 is the spin count value suggested in the documentation */
if (!InitializeCriticalSectionAndSpinCount(lock, 0x400)) {
OPENSSL_free(lock);
return NULL;
}
# else
# else
InitializeCriticalSection(lock);
# endif
# endif
return lock;
@ -39,19 +59,43 @@ CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
{
# ifdef USE_RWLOCK
CRYPTO_win_rwlock *rwlock = lock;
AcquireSRWLockShared(&rwlock->lock);
# else
EnterCriticalSection(lock);
# endif
return 1;
}
int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
{
# ifdef USE_RWLOCK
CRYPTO_win_rwlock *rwlock = lock;
AcquireSRWLockExclusive(&rwlock->lock);
rwlock->exclusive = 1;
# else
EnterCriticalSection(lock);
# endif
return 1;
}
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
{
# ifdef USE_RWLOCK
CRYPTO_win_rwlock *rwlock = lock;
if (rwlock->exclusive) {
rwlock->exclusive = 0;
ReleaseSRWLockExclusive(&rwlock->lock);
} else {
ReleaseSRWLockShared(&rwlock->lock);
}
# else
LeaveCriticalSection(lock);
# endif
return 1;
}
@ -60,7 +104,9 @@ void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
if (lock == NULL)
return;
# ifndef USE_RWLOCK
DeleteCriticalSection(lock);
# endif
OPENSSL_free(lock);
return;