1 /* This is the file to support WIN32 threads.
2 * We initialize the global data structure and the global access variable.
7 #define DONT_TYPEDEF_PFN
14 #define WIN32_LEAN_AND_MEAN
17 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
18 # pragma warning(disable: 4115 4201 4214 4514)
24 # pragma warning(default: 4115 4201 4214)
28 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
30 } mt_tsd_t
; /* thread-specific but only needed by this module. see
31 * ReginaInitializeThread
34 static DWORD ThreadIndex
= 0xFFFFFFFF; /* index of the TSD, not yet got */
36 /* We use only one critical section for all purposes. That's enough since
37 * we use it very rarely.
39 static CRITICAL_SECTION cs
= {0,};
41 #if defined(DYNAMIC) || (defined(__MINGW32__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)))
42 static void DestroyHeap(tsd_t
*TSD
)
44 mt_tsd_t
*mt
= TSD
->mt_tsd
;
48 if (mt
->Heap
!= (HANDLE
) 0)
49 HeapDestroy(mt
->Heap
);
54 int IfcReginaCleanup( VOID
)
56 tsd_t
*TSD
= __regina_get_tsd();
63 TlsSetValue(ThreadIndex
,NULL
);
70 #define AcquireCriticalSection(cs) EnterCriticalSection(cs)
71 #define AcquireThreadIndex() ThreadIndex
73 /* We provide a DLL entry function. Look at the standard documentation */
74 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD Reason
, LPVOID reserved
)
79 case DLL_PROCESS_ATTACH
:
80 /* Two things to do */
81 InitializeCriticalSection(&cs
);
82 ThreadIndex
= TlsAlloc();
83 if (ThreadIndex
== 0xFFFFFFFF)
84 return FALSE
; /* FIXME, FGC: Do we have to call SetLastError()? */
86 case DLL_PROCESS_DETACH
:
88 case DLL_THREAD_ATTACH
:
90 case DLL_THREAD_DETACH
:
91 TSD
= __regina_get_tsd();
102 /* The DLL will do this work in DllMain above. This is for a MT library: */
104 /* AcquireCriticalSection locks the given critical section and
105 * initializes it on the first use.
107 static void AcquireCriticalSection(CRITICAL_SECTION
*cs
)
109 /* double initializing the critical section won't produce an error.
110 * We must do this on thread attachment if an error occurs in later
111 * implementations of WIN32.
113 InitializeCriticalSection(cs
);
115 EnterCriticalSection(cs
);
118 /* AcquireThreadIndex returns a valid ThreadIndex. */
119 static DWORD
AcquireThreadIndex(void)
121 if (ThreadIndex
== 0xFFFFFFFF)
122 { /* get a unique access variable for the whole process */
123 AcquireCriticalSection(&cs
);
124 if (ThreadIndex
== 0xFFFFFFFF) /* may've changed just before Acquire */
125 ThreadIndex
= TlsAlloc();
126 LeaveCriticalSection(&cs
);
127 /* give back a possible error value. nothing will help at this point */
133 /* This should prevent some error messages and is used as a #define */
134 static unsigned sizeof_ptr(void)
136 return(sizeof(void *));
139 /* Lowest level memory allocation function for normal circumstances. */
140 static void *MTMalloc( const tsd_t
*TSD
, size_t size
)
142 mt_tsd_t
*mt
= TSD
->mt_tsd
;
145 return(NULL
); /* Let it die */
147 return(HeapAlloc(mt
->Heap
,HEAP_NO_SERIALIZE
,size
));
150 /* Lowest level memory deallocation function for normal circumstances. */
151 static void MTFree( const tsd_t
*TSD
, void *chunk
)
153 mt_tsd_t
*mt
= TSD
->mt_tsd
;
164 HeapFree(mt
->Heap
,HEAP_NO_SERIALIZE
,chunk
);
167 /* Lowest level exit handler. */
168 static void MTExit(int code
)
173 /* ReginaInitializeThread creates a new thread structure and returns a ptr
174 * to the initialized value.
175 * The function may be called more than once.
177 tsd_t
*ReginaInitializeThread(void)
184 /* If you run into trouble here, you must change the code in
185 * ReginsSetMutex/ReginaUnsetMutex. The argument there assumes the
186 * following rule. This is an ugly hack.
188 assert(sizeof_ptr() >= sizeof(HANDLE
));
189 if (sizeof_ptr() < sizeof(HANDLE
))
190 return(NULL
); /* Be absolutely sure that we HAVE a problem */
192 idx
= AcquireThreadIndex();
194 /* fetch the value of the access variable */
195 retval
= TlsGetValue(idx
);
197 if (retval
!= NULL
) /* already initialized? */
200 /* First call in this thread... */
201 retval
= malloc(sizeof(tsd_t
)); /* no Malloc, etc! */
203 if (retval
== NULL
) /* THIS is really a problem. I don't know what we */
204 return(NULL
); /* should do now. Let the caller run into a crash... */
206 TlsSetValue(idx
,retval
);
208 memset(retval
,0,sizeof(tsd_t
));
209 retval
->MTMalloc
= MTMalloc
;
210 retval
->MTFree
= MTFree
;
211 retval
->MTExit
= MTExit
;
213 /* Since the local data structure contains a Heap object for the memory
214 * management we initialize it first.
216 if ((mt
= malloc(sizeof(mt_tsd_t
))) == NULL
)
217 return(NULL
); /* This is a catastrophy */
219 memset(mt
,0,sizeof(mt_tsd_t
));
220 if ((mt
->Heap
= HeapCreate(HEAP_NO_SERIALIZE
,0x10000,0)) == NULL
)
221 return(NULL
); /* This is a catastrophy */
223 OK
= init_memory(retval
); /* Initialize the memory module FIRST*/
225 /* Without the initial memory we don't have ANY chance! */
230 extern OS_Dep_funcs __regina_OS_Win
;
231 retval
->OS
= &__regina_OS_Win
;
234 OK
&= init_vars(retval
); /* Initialize the variable module */
235 OK
&= init_stacks(retval
); /* Initialize the stack module */
236 OK
&= init_filetable(retval
); /* Initialize the files module */
237 OK
&= init_math(retval
); /* Initialize the math module */
238 OK
&= init_spec_vars(retval
); /* Initialize the interprt module */
239 OK
&= init_tracing(retval
); /* Initialize the tracing module */
240 OK
&= init_builtin(retval
); /* Initialize the builtin module */
241 OK
&= init_client(retval
); /* Initialize the client module */
242 OK
&= init_library(retval
); /* Initialize the library module */
243 OK
&= init_rexxsaa(retval
); /* Initialize the rexxsaa module */
244 OK
&= init_shell(retval
); /* Initialize the shell module */
245 OK
&= init_envir(retval
); /* Initialize the envir module */
246 OK
&= init_expr(retval
); /* Initialize the expr module */
247 OK
&= init_error(retval
); /* Initialize the error module */
249 OK
&= init_vms(retval
); /* Initialize the vmscmd module */
250 OK
&= init_vmf(retval
); /* Initialize the vmsfuncs module */
252 OK
&= init_arexxf(retval
); /* Initialize the arxfuncs modules */
253 retval
->loopcnt
= 1; /* stupid r2perl-module */
254 retval
->traceparse
= -1;
255 retval
->thread_id
= (unsigned long)GetCurrentThreadId();
258 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
263 /* __regina_get_tsd returns a pointer to the thread specific data. Be sure to
264 * calls this after a ReginaInitializeThread only.
266 tsd_t
*__regina_get_tsd(void)
268 /* See above for comments */
269 return(TlsGetValue(ThreadIndex
));
272 /* ReginaSetMutex is the opposite of ReginaUnsetMutex and sets a mutex
273 * variable. The "true" mutex is "*arg" since we have hidden the type
274 * HANDLE which is the correct type. Thus, we have used "HANDLE" and
275 * "void *" in the same manner. If we include windows.h for the
276 * definition of HANDLE we cant include windows later and may run
277 * into trouble. The initialization code will check of errors of
279 * The argument (*mutex) may be NULL. We initialize the mutex in this
280 * case. This prevents the calling functions to initialize the mutex.
281 * The is a little speed penalty but the mutexes are not used very
282 * often. YOU should change it if it hurts you.
284 void ReginaSetMutex(void **mutex
)
287 volatile HANDLE
*w32_mutex
= (volatile HANDLE
*) mutex
;
289 if (*w32_mutex
== (HANDLE
) 0)
291 AcquireCriticalSection(&cs
);
292 if (*w32_mutex
== (HANDLE
)0) /* may have changed due MT */
294 *w32_mutex
= CreateMutex(NULL
,FALSE
,NULL
);
295 if (*w32_mutex
== NULL
)
298 LeaveCriticalSection(&cs
);
300 { /* We must die now! There is no other chance. */
305 WaitForSingleObject(*w32_mutex
,INFINITE
);
306 /* ignore errors, we continue especially if WAIT_ABANDONED occurs */
309 /* see ReginaSetMutex */
310 void ReginaUnsetMutex(void **mutex
)
312 volatile HANDLE
*w32_mutex
= (volatile HANDLE
*) mutex
;
314 ReleaseMutex(*w32_mutex
);