1 /* This is the file to support POSIX threads.
2 * We initialize the global data structure and the global access variable.
14 typedef struct _MT_mem
{
17 /* real data follows here */
20 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
21 struct group getgrgid_retval
;
22 char getgrgid_buf
[2048]; /* AT LEAST 1K, better 2K or 4K */
23 struct passwd getpwuid_retval
;
24 char getpwuid_buf
[2048]; /* AT LEAST 1K, better 2K or 4K */
25 struct tm gmtime_retval
;
26 struct tm localtime_retval
;
27 #ifdef HAVE_RANDOM_DATA
28 struct random_data random
;
29 char random_buf
[64]; /* at least sizeof(clock_t) and time_t */
32 char strerror_buf
[1024];
34 } mt_tsd_t
; /* thread-specific but only needed by this module. see
35 * ReginaInitializeThread
38 static pthread_key_t ThreadIndex
; /* index of the TSD, no initial value */
39 static pthread_once_t ThreadOnce
= PTHREAD_ONCE_INIT
; /* for pthread_once */
41 /* Deinitialize is called when the thread terminates.
42 * This is a wonderful position to place code which frees all allocated stuff!
44 static void Deinitialize(void *buf
)
50 if (TSD
== NULL
) /* Should never happen but be sure */
58 while ((chunk
= mt
->mem_base
) != NULL
)
60 TSD
->MTFree(TSD
,chunk
+ 1);
61 if (mt
->mem_base
== chunk
)
62 break; /* something goes wrong. Don't run into an endless loop */
70 /* ThreadGetKey creates a new index key into the TSD table. This function
71 * must only be used by pthread_once.
73 static void ThreadGetKey(void)
75 pthread_key_create(&ThreadIndex
,Deinitialize
);
78 /* Lowest level memory allocation function for normal circumstances. */
79 static void *MTMalloc(const tsd_t
*TSD
,size_t size
)
82 MT_mem
*new = malloc(size
+ sizeof(MT_mem
));
84 if (new == NULL
) /* may happen. errors are detected in the above layers */
89 new->next
= mt
->mem_base
;
91 mt
->mem_base
->prev
= new;
93 return(new + 1); /* jump over the head */
96 /* Lowest level memory deallocation function for normal circumstances. */
97 static void MTFree(const tsd_t
*TSD
,void *chunk
)
99 mt_tsd_t
*mt
= TSD
->mt_tsd
;
103 this--; /* Go to the header of the chunk */
106 if (this->prev
->next
!= this)
109 if (this->next
->prev
!= this)
112 /* This is a chunk allocated by MTMalloc */
114 this->prev
->next
= this->next
;
116 this->next
->prev
= this->prev
;
117 if (this == mt
->mem_base
)
118 mt
->mem_base
= this->next
;
120 /* Last not least we set the pointers to NULL. This prevents a double-free*/
126 /* Lowest level exit handler. */
127 static void MTExit(int code
)
129 /* pthread_exit's argument has a different semantic as exit has. */
133 /* ReginaInitializeThread creates a new thread structure and returns a ptr
134 * to the initialized value.
135 * The function may be called more than once.
137 tsd_t
*ReginaInitializeThread(void)
142 /* get a unique access variable for the whole process */
143 pthread_once(&ThreadOnce
,ThreadGetKey
);
145 /* fetch the value of the access variable */
146 retval
= pthread_getspecific(ThreadIndex
);
151 /* First call in this thread... */
152 retval
= malloc(sizeof(tsd_t
)); /* no Malloc, etc! */
154 if (retval
== NULL
) /* THIS is really a problem. I don't know what we */
155 return(NULL
); /* should do now. Let the caller run into a crash... */
157 pthread_setspecific(ThreadIndex
,retval
);
159 memset(retval
,0,sizeof(tsd_t
));
160 retval
->MTMalloc
= MTMalloc
;
161 retval
->MTFree
= MTFree
;
162 retval
->MTExit
= MTExit
;
164 /* Since the local data structure contains a memory chain for the memory
165 * management we initialize it first.
167 if ((retval
->mt_tsd
= malloc(sizeof(mt_tsd_t
))) == NULL
)
168 return(NULL
); /* This is a catastrophy */
169 memset(retval
->mt_tsd
,0,sizeof(mt_tsd_t
));
171 OK
= init_memory(retval
); /* Initialize the memory module FIRST*/
173 /* Without the initial memory we don't have ANY chance! */
177 OK
&= init_vars(retval
); /* Initialize the variable module */
178 OK
&= init_stacks(retval
); /* Initialize the stack module */
179 OK
&= init_filetable(retval
); /* Initialize the files module */
180 OK
&= init_math(retval
); /* Initialize the math module */
181 OK
&= init_spec_vars(retval
); /* Initialize the interprt module */
182 OK
&= init_tracing(retval
); /* Initialize the tracing module */
183 OK
&= init_builtin(retval
); /* Initialize the builtin module */
184 OK
&= init_client(retval
); /* Initialize the client module */
185 OK
&= init_library(retval
); /* Initialize the library module */
186 OK
&= init_rexxsaa(retval
); /* Initialize the rexxsaa module */
187 OK
&= init_shell(retval
); /* Initialize the shell module */
188 OK
&= init_envir(retval
); /* Initialize the envir module */
189 OK
&= init_expr(retval
); /* Initialize the expr module */
190 OK
&= init_error(retval
); /* Initialize the error module */
192 OK
&= init_vms(retval
); /* Initialize the vmscmd module */
193 OK
&= init_vmf(retval
); /* Initialize the vmsfuncs module */
195 OK
|= init_arexxf(&__regina_tsd
); /* Initialize the arexxfuncs modules */
196 retval
->loopcnt
= 1; /* stupid r2perl-module */
197 retval
->traceparse
= -1;
198 retval
->thread_id
= (unsigned long)pthread_self();
201 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
206 /* __regina_get_tsd returns a pointer to the thread specific data. Be sure to
207 * calls this after a ReginaInitializeThread only.
209 tsd_t
*__regina_get_tsd(void)
211 /* See above for comments */
212 return(pthread_getspecific(ThreadIndex
));
215 /******************************************************************************
216 ******************************************************************************
217 * Emulation functions to support multi-threading *****************************
218 * The functions will be opaque to the caller *********************************
219 * The "original" functions at this place are not multi-threading safe ********
220 ******************************************************************************
221 *****************************************************************************/
222 #if defined(HAVE_GETGRGID_R_RETURNS_INT_5_PARAMS) || defined(HAVE_GETGRGID_R_RETURNS_INT_4_PARAMS) ||defined(HAVE_GETGRGID_R_RETURNS_STRUCT)
223 /* see documentation of getgrgid and getgrgid_r */
224 struct group
*getgrgid(gid_t gid
)
226 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
229 # ifdef HAVE_GETGRGID_R_RETURNS_INT_5_PARAMS
231 &mt
->getgrgid_retval
,
233 sizeof(mt
->getgrgid_buf
),
236 # ifdef HAVE_GETGRGID_R_RETURNS_INT_4_PARAMS
238 &mt
->getgrgid_retval
,
240 sizeof(mt
->getgrgid_buf
));
241 ptr
= &mt
->getgrgid_retval
;
243 # ifdef HAVE_GETGRGID_R_RETURNS_STRUCT
244 ptr
= getgrgid_r(gid
,
245 &mt
->getgrgid_retval
,
247 sizeof(mt
->getgrgid_buf
) );
249 if ((rc
!= 0) || (ptr
== NULL
))
258 #if defined(HAVE_GETPWUID_R_RETURNS_INT) || defined(HAVE_GETPWUID_R_RETURNS_STRUCT)
259 /* see documentation of getpwuid and getpwuid_r */
260 struct passwd
*getpwuid(uid_t uid
)
262 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
266 # ifdef HAVE_GETPWUID_R_RETURNS_INT
268 &mt
->getpwuid_retval
,
270 sizeof(mt
->getpwuid_buf
),
273 ptr
= getpwuid_r(uid
,
274 &mt
->getpwuid_retval
,
276 sizeof(mt
->getpwuid_buf
) );
278 if ((rc
!= 0) || (ptr
== NULL
))
287 /* see documentation of gmtime and gmtime_r */
288 struct tm
*gmtime(const time_t *time
)
290 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
292 return(gmtime_r(time
,&mt
->gmtime_retval
));
295 /* see documentation of localtime and localtime_r */
296 struct tm
*localtime(const time_t *time
)
298 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
300 return(localtime_r(time
,&mt
->localtime_retval
));
303 #if defined( HAVE_RANDOM_DATA ) && !defined( HAVE_RANDOM )
304 /* see documentation of random and random_r. If you get compile time errors
305 * exclude this function.
309 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
312 if (!mt
->random_init
) /* according to the ANSI this is equivalent to */
313 srandom(1); /* an initial value of 1 for the seed! */
314 random_r(&mt
->random
,&retval
); /* ignore errors, we MUST return anything */
318 /* see documentation of srandom and srandom_r. If you get compile time errors
319 * exclude this function.
321 void srandom(unsigned seed
)
323 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
324 /* The stack is normally not cleared: wonderful random stuff. */
325 char this_is_random_stuff
[sizeof(mt
->random_buf
)];
327 if (!mt
->random_init
)
330 /* In case of a cleared new stack seqment we initialize our buffer
331 * with at least one random stuff:
333 time((time_t *) this_is_random_stuff
);
334 /* If the buffer is large enough, use a second one */
335 if (sizeof(time_t) + sizeof(clock_t) < sizeof(this_is_random_stuff
))
336 *((clock_t *) (this_is_random_stuff
+ sizeof(time_t))) = clock();
338 memcpy(mt
->random_buf
,this_is_random_stuff
,sizeof(mt
->random_buf
));
342 sizeof(mt
->random_buf
),
344 /* initstate calls srandom. We can return savely. */
347 srandom_r(seed
,&mt
->random
);
352 /* see documentation of strerror and strerror_r. */
353 char *strerror(int errnum
)
355 mt_tsd_t
*mt
= __regina_get_tsd()->mt_tsd
;
357 return(strerror_r(errnum
,mt
->strerror_buf
,sizeof(mt
->strerror_buf
)));