1 /* This is the file to support single-threading.
2 * We initialize the global data structure and the global access variable.
7 #define DONT_TYPEDEF_PFN
10 typedef struct _MT_mem
{
13 /* real data follows here */
16 typedef struct { /* mt_tsd: static variables of this module (thread-safe) */
18 } mt_tsd_t
; /* thread-specific but only needed by this module. see
19 * ReginaInitializeThread
22 int __regina_tsd_initialized
= 0;
23 tsd_t __regina_tsd
= {0,}; /* Be sure the var is initialized here */
25 /* Lowest level memory allocation function for normal circumstances. */
26 static void *MTMalloc(const tsd_t
*TSD
,size_t size
)
29 MT_mem
*newptr
= (MT_mem
*)malloc(size
+ sizeof(MT_mem
));
31 if (newptr
== NULL
) /* may happen. errors are detected in the above layers */
34 mt
= (mt_tsd_t
*)TSD
->mt_tsd
;
36 newptr
->next
= mt
->mem_base
;
38 mt
->mem_base
->prev
= newptr
;
39 mt
->mem_base
= newptr
;
40 return(newptr
+ 1); /* jump over the head */
43 /* Lowest level memory deallocation function for normal circumstances. */
44 static void MTFree(const tsd_t
*TSD
,void *chunk
)
46 mt_tsd_t
*mt
= (mt_tsd_t
*)TSD
->mt_tsd
;
55 thisptr
= (MT_mem
*)chunk
;
56 thisptr
--; /* Go to the header of the chunk */
60 if (thisptr
->prev
->next
!= thisptr
)
65 if (thisptr
->next
->prev
!= thisptr
)
69 /* This is a chunk allocated by MTMalloc */
71 thisptr
->prev
->next
= thisptr
->next
;
73 thisptr
->next
->prev
= thisptr
->prev
;
74 if (thisptr
== mt
->mem_base
)
75 mt
->mem_base
= thisptr
->next
;
77 /* Last not least we set the pointers to NULL. This prevents a double-free*/
83 /* Lowest level exit handler. Use this indirection to prevent errors. */
84 static void MTExit(int code
)
89 int IfcReginaCleanup( VOID
)
91 tsd_t
*TSD
= &__regina_tsd
;
95 if (!__regina_tsd_initialized
)
98 __regina_tsd_initialized
= 0;
102 mt
= (mt_tsd_t
*)TSD
->mt_tsd
;
105 while ((chunk
= mt
->mem_base
) != NULL
)
107 TSD
->MTFree(TSD
,chunk
+ 1);
108 if (mt
->mem_base
== chunk
)
109 break; /* something goes wrong. Don't run into an endless loop */
114 memset( TSD
, 0, sizeof(tsd_t
) );
118 tsd_t
*ReginaInitializeProcess(void)
122 if (__regina_tsd_initialized
)
123 return(&__regina_tsd
);
124 __regina_tsd_initialized
= 1;
126 /* Set up the current (single) tsd_t:*/
127 /* Default all values to zero */
128 memset(&__regina_tsd
,0,sizeof(__regina_tsd
));
129 __regina_tsd
.MTMalloc
= MTMalloc
;
130 __regina_tsd
.MTFree
= MTFree
;
131 __regina_tsd
.MTExit
= MTExit
;
133 /* Since the local data structure contains a memory chain for the memory
134 * management we initialize it first.
136 if ((__regina_tsd
.mt_tsd
= malloc(sizeof(mt_tsd_t
))) == NULL
)
137 return(NULL
); /* This is a catastrophy */
138 memset(__regina_tsd
.mt_tsd
,0,sizeof(mt_tsd_t
));
140 OK
= init_memory(&__regina_tsd
); /* Initialize the memory module FIRST*/
142 /* Without the initial memory we don't have ANY chance! */
147 * Some systems with an own MT file don't compile in MT mode. But they
148 * still are systems of that kind.
150 #if defined(WIN32) || defined(__WIN32__)
152 extern OS_Dep_funcs __regina_OS_Win
;
153 __regina_tsd
.OS
= &__regina_OS_Win
;
155 #elif defined(OS2) && !defined(DOS)
157 extern OS_Dep_funcs __regina_OS_Os2
;
158 __regina_tsd
.OS
= &__regina_OS_Os2
;
162 extern OS_Dep_funcs __regina_OS_Other
;
163 __regina_tsd
.OS
= &__regina_OS_Other
;
165 #elif defined(unix) || defined(__unix__) || defined(__unix) || defined(__QNX__) || defined(__BEOS__) || defined(SKYOS) || ( defined( __APPLE_CC__ ) && defined( __MACH__ ) ) || defined(AIX)
167 extern OS_Dep_funcs __regina_OS_Unx
;
168 __regina_tsd
.OS
= &__regina_OS_Unx
;
170 #elif defined(_AMIGA) || defined(__AROS__)
172 extern OS_Dep_funcs __regina_OS_Amiga
;
173 __regina_tsd
.OS
= &__regina_OS_Amiga
;
177 extern OS_Dep_funcs __regina_OS_Other
;
178 __regina_tsd
.OS
= &__regina_OS_Other
;
181 __regina_tsd
.OS
->init();
182 OK
|= init_vars(&__regina_tsd
); /* Initialize the variable module */
183 OK
|= init_stacks(&__regina_tsd
); /* Initialize the stack module */
184 OK
|= init_filetable(&__regina_tsd
); /* Initialize the files module */
185 OK
|= init_math(&__regina_tsd
); /* Initialize the math module */
186 OK
|= init_spec_vars(&__regina_tsd
); /* Initialize the interprt module */
187 OK
|= init_tracing(&__regina_tsd
); /* Initialize the tracing module */
188 OK
|= init_builtin(&__regina_tsd
); /* Initialize the builtin module */
189 OK
|= init_client(&__regina_tsd
); /* Initialize the client module */
190 OK
|= init_library(&__regina_tsd
); /* Initialize the library module */
191 OK
|= init_rexxsaa(&__regina_tsd
); /* Initialize the rexxsaa module */
192 OK
|= init_shell(&__regina_tsd
); /* Initialize the shell module */
193 OK
|= init_envir(&__regina_tsd
); /* Initialize the envir module */
194 OK
|= init_expr(&__regina_tsd
); /* Initialize the expr module */
195 OK
|= init_error(&__regina_tsd
); /* Initialize the error module */
197 OK
|= init_vms(&__regina_tsd
); /* Initialize the vmscmd module */
198 OK
|= init_vmf(&__regina_tsd
); /* Initialize the vmsfuncs module */
200 OK
|= init_arexxf(&__regina_tsd
); /* Initialize the arxfuncs modules */
201 #if defined(_AMIGA) || defined(__AROS__)
202 OK
|= init_amigaf(&__regina_tsd
);
204 __regina_tsd
.loopcnt
= 1; /* stupid r2perl-module */
205 __regina_tsd
.traceparse
= -1;
206 __regina_tsd
.thread_id
= 1;
209 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
211 return(&__regina_tsd
);
215 #ifdef TRACK_TSD_USAGE
216 /* We may want to check the counts of calls to __regina_get_tsd() which may do
217 * MUCH work on different platforms. We do some not optimizable work here.
218 * If you really wanna track down all calls to figure out WHERE to
219 * optimize try under a GNU friendly system:
220 * 1) In Makefile: Add "-pg -a" to the variable called "CFLAGS".
221 * 2) "make rexx" (Other targets might not work)
222 * 3) "./rexx whatyoulike.rexx"
223 * 4) "gprof rexx >usage.lst"
224 * 5) look at usage.lst for occurances of "WorkHeavy".
227 volatile int __regina_Calls
= 300; /* factor to get a "feel" for multithreading */
228 volatile int __regina_Point
= 1;
230 void __regina_Nop(void)
235 /* WorkHeavy does some work and returns the correct thread-specific data. */
236 tsd_t
*__regina_WorkHeavy(void)
238 int todo
= __regina_Calls
;
241 return(&__regina_tsd
);