From ddefc8c142480a7381db7c04c2ac4e368c9964cb Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Mon, 21 Mar 2022 21:11:46 +0100 Subject: [PATCH] Initial thread support. --- etc/deps/pthreadw32/include/pthread.h | 1375 +++++++++++++++++ etc/deps/pthreadw32/include/sched.h | 183 +++ etc/deps/pthreadw32/include/semaphore.h | 169 ++ .../lib/v141/static/x64/pthreadVC2.lib | Bin 0 -> 169588 bytes frontend/SlunkCrypt.vcxproj | 12 + libslunkcrypt/libSlunkCrypt.vcxproj | 18 +- libslunkcrypt/libSlunkCrypt.vcxproj.filters | 6 + libslunkcrypt/src/slunkcrypt.c | 99 +- libslunkcrypt/src/thread.c | 273 ++++ libslunkcrypt/src/thread.h | 23 + libslunkcrypt/src/version.h | 4 +- 11 files changed, 2132 insertions(+), 30 deletions(-) create mode 100644 etc/deps/pthreadw32/include/pthread.h create mode 100644 etc/deps/pthreadw32/include/sched.h create mode 100644 etc/deps/pthreadw32/include/semaphore.h create mode 100644 etc/deps/pthreadw32/lib/v141/static/x64/pthreadVC2.lib create mode 100644 libslunkcrypt/src/thread.c create mode 100644 libslunkcrypt/src/thread.h diff --git a/etc/deps/pthreadw32/include/pthread.h b/etc/deps/pthreadw32/include/pthread.h new file mode 100644 index 0000000..58673f4 --- /dev/null +++ b/etc/deps/pthreadw32/include/pthread.h @@ -0,0 +1,1375 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,9,1,0 +#define PTW32_VERSION_STRING "2, 9, 1, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#if !defined(RC_INVOKED) + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if defined(_UWIN) +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_PTW32_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#if defined(PTW32_INCLUDE_WINDOWS_H) +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +typedef unsigned long ULONG_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if defined(HAVE_PTW32_CONFIG_H) +#include "config.h" +#endif /* HAVE_PTW32_CONFIG_H */ + +#if !defined(NEED_FTIME) +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if defined(HAVE_SIGNAL_H) +#include +#endif /* HAVE_SIGNAL_H */ + +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#if !defined(ENOTSUP) +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#if !defined(ETIMEDOUT) +# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ +#endif + +#if !defined(ENOSYS) +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#if !defined(EDEADLK) +# if defined(EDEADLOCK) +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +/* POSIX 2008 - related to robust mutexes */ +#if !defined(EOWNERDEAD) +# define EOWNERDEAD 43 +#endif +#if !defined(ENOTRECOVERABLE) +# define ENOTRECOVERABLE 44 +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#if !defined(PTW32_INCLUDE_WINDOWS_H) +#if !defined(HANDLE) +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#if !defined(DWORD) +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +# define HAVE_STRUCT_TIMESPEC +# ifndef _TIMESPEC_DEFINED +# define _TIMESPEC_DEFINED +# endif +#endif + +#if !defined(HAVE_STRUCT_TIMESPEC) +#define HAVE_STRUCT_TIMESPEC +#if !defined(_TIMESPEC_DEFINED) +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif /* _TIMESPEC_DEFINED */ +#endif /* HAVE_STRUCT_TIMESPEC */ + +#if !defined(SIG_BLOCK) +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#if !defined(SIG_UNBLOCK) +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#if !defined(SIG_SETMASK) +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200809L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200809L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200809L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200809L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200809L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_mutexattr_{get,set}robust + */ + PTHREAD_MUTEX_STALLED = 0, /* Default */ + PTHREAD_MUTEX_ROBUST = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *)(size_t) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#if defined(__CLEANUP_SEH) + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_C) + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#if defined(__CLEANUP_CXX) + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(PTW32_CDECL *start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (PTW32_CDECL *init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + ptw32_cleanup_callback_t routine, + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (PTW32_CDECL *destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( + pthread_mutexattr_t *attr, + int robust); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( + const pthread_mutexattr_t * attr, + int * robust); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); +PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); +/* + * Returns the win32 thread ID for POSIX thread. + */ +PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#if !defined(_UWIN) +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# if !defined(errno) +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#if defined(__cplusplus) + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if !defined(PTW32_BUILD) + +#if defined(__CLEANUP_SEH) + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_CXX) + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#if defined(_MSC_VER) + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#if !defined(PtW32NoCatchWarn) + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #if defined(PtW32CatchAll)") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#if defined(PTW32__HANDLE_DEF) +# undef HANDLE +#endif +#if defined(PTW32__DWORD_DEF) +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/etc/deps/pthreadw32/include/sched.h b/etc/deps/pthreadw32/include/sched.h new file mode 100644 index 0000000..f36a97a --- /dev/null +++ b/etc/deps/pthreadw32/include/sched.h @@ -0,0 +1,183 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(_SCHED_H) +#define _SCHED_H + +#undef PTW32_SCHED_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_SCHED_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_SCHED_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) +#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX +/* Include everything */ +#endif + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ + +#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) +# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +# else + typedef int pid_t; +# endif +#else + typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_SCHED_LEVEL +#undef PTW32_SCHED_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/etc/deps/pthreadw32/include/semaphore.h b/etc/deps/pthreadw32/include/semaphore.h new file mode 100644 index 0000000..c6e9407 --- /dev/null +++ b/etc/deps/pthreadw32/include/semaphore.h @@ -0,0 +1,169 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_SEMAPHORE_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_SEMAPHORE_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_SEMAPHORE_LEVEL +#define PTW32_SEMAPHORE_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_SEMAPHORE_LEVEL +#define PTW32_SEMAPHORE_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_SEMAPHORE_LEVEL_MAX 3 + +#if !defined(PTW32_SEMAPHORE_LEVEL) +#define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX +/* Include everything */ +#endif + +#if defined(__GNUC__) && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +#if !defined(HAVE_MODE_T) +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_SEMAPHORE_LEVEL +#undef PTW32_SEMAPHORE_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/etc/deps/pthreadw32/lib/v141/static/x64/pthreadVC2.lib b/etc/deps/pthreadw32/lib/v141/static/x64/pthreadVC2.lib new file mode 100644 index 0000000000000000000000000000000000000000..9110912c7a5ea46ad41cc225e7f4149650ede8a8 GIT binary patch literal 169588 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 true 5.1 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/debug/$(PlatformTarget);%(AdditionalLibraryDirectories) @@ -255,6 +256,7 @@ false UseLinkTimeCodeGeneration 5.1 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/static/$(PlatformTarget);%(AdditionalLibraryDirectories) @@ -284,6 +286,7 @@ false UseLinkTimeCodeGeneration 5.1 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/static/$(PlatformTarget);%(AdditionalLibraryDirectories) @@ -313,6 +316,7 @@ UseLinkTimeCodeGeneration Console 5.1 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/shared/$(PlatformTarget);%(AdditionalLibraryDirectories) @@ -330,6 +334,8 @@ Console true 5.2 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/debug/$(PlatformTarget);%(AdditionalLibraryDirectories) + pthreadVC2.lib;%(AdditionalDependencies) @@ -359,6 +365,8 @@ false UseLinkTimeCodeGeneration 5.2 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/static/$(PlatformTarget);%(AdditionalLibraryDirectories) + pthreadVC2.lib;%(AdditionalDependencies) @@ -388,6 +396,8 @@ false UseLinkTimeCodeGeneration 5.2 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/static/$(PlatformTarget);%(AdditionalLibraryDirectories) + pthreadVC2.lib;%(AdditionalDependencies) @@ -417,6 +427,8 @@ UseLinkTimeCodeGeneration Console 5.2 + $(ProjectDir)../etc/deps/pthreadw32/lib/$(PlatformToolset)/shared/$(PlatformTarget);%(AdditionalLibraryDirectories) + pthreadVC2.lib;%(AdditionalDependencies) diff --git a/libslunkcrypt/libSlunkCrypt.vcxproj b/libslunkcrypt/libSlunkCrypt.vcxproj index e700ce6..8d7af04 100644 --- a/libslunkcrypt/libSlunkCrypt.vcxproj +++ b/libslunkcrypt/libSlunkCrypt.vcxproj @@ -38,12 +38,14 @@ + + @@ -201,7 +203,7 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) 4706;4204 MultiThreadedDebug NoExtensions @@ -220,7 +222,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed @@ -252,7 +254,7 @@ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed @@ -284,7 +286,7 @@ WIN32;NDEBUG;_DLL;SLUNKCRYPT_SHARED=1;SLUNKCRYPT_EXPORT=1;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed @@ -312,7 +314,7 @@ _DEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) 4706;4204 MultiThreadedDebug NotSet @@ -331,7 +333,7 @@ NDEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed @@ -363,7 +365,7 @@ NDEBUG;_LIB;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed @@ -395,7 +397,7 @@ NDEBUG;_DLL;SLUNKCRYPT_SHARED=1;SLUNKCRYPT_EXPORT=1;%(PreprocessorDefinitions) true NotUsing - $(ProjectDir)include + $(ProjectDir)include;$(ProjectDir)..\etc\deps\pthreadw32\include;%(AdditionalIncludeDirectories) MaxSpeed AnySuitable Speed diff --git a/libslunkcrypt/libSlunkCrypt.vcxproj.filters b/libslunkcrypt/libSlunkCrypt.vcxproj.filters index 9e5bb18..93906ea 100644 --- a/libslunkcrypt/libSlunkCrypt.vcxproj.filters +++ b/libslunkcrypt/libSlunkCrypt.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files + @@ -41,5 +44,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/libslunkcrypt/src/slunkcrypt.c b/libslunkcrypt/src/slunkcrypt.c index afefcbd..70cb984 100644 --- a/libslunkcrypt/src/slunkcrypt.c +++ b/libslunkcrypt/src/slunkcrypt.c @@ -7,6 +7,7 @@ #include "slunkcrypt.h" #include "compiler.h" #include "keygen.h" +#include "thread.h" #include "version.h" /* CRT */ @@ -35,12 +36,24 @@ rand_state_t; typedef struct { int reverse_mode; - uint8_t wheel[256U][256U]; + const uint8_t (*wheel)[256U]; uint32_t counter; rand_state_t random; + uint8_t *data; +} +thread_state_t; + +typedef struct +{ + uint8_t wheel[256U][256U]; + thrdpl_t thread_pool; + size_t thread_idx; + thread_state_t thread_data[MAX_THREADS]; } crypt_state_t; +#define THREAD_COUNT 1U + // ========================================================================== // Abort flag // ========================================================================== @@ -117,27 +130,37 @@ static INLINE void random_seed(rand_state_t *const state, uint64_t salt, const u // Initialization // ========================================================================== -static int initialize_state(crypt_state_t *const state, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode) +static int initialize_state(crypt_state_t *const state, const uint64_t nonce, const uint8_t *const passwd, const size_t passwd_len, const int mode, const int reset) { uint8_t temp[256U][256U]; size_t r, i; - const int reverse = BOOLIFY(mode); + rand_state_t random; + uint32_t counter; + const int reverse_mode = BOOLIFY(mode); + + /* backup previous value */ + const thrdpl_t thread_pool = reset ? state->thread_pool : THRDPL_NULL; /* initialize state */ slunkcrypt_bzero(state, sizeof(crypt_state_t)); - state->reverse_mode = reverse; + + /* create thread-pool */ + if ((state->thread_pool = reset ? thread_pool : thrdpl_create(THREAD_COUNT)) == THRDPL_NULL) + { + return SLUNKCRYPT_FAILURE; + } /* initialize counter */ - random_seed(&state->random, nonce, (uint16_t)(-1), passwd, passwd_len); - state->counter = random_next(&state->random); + random_seed(&random, nonce, (uint16_t)(-1), passwd, passwd_len); + counter = random_next(&random); /* set up the wheel permutations */ for (r = 0U; r < 256U; ++r) { - random_seed(&state->random, nonce, (uint16_t)r, passwd, passwd_len); + random_seed(&random, nonce, (uint16_t)r, passwd, passwd_len); for (i = 0U; i < 256U; ++i) { - const size_t j = random_next(&state->random) % (i + 1U); + const size_t j = random_next(&random) % (i + 1U); if (j != i) { state->wheel[r][i] = state->wheel[r][j]; @@ -148,7 +171,7 @@ static int initialize_state(crypt_state_t *const state, const uint64_t nonce, co } /* reverse the wheels, if requested */ - if (reverse) + if (reverse_mode) { for (r = 0U; r < 256U; ++r) { @@ -165,12 +188,32 @@ static int initialize_state(crypt_state_t *const state, const uint64_t nonce, co CHECK_ABORTED(); } - random_seed(&state->random, nonce, 256U, passwd, passwd_len); + /* set up thread state */ + random_seed(&random, nonce, 256U, passwd, passwd_len); + for (i = 0U; i < THREAD_COUNT; ++i) + { + state->thread_data[i].reverse_mode = reverse_mode; + state->thread_data[i].wheel = state->wheel; + state->thread_data[i].counter = counter + ((uint32_t)i); + memcpy(&state->thread_data[i].random, &random, sizeof(rand_state_t)); + for (r = 0U; r < i * 63U; ++r) + { + random_next(&state->thread_data[i].random); + } + CHECK_ABORTED(); + } + + slunkcrypt_bzero(&counter, sizeof(uint32_t)); + slunkcrypt_bzero(&random, sizeof(rand_state_t)); + return SLUNKCRYPT_SUCCESS; /* aborted */ aborted: + thrdpl_destroy(state->thread_pool); slunkcrypt_bzero(state, sizeof(crypt_state_t)); + slunkcrypt_bzero(&counter, sizeof(uint32_t)); + slunkcrypt_bzero(&random, sizeof(rand_state_t)); return SLUNKCRYPT_ABORTED; } @@ -189,18 +232,22 @@ static INLINE void update_offset(uint8_t *const offset, uint32_t seed, rand_stat } offset[reverse ? (255U - i) : i] = (uint8_t)seed; } + for (i = 0U; i < 63U * (THREAD_COUNT - 1U); ++i) + { + random_next(state); + } } -static INLINE uint8_t process_next_symbol(crypt_state_t *const state, uint8_t value) +static INLINE void process_next_symbol(thread_state_t *const state) { uint8_t offset[256U]; size_t i; - update_offset(offset, state->counter++, &state->random, state->reverse_mode); + update_offset(offset, state->counter, &state->random, state->reverse_mode); for (i = 0U; i < 256U; ++i) { - value = (state->wheel[i][(value + offset[i]) & 0xFF] - offset[i]) & 0xFF; + *state->data = (state->wheel[i][(*state->data + offset[i]) & 0xFF] - offset[i]) & 0xFF; } - return value; + state->counter += THREAD_COUNT; } // ========================================================================== @@ -235,7 +282,7 @@ slunkcrypt_t slunkcrypt_alloc(const uint64_t nonce, const uint8_t *const passwd, { return SLUNKCRYPT_NULL; } - if (initialize_state(state, nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS) + if (initialize_state(state, nonce, passwd, passwd_len, mode, 0) == SLUNKCRYPT_SUCCESS) { return ((slunkcrypt_t)state); } @@ -254,7 +301,7 @@ int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uin { return SLUNKCRYPT_FAILURE; } - if ((result = initialize_state(state, nonce, passwd, passwd_len, mode)) != SLUNKCRYPT_SUCCESS) + if ((result = initialize_state(state, nonce, passwd, passwd_len, mode, 1)) != SLUNKCRYPT_SUCCESS) { slunkcrypt_bzero(state, sizeof(crypt_state_t)); } @@ -263,6 +310,7 @@ int slunkcrypt_reset(const slunkcrypt_t context, const uint64_t nonce, const uin int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, uint8_t *const output, size_t length) { + size_t i; crypt_state_t *const state = (crypt_state_t*)context; if (!state) { @@ -271,23 +319,26 @@ int slunkcrypt_process(const slunkcrypt_t context, const uint8_t *const input, u if (length > 0U) { - size_t i; + memcpy(output, input, length * sizeof(uint8_t)); for (i = 0; i < length; ++i) { - output[i] = process_next_symbol(state, input[i]); + abort(); //process_next_symbol(state, output + i); CHECK_ABORTED(); } } + thrdpl_await(state->thread_pool); return SLUNKCRYPT_SUCCESS; aborted: + thrdpl_await(state->thread_pool); slunkcrypt_bzero(state, sizeof(crypt_state_t)); return SLUNKCRYPT_ABORTED; } int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t length) { + size_t i; crypt_state_t *const state = (crypt_state_t*)context; if (!state) { @@ -296,17 +347,24 @@ int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t if (length > 0U) { - size_t i; for (i = 0; i < length; ++i) { - buffer[i] = process_next_symbol(state, buffer[i]); + state->thread_data[state->thread_idx].data = buffer + i; + //process_next_symbol(&state->thread_data[state->thread_idx]); + thrdpl_submit(state->thread_pool, process_next_symbol, &state->thread_data[state->thread_idx]); + if (++state->thread_idx >= THREAD_COUNT) + { + state->thread_idx = 0U; + } CHECK_ABORTED(); } } + thrdpl_await(state->thread_pool); return SLUNKCRYPT_SUCCESS; aborted: + thrdpl_await(state->thread_pool); slunkcrypt_bzero(state, sizeof(crypt_state_t)); return SLUNKCRYPT_ABORTED; } @@ -316,6 +374,7 @@ void slunkcrypt_free(const slunkcrypt_t context) crypt_state_t *const state = (crypt_state_t*)context; if (state) { + thrdpl_destroy(state->thread_pool); slunkcrypt_bzero(state, sizeof(crypt_state_t)); free(state); } diff --git a/libslunkcrypt/src/thread.c b/libslunkcrypt/src/thread.c new file mode 100644 index 0000000..054341e --- /dev/null +++ b/libslunkcrypt/src/thread.c @@ -0,0 +1,273 @@ +/******************************************************************************/ +/* SlunkCrypt, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#ifdef _MSC_VER +#define PTW32_STATIC_LIB 1 +#endif + +/* Internal */ +#include "slunkcrypt.h" +#include "thread.h" + +/* CRT */ +#include + +/* PThread */ +#include +#include + +typedef struct +{ + thrdpl_worker_t worker; + void *args; +} +thrdpl_task_t; + +typedef struct +{ + size_t index; + pthread_mutex_t *mutex; + pthread_cond_t *ready; + size_t *queue; + sem_t sem_free, sem_used; + pthread_t thread; + thrdpl_task_t task; +} +thrdpl_thread_t; + +typedef struct +{ + size_t thread_count, index, queue; + pthread_mutex_t mutex; + pthread_cond_t ready; + thrdpl_thread_t threads[MAX_THREADS]; +} +thrdpl_data_t; + +// ========================================================================== +// Thread main +// ========================================================================== + +static void *thread_main(void *const arg) +{ + thrdpl_thread_t *const data = (thrdpl_thread_t*)arg; + + for (;;) + { + if (sem_wait(&data->sem_used) != 0) + { + abort(); + } + + if (pthread_mutex_lock(data->mutex) != 0) + { + abort(); + } + + const thrdpl_worker_t worker = data->task.worker; + void *const args = data->task.args; + + if (pthread_mutex_unlock(data->mutex) != 0) + { + abort(); + } + + worker(args); + + if (pthread_mutex_lock(data->mutex) != 0) + { + abort(); + } + + if (!(*data->queue -= 1U)) + { + if (pthread_cond_broadcast(data->ready) != 0) + { + abort(); + } + } + + if (pthread_mutex_unlock(data->mutex) != 0) + { + abort(); + } + + if (sem_post(&data->sem_free) != 0) + { + abort(); + } + } +} + +// ========================================================================== +// Manage threads +// ========================================================================== + +static int create_thread(const size_t index, thrdpl_thread_t *const thread_data, pthread_mutex_t *const mutex, pthread_cond_t *const ready, size_t *const queue) +{ + thread_data->index = index; + thread_data->mutex = mutex; + thread_data->ready = ready; + thread_data->queue = queue; + + if (sem_init(&thread_data->sem_free, 0, 1U) != 0) + { + return -1; + } + + if (sem_init(&thread_data->sem_used, 0, 0U) != 0) + { + sem_destroy(&thread_data->sem_free); + return -1; + } + + if (pthread_create(&thread_data->thread, NULL, thread_main, thread_data) != 0) + { + sem_destroy(&thread_data->sem_used); + sem_destroy(&thread_data->sem_free); + return -1; + } + + return 0; +} + +static int destroy_thread(thrdpl_thread_t *const thread_data) +{ + pthread_cancel(thread_data->thread); + pthread_join(thread_data->thread, NULL); + sem_destroy(&thread_data->sem_used); + sem_destroy(&thread_data->sem_free); + return 0; +} + +// ========================================================================== +// Thread pool API +// ========================================================================== + +thrdpl_t thrdpl_create(const size_t count) +{ + size_t i, j; + thrdpl_data_t *pool = NULL; + + if ((count < 1U) || (count > MAX_THREADS)) + { + return THRDPL_NULL; + } + + if (!(pool = (thrdpl_data_t*) malloc(sizeof(thrdpl_data_t)))) + { + return THRDPL_NULL; + } + + slunkcrypt_bzero(pool, sizeof(thrdpl_data_t)); + pool->thread_count = count; + + if (pthread_mutex_init(&pool->mutex, NULL) != 0) + { + goto failure; + } + + if (pthread_cond_init(&pool->ready, NULL) != 0) + { + pthread_mutex_destroy(&pool->mutex); + goto failure; + } + + for (i = 0U; i < count; ++i) + { + if (create_thread(i, &pool->threads[i], &pool->mutex, &pool->ready, &pool->queue) != 0) + { + for (j = 0U; j < i; ++j) + { + destroy_thread(&pool->threads[j]); + } + pthread_cond_destroy(&pool->ready); + pthread_mutex_destroy(&pool->mutex); + goto failure; + } + } + + return (thrdpl_t)pool; + +failure: + free(pool); + return (thrdpl_t)NULL; +} + +void thrdpl_submit(const thrdpl_t thrdpl, const thrdpl_worker_t worker, void *const args) +{ + thrdpl_data_t *const pool = (thrdpl_data_t*)thrdpl; + + if (pthread_mutex_lock(&pool->mutex) != 0) + { + abort(); + } + + thrdpl_thread_t *const thread = &pool->threads[pool->index]; + + if (++pool->index >= pool->thread_count) + { + pool->index = 0U; + } + + ++pool->queue; + + if (pthread_mutex_unlock(&pool->mutex) != 0) + { + abort(); + } + + if (sem_wait(&thread->sem_free) != 0) + { + abort(); + } + + thread->task.worker = worker; + thread->task.args = args; + + if (sem_post(&thread->sem_used) != 0) + { + abort(); + } +} + +void thrdpl_await(const thrdpl_t thrdpl) +{ + thrdpl_data_t *const pool = (thrdpl_data_t*)thrdpl; + + if (pthread_mutex_lock(&pool->mutex) != 0) + { + abort(); + } + + while (pool->queue) + { + if (pthread_cond_wait(&pool->ready, &pool->mutex) != 0) + { + abort(); + } + } + + if (pthread_mutex_unlock(&pool->mutex) != 0) + { + abort(); + } +} + +void thrdpl_destroy(const thrdpl_t thrdpl) +{ + size_t i; + thrdpl_data_t *const pool = (thrdpl_data_t*)thrdpl; + if (pool) + { + for (i = 0U; i < pool->thread_count; ++i) + { + destroy_thread(&pool->threads[i]); + } + pthread_cond_destroy(&pool->ready); + pthread_mutex_destroy(&pool->mutex); + free(pool); + } +} diff --git a/libslunkcrypt/src/thread.h b/libslunkcrypt/src/thread.h new file mode 100644 index 0000000..1dcef2d --- /dev/null +++ b/libslunkcrypt/src/thread.h @@ -0,0 +1,23 @@ +/******************************************************************************/ +/* SlunkCrypt, by LoRd_MuldeR */ +/* This work has been released under the CC0 1.0 Universal license! */ +/******************************************************************************/ + +#ifndef INC_SLUNKCRYPT_THREAD_H +#define INC_SLUNKCRYPT_THREAD_H + +#include +#include + +#define MAX_THREADS 8U +#define THRDPL_NULL ((thrdpl_t)NULL) + +typedef void (*thrdpl_worker_t)(void *arguments); +typedef uintptr_t thrdpl_t; + +thrdpl_t thrdpl_create(const size_t count); +void thrdpl_submit(const thrdpl_t thrdpl, const thrdpl_worker_t worker, void *const arguments); +void thrdpl_await(const thrdpl_t thrdpl); +void thrdpl_destroy(const thrdpl_t thrdpl); + +#endif \ No newline at end of file diff --git a/libslunkcrypt/src/version.h b/libslunkcrypt/src/version.h index 097c508..d9c8c2c 100644 --- a/libslunkcrypt/src/version.h +++ b/libslunkcrypt/src/version.h @@ -7,7 +7,7 @@ #define INC_SLUNKCRYPT_VERSION_H #define LIB_VERSION_MAJOR 1 -#define LIB_VERSION_MINOR 1 -#define LIB_VERSION_PATCH 2 +#define LIB_VERSION_MINOR 2 +#define LIB_VERSION_PATCH 0 #endif