lokinet/crypto/libsodium/init.c
despair d9863128b9 the intrinsic variant is 32-bit clean
the ASM variant is not

found it

fix

something is wrong with the external build

hmm

why is this critical section doing nothing

fix multiple init

debug init

ok fixed
2018-11-19 04:29:36 -06:00

231 lines
3.8 KiB
C

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#elif defined(HAVE_PTHREAD)
#include <pthread.h>
#endif
#include <sodium/core.h>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_stream_chacha20.h>
#include <sodium/crypto_stream_salsa20.h>
#include <sodium/randombytes.h>
#include <sodium/runtime.h>
#include <sodium/utils.h>
#include <sodium/private/implementations.h>
#include <sodium/private/mutex.h>
static volatile int initialized;
int
sodium_init(void)
{
if(sodium_crit_enter() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
if(initialized != 0)
{
if(sodium_crit_leave() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
/* if we're here, we already started properly */
return initialized ? 0: -1;
}
_sodium_runtime_get_cpu_features();
_crypto_generichash_blake2b_pick_best_implementation();
_crypto_scalarmult_curve25519_pick_best_implementation();
_crypto_stream_chacha20_pick_best_implementation();
_crypto_stream_salsa20_pick_best_implementation();
randombytes_stir();
initialized = 1;
if(sodium_crit_leave() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
return initialized ? 0 : -1;
}
#ifdef _WIN32
static CRITICAL_SECTION _sodium_lock;
static volatile LONG _sodium_lock_initialized;
static volatile int locked;
int
_sodium_crit_init(void)
{
LONG status = 0L;
while((status = InterlockedCompareExchange(&_sodium_lock_initialized, 1L, 0L))
== 1L)
{
Sleep(0);
}
switch(status)
{
case 0L:
InitializeCriticalSection(&_sodium_lock);
return InterlockedExchange(&_sodium_lock_initialized, 2L) == 1L ? 0 : -1;
case 2L:
return 0;
default: /* should never be reached */
return -1;
}
}
int
sodium_crit_enter(void)
{
if(_sodium_crit_init() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
EnterCriticalSection(&_sodium_lock);
assert(locked == 0);
locked = 1;
return 0;
}
int
sodium_crit_leave(void)
{
if(locked == 0)
{
#ifdef EPERM
errno = EPERM;
#endif
return -1;
}
locked = 0;
LeaveCriticalSection(&_sodium_lock);
return 0;
}
#elif defined(HAVE_PTHREAD) && !defined(__EMSCRIPTEN__)
static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER;
static volatile int locked;
int
sodium_crit_enter(void)
{
int ret;
if((ret = pthread_mutex_lock(&_sodium_lock)) == 0)
{
assert(locked == 0);
locked = 1;
}
return ret;
}
int
sodium_crit_leave(void)
{
int ret;
if(locked == 0)
{
#ifdef EPERM
errno = EPERM;
#endif
return -1;
}
locked = 0;
return pthread_mutex_unlock(&_sodium_lock);
}
#elif defined(HAVE_ATOMIC_OPS) && !defined(__EMSCRIPTEN__) \
&& !defined(__native_client__)
static volatile int _sodium_lock;
int
sodium_crit_enter(void)
{
#ifdef HAVE_NANOSLEEP
struct timespec q;
memset(&q, 0, sizeof q);
#endif
while(__sync_lock_test_and_set(&_sodium_lock, 1) != 0)
{
#ifdef HAVE_NANOSLEEP
(void)nanosleep(&q, NULL);
#elif defined(__x86_64__) || defined(__i386__)
__asm__ __volatile__("pause");
#endif
}
return 0;
}
int
sodium_crit_leave(void)
{
__sync_lock_release(&_sodium_lock);
return 0;
}
#else
int
sodium_crit_enter(void)
{
return 0;
}
int
sodium_crit_leave(void)
{
return 0;
}
#endif
static void (*_misuse_handler)(void);
void
sodium_misuse(void)
{
void (*handler)(void);
(void)sodium_crit_leave();
if(sodium_crit_enter() == 0)
{
handler = _misuse_handler;
if(handler != NULL)
{
handler();
}
}
/* LCOV_EXCL_START */
abort();
}
/* LCOV_EXCL_STOP */
int
sodium_set_misuse_handler(void (*handler)(void))
{
if(sodium_crit_enter() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
_misuse_handler = handler;
if(sodium_crit_leave() != 0)
{
return -1; /* LCOV_EXCL_LINE */
}
return 0;
}