EWL is highly adaptive when it comes to multithreading. The C standard makes no mention of threading. It even has points where global data is accessed directly, for example errno, asctime(). EWL can be configured to know about multithreaded systems and be completely reentrant. There are essentially three ways to configure the EWL thread support:
With EWL_THREADSAFE defined to 1, EWL is setup to operate in a single thread environment. There are no critical regions to synchronize operations between threads. It is sometimes advantageous to configure EWL for a single threaded environment. Operations such as file input/output and memory allocations will be quicker because there is no need to ask for or wait for critical regions. Many simple programs do not make use of threads, thus there may be no need for the additional overhead.
With EWL_THREADSAFE defined to 1, EWL is setup to synchronize operations between threads properly by the use of critical regions. Critical regions are supplied either by POSIX pthread functions or by the use of platform specific calls. If the platform has an underlying POSIX layer supporting pthreads, simply defining EWL_THREADSAFE and EWL_PTHREADS is enough for EWL to fully operate. No other custom code is necessary.
With EWL_THREADSAFE defined to 1 and EWL_PTHREADS defined to 0, the platform must provide its own critical region code. This is generally done by first providing an array of critical region identifiers in the critical_regions_platform .c file, and then by completing the four critical region functions in the critical_regions_platform .h header file (where platform represents the target platform which EWL runs on). The compiler runtime library must make a call to init_critical_regions() before calling main().
With EWL_THREADSAFE on, the EWL_LOCALDATA_AVAILABLE flag controls whether or not the EWL library is completely reentrant or not. When EWL_LOCALDATA_AVAILABLE is off, the EWL library uses global and static variables, and is therefore not completely reentrant for such items as errno, the random number seed used by rand(), strtok() state information, etc. When EWL_LOCALDATA_AVAILABLE is on, the EWL library uses thread local storage to maintain state information. Each thread has its own copy of some dynamic memory that gets used.
With EWL_LOCALDATA_AVAILABLE on and EWL_PTHREADS on, simply adding the following line to the platform prefix file is enough to fully support complete reentrancy:
#define _EWL_LOCALDATA(_a) __ewl_GetThreadLocalData()->_a
With EWL_LOCALDATA_AVAILABLE on and EWL_PTHREADS off, the platform must completely supply its own routines to maintain and access thread local storage. The thread_local_data_xxx.h and thread_local_data_xxx.c files are used to provide the necessary functionality. Also, the common EWL header ( ewl_thread_local_data.h) must be modified to include the platform header ( thread_local_data_platform.h) based on its dest_os value. The EWL_LOCALDATA macro is used to access items in thread local storage. So, for example, if the random number seed needs to be obtained, the EWL code will invoke
_EWL_LOCALDATA(random_next)
to get the random number seed. The macro must expand to an l-value expression.
At times, it may be easier to turn on EWL_PTHREADS even if the underlying platform does not have built-in pthread support. Instead of writing custom code to support the EWL threading model, it may be easier to turn on EWL_PTHREADS and then write comparable pthread routines. When EWL_PTHREADS is on and _EWL_THREADSAFE is on, four pthread routines in the pthread_platform .c file are used by EWL to implement critical regions.