bringing SDL 1.2.14 from vendor into the main branch
[AROS-Contrib.git] / regina / mt_win32.c
blobddb03648b92b7ac0a228793c99d07c77b7de3ff9
1 /* This is the file to support WIN32 threads.
2 * We initialize the global data structure and the global access variable.
3 */
5 #include "rexx.h"
6 #include <stdlib.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <assert.h>
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
14 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
15 HANDLE Heap;
16 } mt_tsd_t; /* thread-specific but only needed by this module. see
17 * ReginaInitializeThread
20 static DWORD ThreadIndex = 0xFFFFFFFF; /* index of the TSD, not yet got */
22 /* We use only one critical section for all purposes. That's enough since
23 * we use it very rarely.
25 static CRITICAL_SECTION cs = {0,};
27 #ifdef DYNAMIC
28 #define AcquireCriticalSection(cs) EnterCriticalSection(cs)
29 #define AcquireThreadIndex() ThreadIndex
31 static void DestroyHeap(tsd_t *TSD)
33 mt_tsd_t *mt = TSD->mt_tsd;
35 if (mt == NULL)
36 return;
37 if (mt->Heap != (HANDLE) 0)
38 HeapDestroy(mt->Heap);
39 free(mt);
40 free(TSD);
43 /* We provide a DLL entry function. Look at the standard documentation */
44 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved)
46 tsd_t *TSD;
48 switch (Reason) {
49 case DLL_PROCESS_ATTACH:
50 /* Two things to do */
51 InitializeCriticalSection(&cs);
52 ThreadIndex = TlsAlloc();
53 if (ThreadIndex == 0xFFFFFFFF)
54 return FALSE; /* FIXME, FGC: Do we have to call SetLastError()? */
55 break;
56 case DLL_PROCESS_DETACH:
57 break;
58 case DLL_THREAD_ATTACH:
59 break;
60 case DLL_THREAD_DETACH:
61 TSD = __regina_get_tsd();
62 if (TSD != NULL)
64 deinit_rexxsaa(TSD);
65 DestroyHeap(TSD);
67 break;
69 return(TRUE);
71 #else
72 /* The DLL will do this work in DllMain above. This is for a MT library: */
74 /* AcquireCriticalSection locks the given critical section and
75 * initializes it on the first use.
77 static void AcquireCriticalSection(CRITICAL_SECTION *cs)
79 /* double initializing the critical section won't produce an error.
80 * We must do this on thread attachment if an error occurs in later
81 * implementations of WIN32.
83 InitializeCriticalSection(cs);
85 EnterCriticalSection(cs);
88 /* AcquireThreadIndex returns a valid ThreadIndex. */
89 static DWORD AcquireThreadIndex(void)
91 if (ThreadIndex == 0xFFFFFFFF)
92 { /* get a unique access variable for the whole process */
93 AcquireCriticalSection(&cs);
94 if (ThreadIndex == 0xFFFFFFFF) /* may've changed just before Acquire */
95 ThreadIndex = TlsAlloc();
96 LeaveCriticalSection(&cs);
97 /* give back a possible error value. nothing will help at this point */
99 return(ThreadIndex);
101 #endif
103 /* This should prevent some error messages and is used as a #define */
104 static unsigned sizeof_ptr(void)
106 return(sizeof(void *));
109 /* Lowest level memory allocation function for normal circumstances. */
110 static void *MTMalloc(const tsd_t *TSD,size_t size)
112 mt_tsd_t *mt = TSD->mt_tsd;
114 if (mt == NULL)
115 return(NULL); /* Let it die */
117 return(HeapAlloc(mt->Heap,HEAP_NO_SERIALIZE,size));
120 /* Lowest level memory deallocation function for normal circumstances. */
121 static void MTFree(const tsd_t *TSD,void *chunk)
123 mt_tsd_t *mt = TSD->mt_tsd;
125 if (mt == NULL)
126 return; /* ??? */
128 HeapFree(mt->Heap,HEAP_NO_SERIALIZE,chunk);
131 /* Lowest level exit handler. */
132 static void MTExit(int code)
134 ExitThread(code);
137 /* ReginaInitializeThread creates a new thread structure and returns a ptr
138 * to the initialized value.
139 * The function may be called more than once.
141 tsd_t *ReginaInitializeThread(void)
143 int OK;
144 DWORD idx;
145 tsd_t *retval;
146 mt_tsd_t *mt;
148 /* If you run into trouble here, you must change the code in
149 * ReginsSetMutex/ReginaUnsetMutex. The argument there assumes the
150 * following rule. This is an ugly hack.
152 assert(sizeof_ptr() >= sizeof(HANDLE));
153 if (sizeof_ptr() < sizeof(HANDLE))
154 return(NULL); /* Be absolutely sure that we HAVE a problem */
156 idx = AcquireThreadIndex();
158 /* fetch the value of the access variable */
159 retval = TlsGetValue(idx);
161 if (retval != NULL) /* already initialized? */
162 return(retval);
164 /* First call in this thread... */
165 retval = malloc(sizeof(tsd_t)); /* no Malloc, etc! */
167 if (retval == NULL) /* THIS is really a problem. I don't know what we */
168 return(NULL); /* should do now. Let the caller run into a crash... */
170 TlsSetValue(idx,retval);
172 memset(retval,0,sizeof(tsd_t));
173 retval->MTMalloc = MTMalloc;
174 retval->MTFree = MTFree;
175 retval->MTExit = MTExit;
177 /* Since the local data structure contains a Heap object for the memory
178 * management we initialize it first.
180 if ((mt = malloc(sizeof(mt_tsd_t))) == NULL)
181 return(NULL); /* This is a catastrophy */
182 retval->mt_tsd = mt;
183 memset(mt,0,sizeof(mt_tsd_t));
184 if ((mt->Heap = HeapCreate(HEAP_NO_SERIALIZE,0x10000,0)) == NULL)
185 return(NULL); /* This is a catastrophy */
187 OK = init_memory(retval); /* Initialize the memory module FIRST*/
189 /* Without the initial memory we don't have ANY chance! */
190 if (!OK)
191 return(NULL);
193 OK &= init_vars(retval); /* Initialize the variable module */
194 OK &= init_stacks(retval); /* Initialize the stack module */
195 OK &= init_filetable(retval); /* Initialize the files module */
196 OK &= init_math(retval); /* Initialize the math module */
197 OK &= init_spec_vars(retval); /* Initialize the interprt module */
198 OK &= init_tracing(retval); /* Initialize the tracing module */
199 OK &= init_builtin(retval); /* Initialize the builtin module */
200 OK &= init_client(retval); /* Initialize the client module */
201 OK &= init_library(retval); /* Initialize the library module */
202 OK &= init_rexxsaa(retval); /* Initialize the rexxsaa module */
203 OK &= init_shell(retval); /* Initialize the shell module */
204 OK &= init_envir(retval); /* Initialize the envir module */
205 OK &= init_expr(retval); /* Initialize the expr module */
206 OK &= init_error(retval); /* Initialize the error module */
207 #ifdef VMS
208 OK &= init_vms(retval); /* Initialize the vmscmd module */
209 OK &= init_vmf(retval); /* Initialize the vmsfuncs module */
210 #endif
211 OK |= init_arexxf(&__regina_tsd); /* Initialize the arexxfuncs modules */
212 retval->loopcnt = 1; /* stupid r2perl-module */
213 retval->traceparse = -1;
214 retval->thread_id = (unsigned long)GetCurrentThreadId();
216 if (!OK)
217 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
219 return(retval);
222 /* __regina_get_tsd returns a pointer to the thread specific data. Be sure to
223 * calls this after a ReginaInitializeThread only.
225 tsd_t *__regina_get_tsd(void)
227 /* See above for comments */
228 return(TlsGetValue(ThreadIndex));
231 /* ReginaSetMutex is the opposite of ReginaUnsetMutex and sets a mutex
232 * variable. The "true" mutex is "*arg" since we have hidden the type
233 * HANDLE which is the correct type. Thus, we have used "HANDLE" and
234 * "void *" in the same manner. If we include windows.h for the
235 * definition of HANDLE we cant include windows later and may run
236 * into trouble. The initialization code will check of errors of
237 * this assumption.
238 * The argument (*mutex) may be NULL. We initialize the mutex in this
239 * case. This prevents the calling functions to initialize the mutex.
240 * The is a little speed penalty but the mutexes are not used very
241 * often. YOU should change it if it hurts you.
243 void ReginaSetMutex(void **mutex)
245 int OK = 1;
246 volatile HANDLE *w32_mutex = (volatile HANDLE *) mutex;
248 if (*w32_mutex == (HANDLE) 0)
250 AcquireCriticalSection(&cs);
251 if (*w32_mutex == (HANDLE)0) /* may have changed due MT */
253 *w32_mutex = CreateMutex(NULL,FALSE,NULL);
254 if (*w32_mutex == NULL)
255 OK = 0;
257 LeaveCriticalSection(&cs);
258 if (!OK)
259 { /* We must die now! There is no other chance. */
260 *((int *) NULL) = 1;
264 WaitForSingleObject(*w32_mutex,INFINITE);
265 /* ignore errors, we continue especially if WAIT_ABANDONED occurs */
268 /* see ReginaSetMutex */
269 void ReginaUnsetMutex(void **mutex)
271 volatile HANDLE *w32_mutex = (volatile HANDLE *) mutex;
273 ReleaseMutex(*w32_mutex);