1 /* This is the file to support WIN32 threads.
2 * We initialize the global data structure and the global access variable.
3 */
4
5 #define DONT_TYPEDEF_PFN
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <assert.h>
11
12 #define WIN32_LEAN_AND_MEAN
13 #ifdef _MSC_VER
14 # if _MSC_VER >= 1100
15 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
16 # pragma warning(disable: 4115 4201 4214 4514)
17 # endif
18 #endif
19 #include <windows.h>
20 #ifdef _MSC_VER
21 # if _MSC_VER >= 1100
22 # pragma warning(default: 4115 4201 4214)
23 # endif
24 #endif
25
26 #include "rxmt.h"
27
28 /* mt_tsd: static variables of this module (thread-safe) */
29 typedef struct
30 {
31 HANDLE Heap;
32 } mt_tsd_t; /* thread-specific but only needed by this module. see
33 * RxPackInitializeThread
34 */
35
36 static DWORD ThreadIndex = 0xFFFFFFFF; /* index of the TSD, not yet got */
37
38 extern void *INIT_RXPACKAGE(RxPackageGlobalDataDef *);
39 extern void TERM_RXPACKAGE(RxPackageGlobalDataDef *);
40
41 /* We use only one critical section for all purposes. That's enough since
42 * we use it very rarely.
43 */
44 static CRITICAL_SECTION cs = {0,};
45
46 #if defined(DYNAMIC) || (defined(__MINGW32__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)))
DestroyHeap(RxPackageGlobalDataDef * TSD)47 static void DestroyHeap( RxPackageGlobalDataDef *TSD )
48 {
49 mt_tsd_t *mt = TSD->mt_tsd;
50
51 if ( mt == NULL )
52 return;
53 if ( mt->Heap != (HANDLE) 0 )
54 HeapDestroy( mt->Heap );
55 GlobalFree( mt );
56 GlobalFree( TSD );
57 }
58
IfcRxPackCleanup(VOID)59 int IfcRxPackCleanup( VOID )
60 {
61 RxPackageGlobalDataDef *TSD = __rxpack_get_tsd();
62
63 if ( TSD == NULL )
64 return 0;
65
66 /*
67 deinit_rexxsaa(TSD);
68 */
69 DestroyHeap( TSD );
70 TlsSetValue( ThreadIndex, NULL );
71
72 return 1;
73 }
74 #endif
75
76 #ifdef DYNAMIC
77 #define AcquireCriticalSection(cs) EnterCriticalSection(cs)
78 #define AcquireThreadIndex() ThreadIndex
79
80 /* We provide a DLL entry function. Look at the standard documentation */
DllMain(HINSTANCE hinstDLL,DWORD Reason,LPVOID reserved)81 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved)
82 {
83 RxPackageGlobalDataDef *TSD;
84
85 switch (Reason) {
86 case DLL_PROCESS_ATTACH:
87 /* Two things to do */
88 InitializeCriticalSection(&cs);
89 ThreadIndex = TlsAlloc();
90 if (ThreadIndex == 0xFFFFFFFF)
91 return FALSE; /* FIXME, FGC: Do we have to call SetLastError()? */
92 break;
93 case DLL_PROCESS_DETACH:
94 break;
95 case DLL_THREAD_ATTACH:
96 break;
97 case DLL_THREAD_DETACH:
98 TSD = __rxpack_get_tsd();
99 if ( TSD != NULL )
100 {
101 TERM_RXPACKAGE( TSD );
102 DestroyHeap( TSD );
103 }
104 break;
105 }
106 return(TRUE);
107 }
108 #else
109 /* The DLL will do this work in DllMain above. This is for a MT library: */
110
111 /* AcquireCriticalSection locks the given critical section and
112 * initializes it on the first use.
113 */
AcquireCriticalSection(CRITICAL_SECTION * cs)114 static void AcquireCriticalSection(CRITICAL_SECTION *cs)
115 {
116 /* double initializing the critical section won't produce an error.
117 * We must do this on thread attachment if an error occurs in later
118 * implementations of WIN32.
119 */
120 InitializeCriticalSection(cs);
121
122 EnterCriticalSection(cs);
123 }
124
125 /* AcquireThreadIndex returns a valid ThreadIndex. */
AcquireThreadIndex(void)126 static DWORD AcquireThreadIndex(void)
127 {
128 if (ThreadIndex == 0xFFFFFFFF)
129 { /* get a unique access variable for the whole process */
130 AcquireCriticalSection(&cs);
131 if (ThreadIndex == 0xFFFFFFFF) /* may've changed just before Acquire */
132 ThreadIndex = TlsAlloc();
133 LeaveCriticalSection(&cs);
134 /* give back a possible error value. nothing will help at this point */
135 }
136 return(ThreadIndex);
137 }
138 #endif
139
140 /* This should prevent some error messages and is used as a #define */
sizeof_ptr(void)141 static unsigned sizeof_ptr(void)
142 {
143 return(sizeof(void *));
144 }
145
146 /* Lowest level memory allocation function for normal circumstances. */
RxMTMalloc(const RxPackageGlobalDataDef * TSD,size_t size)147 static void *RxMTMalloc( const RxPackageGlobalDataDef *TSD, size_t size )
148 {
149 mt_tsd_t *mt = TSD->mt_tsd;
150 void *ptr;
151
152 if ( mt == NULL )
153 return( NULL ); /* Let it die */
154 ptr = HeapAlloc( mt->Heap, HEAP_NO_SERIALIZE, size );
155 return(ptr);
156 }
157
158 /* Lowest level memory deallocation function for normal circumstances. */
RxMTFree(const RxPackageGlobalDataDef * TSD,void * chunk)159 static void RxMTFree( const RxPackageGlobalDataDef *TSD, void *chunk )
160 {
161 mt_tsd_t *mt = TSD->mt_tsd;
162
163 /*
164 * Just in case...
165 */
166 if ( chunk == NULL)
167 return;
168
169 if ( mt == NULL )
170 return; /* ??? */
171 HeapFree( mt->Heap, HEAP_NO_SERIALIZE, chunk );
172 }
173
174 /* Lowest level exit handler. */
RxMTExit(int code)175 static void RxMTExit(int code)
176 {
177 ExitThread(code);
178 }
179
180 /* RxPackInitializeThread creates a new thread structure and returns a ptr
181 * to the initialized value.
182 * The function may be called more than once.
183 */
RxPackInitializeThread(void)184 RxPackageGlobalDataDef *RxPackInitializeThread(void)
185 {
186 DWORD idx;
187 RxPackageGlobalDataDef *retval=NULL;
188 mt_tsd_t *mt;
189
190 /* If you run into trouble here, you must change the code in
191 * ReginsSetMutex/RxPackUnsetMutex. The argument there assumes the
192 * following rule. This is an ugly hack.
193 */
194 assert(sizeof_ptr() >= sizeof(HANDLE));
195 if (sizeof_ptr() < sizeof(HANDLE))
196 return(NULL); /* Be absolutely sure that we HAVE a problem */
197
198 idx = AcquireThreadIndex();
199
200 /* fetch the value of the access variable */
201 retval = TlsGetValue(idx);
202
203 if ( retval != NULL ) /* already initialized? */
204 return(retval);
205
206 /* First call in this thread... */
207 retval = (RxPackageGlobalDataDef *)( GlobalLock( GlobalAlloc( GMEM_FIXED, sizeof(RxPackageGlobalDataDef) ) ) ); /* no MALLOC_TSD, etc! */
208
209 if ( retval == NULL ) /* THIS is really a problem. I don't know what we */
210 return(NULL); /* should do now. Let the caller run into a crash... */
211
212 TlsSetValue( idx, retval );
213
214 memset( retval, 0, sizeof(RxPackageGlobalDataDef) );
215 retval->RxMTMalloc = RxMTMalloc;
216 retval->RxMTFree = RxMTFree;
217 retval->RxMTExit = RxMTExit;
218
219 /* Since the local data structure contains a Heap object for the memory
220 * management we initialize it first.
221 */
222 if ( ( mt = GlobalLock( GlobalAlloc( GMEM_FIXED, sizeof(mt_tsd_t) ) ) ) == NULL )
223 return(NULL); /* This is a catastrophy */
224 retval->mt_tsd = mt;
225 memset( mt, 0, sizeof(mt_tsd_t) );
226 if ( ( mt->Heap = HeapCreate( HEAP_NO_SERIALIZE, 0x10000, 0 ) ) == NULL )
227 return(NULL); /* This is a catastrophy */
228
229 if ( !INIT_RXPACKAGE( retval ) )
230 {
231 return(NULL);
232 }
233 retval->thread_id = (unsigned long)GetCurrentThreadId();
234 return(retval);
235 }
236
237 /* __rxpack_get_tsd returns a pointer to the thread specific data. Be sure to
238 * call this after a RxPackInitializeThread only.
239 */
__rxpack_get_tsd(void)240 RxPackageGlobalDataDef *__rxpack_get_tsd(void)
241 {
242 /* See above for comments */
243 return(TlsGetValue(ThreadIndex));
244 }
245
246 /* RxPackSetMutex is the opposite of RxPackUnsetMutex and sets a mutex
247 * variable. The "true" mutex is "*arg" since we have hidden the type
248 * HANDLE which is the correct type. Thus, we have used "HANDLE" and
249 * "void *" in the same manner. If we include windows.h for the
250 * definition of HANDLE we cant include windows later and may run
251 * into trouble. The initialization code will check of errors of
252 * this assumption.
253 * The argument (*mutex) may be NULL. We initialize the mutex in this
254 * case. This prevents the calling functions to initialize the mutex.
255 * The is a little speed penalty but the mutexes are not used very
256 * often. YOU should change it if it hurts you.
257 */
RxPackSetMutex(void ** mutex)258 void RxPackSetMutex(void **mutex)
259 {
260 int OK = 1;
261 volatile HANDLE *w32_mutex = (volatile HANDLE *) mutex;
262
263 if (*w32_mutex == (HANDLE) 0)
264 {
265 AcquireCriticalSection(&cs);
266 if (*w32_mutex == (HANDLE)0) /* may have changed due MT */
267 {
268 *w32_mutex = CreateMutex(NULL,FALSE,NULL);
269 if (*w32_mutex == NULL)
270 OK = 0;
271 }
272 LeaveCriticalSection(&cs);
273 if (!OK)
274 { /* We must die now! There is no other chance. */
275 *((int *) NULL) = 1;
276 }
277 }
278
279 WaitForSingleObject(*w32_mutex,INFINITE);
280 /* ignore errors, we continue especially if WAIT_ABANDONED occurs */
281 }
282
283 /* see RxPackSetMutex */
RxPackUnsetMutex(void ** mutex)284 void RxPackUnsetMutex(void **mutex)
285 {
286 volatile HANDLE *w32_mutex = (volatile HANDLE *) mutex;
287
288 ReleaseMutex(*w32_mutex);
289 }
290
291 /* get our thread id */
RxPackGetThreadID(void)292 unsigned long RxPackGetThreadID(void)
293 {
294 return (unsigned long)GetCurrentThreadId();
295 }
296
297 /*
298 * Following useful for finding heap corruptions
299 */
CheckHeap(RxPackageGlobalDataDef * TSD,char filename,int lineno)300 void CheckHeap( RxPackageGlobalDataDef *TSD, char filename, int lineno )
301 {
302 mt_tsd_t *mt = TSD->mt_tsd;
303 if ( HeapValidate( mt->Heap, 0, NULL ) == 0 )
304 {
305 fprintf( stderr, "\n\n\n ************* Heap invalid: In %s at line %d\n\n\n\n", filename, lineno );
306 }
307 }
308