disable the unrecognized nls flag
[AROS-Contrib.git] / regina / mt_posix.c
blobde7085d2319c594defb4f2cbb03b26902bd3fba0
1 /* This is the file to support POSIX threads.
2 * We initialize the global data structure and the global access variable.
3 */
5 #include "regina_c.h"
6 #include "rexxsaa.h"
7 #define DONT_TYPEDEF_PFN
8 #include "rexx.h"
9 #include <pthread.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <pwd.h>
13 #ifdef HAVE_NETDB_H
14 # include <netdb.h>
15 #endif
16 #ifdef HAVE_NETINET_IN_H
17 # include <netinet/in.h>
18 #endif
19 #ifdef HAVE_ARPA_INET_H
20 # include <arpa/inet.h>
21 #endif
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
24 #endif
25 #ifdef HAVE_GRP_H
26 # include <grp.h>
27 #endif
28 #include <time.h>
29 #include <errno.h>
31 typedef struct _MT_mem {
32 struct _MT_mem *prev;
33 struct _MT_mem *next;
34 /* real data follows here */
35 } MT_mem;
37 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
38 struct group getgrgid_retval;
39 char getgrgid_buf[2048]; /* AT LEAST 1K, better 2K or 4K */
40 struct passwd getpwuid_retval;
41 char getpwuid_buf[2048]; /* AT LEAST 1K, better 2K or 4K */
42 struct hostent gethbyn_retval;
43 char gethbyn_buf[8192]; /* sign, size copied from glibc */
44 char inetntoa_buf[16];
45 struct tm gmtime_retval;
46 struct tm localtime_retval;
47 #ifdef HAVE_RANDOM_DATA
48 struct random_data random;
49 char random_buf[64]; /* at least sizeof(clock_t) and time_t */
50 int random_init;
51 #endif
52 char strerror_buf[1024];
53 MT_mem * mem_base;
54 } mt_tsd_t; /* thread-specific but only needed by this module. see
55 * ReginaInitializeThread
58 static pthread_key_t ThreadIndex; /* index of the TSD, no initial value */
59 static pthread_once_t ThreadOnce = PTHREAD_ONCE_INIT; /* for pthread_once */
61 /* Deinitialize is called when the thread terminates.
62 * This is a wonderful position to place code which frees all allocated stuff!
64 static void Deinitialize(void *buf)
66 tsd_t *TSD = (tsd_t *)buf;
67 mt_tsd_t *mt;
68 MT_mem *chunk;
70 if (TSD == NULL) /* Should never happen but be sure */
71 return;
73 deinit_rexxsaa(TSD);
75 mt = (mt_tsd_t *)TSD->mt_tsd;
76 if (mt)
78 while ((chunk = mt->mem_base) != NULL)
80 TSD->MTFree(TSD,chunk + 1);
81 if (mt->mem_base == chunk)
82 break; /* something goes wrong. Don't run into an endless loop */
85 if (mt)
86 free(mt);
87 free(TSD);
90 int IfcReginaCleanup( VOID )
92 tsd_t *TSD = __regina_get_tsd();
94 if (TSD == NULL)
95 return 0;
96 Deinitialize(TSD);
97 pthread_setspecific(ThreadIndex,NULL);
99 return 1;
102 /* ThreadGetKey creates a new index key into the TSD table. This function
103 * must only be used by pthread_once.
105 static void ThreadGetKey(void)
107 pthread_key_create(&ThreadIndex,Deinitialize);
110 /* Lowest level memory allocation function for normal circumstances. */
111 static void *MTMalloc( const tsd_t *TSD, size_t size )
113 mt_tsd_t *mt;
114 MT_mem *newptr = (MT_mem *)malloc(size + sizeof(MT_mem));
116 if (newptr == NULL) /* may happen. errors are detected in the above layers */
117 return(NULL);
119 mt = (mt_tsd_t *)TSD->mt_tsd;
120 newptr->prev = NULL;
121 newptr->next = mt->mem_base;
122 if (mt->mem_base)
123 mt->mem_base->prev = newptr;
124 mt->mem_base = newptr;
125 return(newptr + 1); /* jump over the head */
128 /* Lowest level memory deallocation function for normal circumstances. */
129 static void MTFree( const tsd_t *TSD, void *chunk )
131 mt_tsd_t *mt = (mt_tsd_t *)TSD->mt_tsd;
132 MT_mem *thisptr;
135 * Just in case...
137 if (chunk == NULL)
138 return;
140 thisptr = (MT_mem *)chunk;
141 thisptr--; /* Go to the header of the chunk */
143 if (thisptr->prev)
145 if (thisptr->prev->next != thisptr)
146 return;
148 if (thisptr->next)
150 if (thisptr->next->prev != thisptr)
151 return;
154 /* This is a chunk allocated by MTMalloc */
155 if (thisptr->prev)
156 thisptr->prev->next = thisptr->next;
157 if (thisptr->next)
158 thisptr->next->prev = thisptr->prev;
159 if (thisptr == mt->mem_base)
160 mt->mem_base = thisptr->next;
162 /* Last not least we set the pointers to NULL. This prevents a double-free*/
163 thisptr->next = NULL;
164 thisptr->prev = NULL;
165 free(thisptr);
168 /* Lowest level exit handler. */
169 static void MTExit(int code)
171 /* pthread_exit's argument has a different semantic as exit has. */
172 pthread_exit(NULL);
175 /* ReginaInitializeThread creates a new thread structure and returns a ptr
176 * to the initialized value.
177 * The function may be called more than once.
179 tsd_t *ReginaInitializeThread(void)
181 int OK;
182 tsd_t *retval;
184 /* get a unique access variable for the whole process */
185 pthread_once(&ThreadOnce,ThreadGetKey);
187 /* fetch the value of the access variable */
188 retval = (tsd_t *)pthread_getspecific(ThreadIndex);
190 if (retval != NULL)
191 return(retval);
193 /* First call in this thread... */
194 retval = (tsd_t *)malloc(sizeof(tsd_t)); /* no Malloc, etc! */
196 if (retval == NULL) /* THIS is really a problem. I don't know what we */
197 return(NULL); /* should do now. Let the caller run into a crash... */
199 pthread_setspecific(ThreadIndex,retval);
201 memset(retval,0,sizeof(tsd_t));
202 retval->MTMalloc = MTMalloc;
203 retval->MTFree = MTFree;
204 retval->MTExit = MTExit;
206 /* Since the local data structure contains a memory chain for the memory
207 * management we initialize it first.
209 if ( ( retval->mt_tsd = (mt_tsd_t *)malloc( sizeof(mt_tsd_t) ) ) == NULL )
210 return(NULL); /* This is a catastrophy */
211 memset( retval->mt_tsd, 0, sizeof(mt_tsd_t) );
213 OK = init_memory(retval); /* Initialize the memory module FIRST*/
215 /* Without the initial memory we don't have ANY chance! */
216 if (!OK)
217 return(NULL);
220 extern OS_Dep_funcs __regina_OS_Unx;
221 retval->OS = &__regina_OS_Unx;
224 OK &= init_vars(retval); /* Initialize the variable module */
225 OK &= init_stacks(retval); /* Initialize the stack module */
226 OK &= init_filetable(retval); /* Initialize the files module */
227 OK &= init_math(retval); /* Initialize the math module */
228 OK &= init_spec_vars(retval); /* Initialize the interprt module */
229 OK &= init_tracing(retval); /* Initialize the tracing module */
230 OK &= init_builtin(retval); /* Initialize the builtin module */
231 OK &= init_client(retval); /* Initialize the client module */
232 OK &= init_library(retval); /* Initialize the library module */
233 OK &= init_rexxsaa(retval); /* Initialize the rexxsaa module */
234 OK &= init_shell(retval); /* Initialize the shell module */
235 OK &= init_envir(retval); /* Initialize the envir module */
236 OK &= init_expr(retval); /* Initialize the expr module */
237 OK &= init_error(retval); /* Initialize the error module */
238 #ifdef VMS
239 OK &= init_vms(retval); /* Initialize the vmscmd module */
240 OK &= init_vmf(retval); /* Initialize the vmsfuncs module */
241 #endif
242 OK &= init_arexxf(retval); /* Initialize the arxfuncs modules */
243 retval->loopcnt = 1; /* stupid r2perl-module */
244 retval->traceparse = -1;
245 retval->thread_id = (unsigned long)pthread_self();
247 if (!OK)
248 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
250 return(retval);
253 /* __regina_get_tsd returns a pointer to the thread specific data. Be sure to
254 * calls this after a ReginaInitializeThread only.
256 tsd_t *__regina_get_tsd(void)
258 /* See above for comments */
259 return( (tsd_t *)pthread_getspecific( ThreadIndex ) );
262 /******************************************************************************
263 ******************************************************************************
264 * Emulation functions to support multi-threading *****************************
265 * The functions will be opaque to the caller *********************************
266 * The "original" functions at this place are not multi-threading safe ********
267 ******************************************************************************
268 *****************************************************************************/
269 #if defined(HAVE_GETGRGID_R_RETURNS_INT_5_PARAMS) || defined(HAVE_GETGRGID_R_RETURNS_INT_4_PARAMS) ||defined(HAVE_GETGRGID_R_RETURNS_STRUCT)
270 /* see documentation of getgrgid and getgrgid_r */
271 struct group *getgrgid(gid_t gid)
273 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
274 struct group *ptr=NULL;
275 int rc=0;
276 # ifdef HAVE_GETGRGID_R_RETURNS_INT_5_PARAMS
277 rc = getgrgid_r(gid,
278 &mt->getgrgid_retval,
279 mt->getgrgid_buf,
280 sizeof(mt->getgrgid_buf),
281 &ptr);
282 # endif
283 # ifdef HAVE_GETGRGID_R_RETURNS_INT_4_PARAMS
284 rc = getgrgid_r(gid,
285 &mt->getgrgid_retval,
286 mt->getgrgid_buf,
287 sizeof(mt->getgrgid_buf));
288 ptr = &mt->getgrgid_retval;
289 # endif
290 # ifdef HAVE_GETGRGID_R_RETURNS_STRUCT
291 ptr = getgrgid_r(gid,
292 &mt->getgrgid_retval,
293 mt->getgrgid_buf,
294 sizeof(mt->getgrgid_buf) );
295 # endif
296 if ((rc != 0) || (ptr == NULL))
298 errno = rc;
299 return(NULL);
301 return(ptr);
303 #endif
305 #if defined(HAVE_GETPWUID_R_RETURNS_INT) || defined(HAVE_GETPWUID_R_RETURNS_STRUCT)
306 /* see documentation of getpwuid and getpwuid_r */
307 struct passwd *getpwuid(uid_t uid)
309 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
310 struct passwd *ptr=NULL;
311 int rc=0;
313 # ifdef HAVE_GETPWUID_R_RETURNS_INT
314 rc = getpwuid_r(uid,
315 &mt->getpwuid_retval,
316 mt->getpwuid_buf,
317 sizeof(mt->getpwuid_buf),
318 &ptr);
319 # else
320 ptr = getpwuid_r(uid,
321 &mt->getpwuid_retval,
322 mt->getpwuid_buf,
323 sizeof(mt->getpwuid_buf) );
324 # endif
325 if ((rc != 0) || (ptr == NULL))
327 errno = rc;
328 return(NULL);
330 return(ptr);
332 #endif
334 /* see documentation of gmtime and gmtime_r */
335 struct tm *gmtime(const time_t *time)
337 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
338 #ifdef HAVE_GMTIME_R
339 return(gmtime_r(time,&mt->gmtime_retval));
340 #else
341 return NULL;
342 #endif
345 /* see documentation of localtime and localtime_r */
346 struct tm *localtime(const time_t *time)
348 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
350 #ifdef HAVE_LOCALTIME_R
351 return(localtime_r(time,&mt->localtime_retval));
352 #else
353 return NULL;
354 #endif
357 /* see documentation of gethostbyname and gethostbyname_r */
358 struct hostent *gethostbyname(const char *name)
360 int herr;
361 struct hostent *he=NULL;
362 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
364 #ifdef HAVE_GETHOSTBYNAME_R_RETURNS_INT_6_PARAMS
365 if (gethostbyname_r(name,
366 &mt->gethbyn_retval,
367 mt->gethbyn_buf,
368 sizeof(mt->gethbyn_buf),
369 &he,
370 &herr) != 0)
371 return(NULL);
372 #endif
373 #ifdef HAVE_GETHOSTBYNAME_R_RETURNS_STRUCT_5_PARAMS
374 he = gethostbyname_r(name,
375 &mt->gethbyn_retval,
376 mt->gethbyn_buf,
377 sizeof(mt->gethbyn_buf),
378 &herr);
379 #endif
380 return(he);
383 /* see documentation of inet_ntoa and inet_ntop */
384 char *inet_ntoa(struct in_addr in)
386 #ifdef HAVE_INET_NTOP
387 mt_tsd_t *mt = (mt_tsd_t *)__regina_get_tsd()->mt_tsd;
389 return((char *) inet_ntop(AF_INET,
390 &in,
391 mt->inetntoa_buf,
392 sizeof(mt->inetntoa_buf)));
393 #else
394 return NULL;
395 #endif
398 #if defined( HAVE_RANDOM_DATA ) && !defined( HAVE_RANDOM )
399 /* see documentation of random and random_r. If you get compile time errors
400 * exclude this function.
402 int32_t random(void)
404 mt_tsd_t *mt = __regina_get_tsd()->mt_tsd;
405 int32_t retval;
407 if (!mt->random_init) /* according to the ANSI this is equivalent to */
408 srandom(1); /* an initial value of 1 for the seed! */
409 random_r(&mt->random,&retval); /* ignore errors, we MUST return anything */
410 return(retval);
413 /* see documentation of srandom and srandom_r. If you get compile time errors
414 * exclude this function.
416 void srandom(unsigned seed)
418 mt_tsd_t *mt = __regina_get_tsd()->mt_tsd;
419 /* The stack is normally not cleared: wonderful random stuff. */
420 char this_is_random_stuff[sizeof(mt->random_buf)];
422 if (!mt->random_init)
424 mt->random_init = 1;
425 /* In case of a cleared new stack seqment we initialize our buffer
426 * with at least one random stuff:
428 time((time_t *) this_is_random_stuff);
429 /* If the buffer is large enough, use a second one */
430 if (sizeof(time_t) + sizeof(clock_t) < sizeof(this_is_random_stuff))
431 *((clock_t *) (this_is_random_stuff + sizeof(time_t))) = clock();
433 memcpy(mt->random_buf,this_is_random_stuff,sizeof(mt->random_buf));
435 initstate_r(seed,
436 mt->random_buf,
437 sizeof(mt->random_buf),
438 &mt->random);
439 /* initstate calls srandom. We can return savely. */
440 return;
442 srandom_r(seed,&mt->random);
444 #endif
446 #ifdef STRERROR_R
447 /* see documentation of strerror and strerror_r. */
448 char *strerror(int errnum)
450 mt_tsd_t *mt = __regina_get_tsd()->mt_tsd;
452 return(strerror_r(errnum,mt->strerror_buf,sizeof(mt->strerror_buf)));
454 #endif