1 /* This is the file to support POSIX threads.
2 * We initialize the global data structure and the global access variable.
7 #define DONT_TYPEDEF_PFN
16 #ifdef HAVE_NETINET_IN_H
17 # include <netinet/in.h>
19 #ifdef HAVE_ARPA_INET_H
20 # include <arpa/inet.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
31 typedef struct _MT_mem
{
34 /* real data follows here */
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 */
52 char strerror_buf
[1024];
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
;
70 if (TSD
== NULL
) /* Should never happen but be sure */
75 mt
= (mt_tsd_t
*)TSD
->mt_tsd
;
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 */
90 int IfcReginaCleanup( VOID
)
92 tsd_t
*TSD
= __regina_get_tsd();
97 pthread_setspecific(ThreadIndex
,NULL
);
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
)
114 MT_mem
*newptr
= (MT_mem
*)malloc(size
+ sizeof(MT_mem
));
116 if (newptr
== NULL
) /* may happen. errors are detected in the above layers */
119 mt
= (mt_tsd_t
*)TSD
->mt_tsd
;
121 newptr
->next
= 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
;
140 thisptr
= (MT_mem
*)chunk
;
141 thisptr
--; /* Go to the header of the chunk */
145 if (thisptr
->prev
->next
!= thisptr
)
150 if (thisptr
->next
->prev
!= thisptr
)
154 /* This is a chunk allocated by MTMalloc */
156 thisptr
->prev
->next
= 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
;
168 /* Lowest level exit handler. */
169 static void MTExit(int code
)
171 /* pthread_exit's argument has a different semantic as exit has. */
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)
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
);
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! */
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 */
239 OK
&= init_vms(retval
); /* Initialize the vmscmd module */
240 OK
&= init_vmf(retval
); /* Initialize the vmsfuncs module */
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();
248 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
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
;
276 # ifdef HAVE_GETGRGID_R_RETURNS_INT_5_PARAMS
278 &mt
->getgrgid_retval
,
280 sizeof(mt
->getgrgid_buf
),
283 # ifdef HAVE_GETGRGID_R_RETURNS_INT_4_PARAMS
285 &mt
->getgrgid_retval
,
287 sizeof(mt
->getgrgid_buf
));
288 ptr
= &mt
->getgrgid_retval
;
290 # ifdef HAVE_GETGRGID_R_RETURNS_STRUCT
291 ptr
= getgrgid_r(gid
,
292 &mt
->getgrgid_retval
,
294 sizeof(mt
->getgrgid_buf
) );
296 if ((rc
!= 0) || (ptr
== NULL
))
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
;
313 # ifdef HAVE_GETPWUID_R_RETURNS_INT
315 &mt
->getpwuid_retval
,
317 sizeof(mt
->getpwuid_buf
),
320 ptr
= getpwuid_r(uid
,
321 &mt
->getpwuid_retval
,
323 sizeof(mt
->getpwuid_buf
) );
325 if ((rc
!= 0) || (ptr
== NULL
))
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
;
339 return(gmtime_r(time
,&mt
->gmtime_retval
));
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
));
357 /* see documentation of gethostbyname and gethostbyname_r */
358 struct hostent
*gethostbyname(const char *name
)
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
,
368 sizeof(mt
->gethbyn_buf
),
373 #ifdef HAVE_GETHOSTBYNAME_R_RETURNS_STRUCT_5_PARAMS
374 he
= gethostbyname_r(name
,
377 sizeof(mt
->gethbyn_buf
),
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
,
392 sizeof(mt
->inetntoa_buf
)));
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.
404 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
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 */
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
)
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
));
437 sizeof(mt
->random_buf
),
439 /* initstate calls srandom. We can return savely. */
442 srandom_r(seed
,&mt
->random
);
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
)));