1 /* This is the file to support OS/2 threads.
2 * This file is under construction. We partially support EMX. The EMX
3 * environment must currently be "OS2". Thus, usage is provided for
4 * makefile.os2.emx. Others may run.
5 * We initialize the global data structure and the global access variable.
9 #define INCL_DOSPROCESS
10 #define INCL_DOSSEMAPHORES
11 #define INCL_DOSERRORS
12 #define INCL_DOSMEMMGR
15 # define DONT_TYPEDEF_PFN
18 #elif defined (__WATCOMC__)
19 # define DONT_TYPEDEF_PFN
30 static ULONG
*TSD_ptrs
= NULL
;
32 typedef struct _MT_mem
{
35 /* real data follows here */
38 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
39 MT_mem
*mem_base
; /* From DosAllocMem, we use this memory scheme since it is
40 * native OS/2. emx has its own heap allocation functions.
42 } mt_tsd_t
; /* thread-specific but only needed by this module. see
43 * ReginaInitializeThread
46 /* Returns a pointer to the TSD pointer */
47 static tsd_t
**FindThreadDataIdx(void)
49 tsd_t
**retval
= NULL
;
55 retval
= (tsd_t
**) TSD_ptrs
;
58 if ((rc
= DosAllocThreadLocalMemory(1,&TSD_ptrs
)) != NO_ERROR
)
60 fprintf(stderr
,"rc = %lu from DosAllocThreadLocalMemory, await SIGSEGV!\n",
65 retval
= (tsd_t
**) TSD_ptrs
;
71 static void Deinitialize(void *buf
)
77 if (TSD
== NULL
) /* Should never happen but be sure */
84 while ((chunk
= mt
->mem_base
) != NULL
)
86 TSD
->MTFree(TSD
,chunk
+ 1);
87 if (mt
->mem_base
== chunk
)
88 break; /* something goes wrong. Don't run into an endless loop */
95 int IfcReginaCleanup( VOID
)
97 tsd_t
**ptsd
= FindThreadDataIdx();
108 /* Deinitialize is called when the thread terminates.
109 * This is a wonderful position to place code which frees all allocated stuff!
112 /* We provide a DLL entry function. Look at the standard documentation for
113 * EMX. See emxdev.doc and testdll6.c. We may use the macros CRT_INIT1 and
114 * CRT_TERM1 from sys/startup.h instead but that's undocumented stuff.
116 int _CRT_init (void);
117 void _CRT_term (void);
118 void __ctordtorInit (void);
119 void __ctordtorTerm (void);
121 unsigned long _DLL_InitTerm (unsigned long mod_handle
, unsigned long flag
)
126 if (_CRT_init() != 0)
132 * This will run ONLY if called on dynamic unload of the complete
133 * library. This means, the last thread will receive an unload
134 * command. Stupid OS/2.
148 /* This should prevent some error messages and is used as a #define */
149 static unsigned sizeof_ptr(void)
151 return(sizeof(void *));
154 /* Lowest level memory allocation function for normal circumstances. */
155 static void *MTMalloc( const tsd_t
*TSD
, size_t size
)
160 if (DosAllocMem((PPVOID
) &new,
161 size
+ sizeof(MT_mem
),
162 PAG_READ
|PAG_WRITE
|PAG_COMMIT
) != NO_ERROR
)
163 return(NULL
); /* may happen. errors are detected in the above layers */
167 new->next
= mt
->mem_base
;
169 mt
->mem_base
->prev
= new;
171 return(new + 1); /* jump over the head */
174 /* Lowest level memory deallocation function for normal circumstances. */
175 static void MTFree( const tsd_t
*TSD
, void *chunk
)
177 mt_tsd_t
*mt
= TSD
->mt_tsd
;
187 this--; /* Go to the header of the chunk */
190 if (this->prev
->next
!= this)
193 if (this->next
->prev
!= this)
196 /* This is a chunk allocated by MTMalloc */
198 this->prev
->next
= this->next
;
200 this->next
->prev
= this->prev
;
201 if (this == mt
->mem_base
)
202 mt
->mem_base
= this->next
;
204 /* Last not least we set the pointers to NULL. This prevents a double-free*/
210 /* Lowest level exit handler. */
211 static void MTExit(int code
)
213 DosExit(EXIT_THREAD
,code
);
216 /* ReginaInitializeThread creates a new thread structure and returns a ptr
217 * to the initialized value.
218 * The function may be called more than once.
220 tsd_t
*ReginaInitializeThread(void)
223 tsd_t
*retval
,**ptsd
;
226 /* If you run into trouble here, you must change the code in
227 * ReginsSetMutex/ReginaUnsetMutex. The argument there assumes the
228 * following rule. This is an ugly hack.
230 assert(sizeof_ptr() >= sizeof(HMTX
));
231 if (sizeof_ptr() < sizeof(HMTX
))
232 return(NULL
); /* Be absolutely sure that we HAVE a problem */
234 ptsd
= FindThreadDataIdx();
235 if (ptsd
== NULL
) /* can't initialize? */
238 if (*ptsd
!= NULL
) /* already initialized? */
241 /* First call in this thread, a atexit() per thread will be great, sigh...*/
242 retval
= malloc(sizeof(tsd_t
)); /* no Malloc, etc! */
244 if (retval
== NULL
) /* THIS is really a problem. I don't know what we */
245 return(NULL
); /* should do now. Let the caller run into a crash... */
249 memset(retval
,0,sizeof(tsd_t
));
250 retval
->MTMalloc
= MTMalloc
;
251 retval
->MTFree
= MTFree
;
252 retval
->MTExit
= MTExit
;
254 /* Since the local data structure contains a Heap object for the memory
255 * management we initialize it first.
257 if ((mt
= malloc(sizeof(mt_tsd_t
))) == NULL
)
258 return(NULL
); /* This is a catastrophy */
262 OK
= init_memory(retval
); /* Initialize the memory module FIRST*/
264 /* Without the initial memory we don't have ANY chance! */
269 extern OS_Dep_funcs __regina_OS_Os2
;
270 retval
->OS
= &__regina_OS_Os2
;
273 OK
&= init_vars(retval
); /* Initialize the variable module */
274 OK
&= init_stacks(retval
); /* Initialize the stack module */
275 OK
&= init_filetable(retval
); /* Initialize the files module */
276 OK
&= init_math(retval
); /* Initialize the math module */
277 OK
&= init_spec_vars(retval
); /* Initialize the interprt module */
278 OK
&= init_tracing(retval
); /* Initialize the tracing module */
279 OK
&= init_builtin(retval
); /* Initialize the builtin module */
280 OK
&= init_client(retval
); /* Initialize the client module */
281 OK
&= init_library(retval
); /* Initialize the library module */
282 OK
&= init_rexxsaa(retval
); /* Initialize the rexxsaa module */
283 OK
&= init_shell(retval
); /* Initialize the shell module */
284 OK
&= init_envir(retval
); /* Initialize the envir module */
285 OK
&= init_expr(retval
); /* Initialize the expr module */
286 OK
&= init_error(retval
); /* Initialize the error module */
288 OK
&= init_vms(retval
); /* Initialize the vmscmd module */
289 OK
&= init_vmf(retval
); /* Initialize the vmsfuncs module */
291 OK
&= init_arexxf(retval
); /* Initialize the arxfuncs modules */
292 retval
->loopcnt
= 1; /* stupid r2perl-module */
293 retval
->traceparse
= -1;
295 retval
->thread_id
= _gettid();
296 #elif defined(__WATCOMC__)
297 retval
->thread_id
= *_threadid
;
299 retval
->thread_id
= _gettid();
303 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
307 /* __regina_get_tsd returns a pointer to the thread specific data. Be sure to
308 * calls this after a ReginaInitializeThread only.
310 tsd_t
*__regina_get_tsd(void)
312 /* See above for comments */
313 return(*FindThreadDataIdx());
316 /* ReginaSetMutex is the opposite of ReginaUnsetMutex and sets a mutex
317 * variable. The "true" mutex is "*arg" since we have hidden the type
318 * HMTX which is the correct type. Thus, we have used "HMTX" and
319 * "void *" in the same manner. If we include windows.h for the
320 * definition of HANDLE we cant include windows later and may run
321 * into trouble. The initialization code will check of errors of
323 * The argument (*mutex) may be NULL. We initialize the mutex in this
324 * case. This prevents the calling functions to initialize the mutex.
325 * The is a little speed penalty but the mutexes are not used very
326 * often. YOU should change it if it hurts you.
328 void ReginaSetMutex(void **mutex
)
331 HMTX
*os2_mutex
= (HMTX
*) mutex
;
333 if (*os2_mutex
== (HMTX
) 0)
336 if (*os2_mutex
== (HMTX
) 0) /* may have changed due MT */
338 if (DosCreateMutexSem(NULL
,os2_mutex
,0,FALSE
) != NO_ERROR
)
343 { /* We must die now! There is no other chance. */
348 DosRequestMutexSem(*os2_mutex
,SEM_INDEFINITE_WAIT
);
349 /* ignore errors, we continue especially if ERROR_INTERRUPTED occurs.
350 * FIXME, ignoring ERROR_INTERRUPTED OK?
354 /* see ReginaSetMutex */
355 void ReginaUnsetMutex(void **mutex
)
357 HMTX
*os2_mutex
= (HMTX
*) mutex
;
359 DosReleaseMutexSem(*os2_mutex
);