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