2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * @brief hythread init/shutdown functions
24 #define LOG_DOMAIN "tm.init"
26 #include <open/hythread_ext.h>
27 #include "port_mutex.h"
28 #include "thread_private.h"
31 #include "thread_classlib_defs.h"
32 #endif /* HY_NO_THR */
36 // Global pointer to the threading library
37 hythread_library_t TM_LIBRARY
= NULL
;
39 //Thread manager memory pool
40 apr_pool_t
*TM_POOL
= NULL
;
43 apr_threadkey_t
*TM_THREAD_KEY
;
45 //Thread manager global lock
46 osmutex_t TM_START_LOCK
;
47 static int hythread_library_state
= TM_LIBRARY_STATUS_NOT_INITIALIZED
;
48 #define GLOBAL_MONITOR_NAME "global_monitor"
49 hythread_monitor_t p_global_monitor
;
51 //group for the threads created/attached to the NULL group
52 hythread_group_t TM_DEFAULT_GROUP
;
53 hythread_group_t group_list
;
57 static IDATA
init_group_list();
58 static IDATA
destroy_group_list();
62 BOOL WINAPI
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpres
) {
63 if (dwReason
== DLL_PROCESS_ATTACH
) {
64 hythread_lib_create(&TM_LIBRARY
);
69 void hythread_library_init(void) {
70 hythread_lib_create(&TM_LIBRARY
);
78 * Determine the size of the thread library.
80 * Given a thread library version, return the size of the structure in bytes
81 * required to be allocated.
83 * @param[in] version The HyThreadLibraryVersion structure.
84 * @return size of thread library on success, zero on failure
87 hythread_getSize (struct HyThreadLibraryVersion
* version
)
89 /* Can't initialize a structure that is not understood by this version of the thread library */
90 if (HYTHREAD_MAJOR_VERSION_NUMBER
!= version
->majorVersionNumber
)
95 return sizeof (HyThreadLibrary
);
99 * Stub startup function
101 HY_CFUNC THREXPORT I_32 VMCALL
102 hythread_startup_library (struct HyThreadLibraryInternal
*threadLibrary
)
104 /* Do nothing here - thread library initialised by hythread_allocate_library() */
109 * Shutdown the thread library - forwards call to hythread_shutdown()
111 HY_CFUNC THREXPORT I_32 VMCALL
112 hythread_shutdown_library (struct HyThreadLibraryInternal
*threadLibrary
)
119 * Allocate the thread library function table and return it's pointer
121 HY_CFUNC THREXPORT I_32 VMCALL
122 hythread_allocate_library (struct HyThreadLibraryVersion
*expectedVersion
,
123 struct HyThreadLibrary
**threadLibraryFuncs
)
125 UDATA size
= hythread_getSize (expectedVersion
);
126 HyThreadLibrary
*threadLib
;
133 hythread_lib_create(&TM_LIBRARY
);
135 /* Allocate memory for the function table */
136 *threadLibraryFuncs
= NULL
;
137 threadLib
= (HyThreadLibrary
*) apr_palloc(TM_POOL
, sizeof(HyThreadLibrary
));
138 if (NULL
== threadLib
)
143 /* Null and initialize the table passed in */
144 memset(threadLib
, 0, size
);
145 memcpy(threadLib
, &MasterThreadLibraryTable
, size
);
147 /* Set version numbers */
148 threadLib
->threadVersion
.majorVersionNumber
= expectedVersion
->majorVersionNumber
;
149 threadLib
->threadVersion
.minorVersionNumber
= expectedVersion
->minorVersionNumber
;
150 threadLib
->threadVersion
.capabilities
= HYTHREAD_CAPABILITY_MASK
;
152 threadLib
->self_handle
= threadLib
;
153 *threadLibraryFuncs
= threadLib
;
158 #endif /* HY_NO_THR */
161 * Creates and initializes a threading library.
163 * @param[out] lib pointer to the created thread library
164 * @return The thread library's initStatus will be set to 0 on success or
165 * a negative value on failure.
167 IDATA VMCALL
hythread_lib_create(hythread_library_t
* lib
) {
168 apr_status_t apr_status
;
170 // Current implementation doesn't support more than one library instance.
173 return TM_ERROR_NONE
;
176 apr_status
= apr_initialize();
177 assert(apr_status
== APR_SUCCESS
);
179 apr_status
= apr_pool_create(&TM_POOL
, NULL
);
180 if (apr_status
!= APR_SUCCESS
) return CONVERT_ERROR(apr_status
);
182 *lib
= (hythread_library_t
) apr_palloc(TM_POOL
, sizeof(HyThreadLibraryInternal
));
183 if (*lib
== NULL
) return TM_ERROR_OUT_OF_MEMORY
;
186 return TM_ERROR_NONE
;
190 * Shut down the threading library.
192 * @param lib the library
195 * @see hythread_lib_create
197 void VMCALL
hythread_lib_destroy(hythread_library_t lib
) {
198 apr_pool_destroy(TM_POOL
);
202 * Initialize a threading library.
204 * @note This must only be called once.
206 * If any OS threads were created before calling this function, they must be attached using
207 * hythread_attach before accessing any thread library functions.
209 * @param[in] lib pointer to the thread library to be initialized (non-NULL)
210 * @return The thread library's initStatus will be set to 0 on success or
211 * a negative value on failure.
213 void VMCALL
hythread_init(hythread_library_t lib
) {
214 apr_status_t apr_status
;
216 hythread_monitor_t
*mon
;
218 // Current implementation doesn't support more than one library instance.
219 if (TM_LIBRARY
== NULL
) {
222 assert(TM_LIBRARY
== lib
);
224 if (hythread_library_state
!= TM_LIBRARY_STATUS_NOT_INITIALIZED
)
226 hythread_library_state
= TM_LIBRARY_STATUS_INITIALIZED
;
228 apr_status
= apr_initialize();
229 assert(apr_status
== APR_SUCCESS
);
230 // TM_POOL will be NULL if hythread_lib_create was not used to create the library
231 if (TM_POOL
== NULL
) {
232 apr_status
= apr_pool_create(&TM_POOL
, NULL
);
233 assert(apr_status
== APR_SUCCESS
);
236 apr_status
= apr_threadkey_private_create(&TM_THREAD_KEY
, NULL
, TM_POOL
);
237 assert(apr_status
== APR_SUCCESS
);
239 status
= port_mutex_create(&lib
->TM_LOCK
, APR_THREAD_MUTEX_NESTED
);
240 assert(status
== TM_ERROR_NONE
);
241 status
= port_mutex_create(&TM_START_LOCK
, APR_THREAD_MUTEX_NESTED
);
242 assert(status
== TM_ERROR_NONE
);
244 status
= init_group_list();
245 assert(status
== TM_ERROR_NONE
);
247 // Create default group - hosts any thread crated with NULL group
248 status
= hythread_group_create(&TM_DEFAULT_GROUP
);
249 assert(status
== TM_ERROR_NONE
);
251 //nondaemon thread barrier
253 lib
->nondaemon_thread_count
= 0;
254 status
= hycond_create(&lib
->nondaemon_thread_cond
);
255 assert(status
== TM_ERROR_NONE
);
257 // init global monitor
258 status
=hythread_monitor_init_with_name(&p_global_monitor
, 0, "Thread Global Monitor");
259 assert(status
== TM_ERROR_NONE
);
261 mon
= (hythread_monitor_t
*)hythread_global(GLOBAL_MONITOR_NAME
);
262 *mon
= p_global_monitor
;
267 * Prepares to shutdown the hythread library.
273 void VMCALL
hythread_shutdowning() {
274 hythread_library_state
= TM_LIBRARY_STATUS_SHUTDOWN
;
278 * Returns hythread library state
280 int VMCALL
hythread_lib_state() {
281 return hythread_library_state
;
285 * Shut down the threading library associated with the current thread.
291 void VMCALL
hythread_shutdown() {
292 hythread_lib_destroy(hythread_self()->library
);
296 * Acquires global lock of the library associated with the current thread.
298 * @param[in] self current thread
300 void VMCALL
hythread_lib_lock(hythread_t self
) {
303 assert(self
== hythread_self());
304 status
= port_mutex_lock(&self
->library
->TM_LOCK
);
305 assert(status
== TM_ERROR_NONE
);
309 * Releases global lock of the library associated with the current thread.
311 * @param[in] self current thread
313 void VMCALL
hythread_lib_unlock(hythread_t self
) {
316 assert(self
== hythread_self());
317 status
= port_mutex_unlock(&self
->library
->TM_LOCK
);
318 assert(status
== TM_ERROR_NONE
);
322 * Acquires the lock over threading subsystem.
324 * The lock blocks new thread creation and thread exit operations.
326 IDATA VMCALL
hythread_global_lock() {
328 hythread_t self
= hythread_self();
330 // we need not care about suspension if the thread
331 // is not even attached to hythread
333 return port_mutex_lock(&TM_LIBRARY
->TM_LOCK
);
336 // disable_count must be 0 on potentially
337 // blocking operation to prevent suspension deadlocks,
338 // meaning that the thread is safe for suspension
339 assert(hythread_is_suspend_enabled());
341 status
= port_mutex_lock(&TM_LIBRARY
->TM_LOCK
);
342 assert(status
== TM_ERROR_NONE
);
344 // make sure we do not get a global thread lock
345 // while being requested to suspend
346 while (self
->suspend_count
) {
347 // give up global thread lock before safepoint,
348 // because this thread can be suspended at a safepoint
349 status
= port_mutex_unlock(&TM_LIBRARY
->TM_LOCK
);
350 assert(status
== TM_ERROR_NONE
);
351 hythread_safe_point();
352 status
= port_mutex_lock(&TM_LIBRARY
->TM_LOCK
);
353 assert(status
== TM_ERROR_NONE
);
355 return TM_ERROR_NONE
;
359 * Releases the lock over threading subsystem.
362 IDATA VMCALL
hythread_global_unlock() {
364 assert(!hythread_self() || hythread_is_suspend_enabled());
365 status
= port_mutex_unlock(&TM_LIBRARY
->TM_LOCK
);
366 assert(status
== TM_ERROR_NONE
);
367 return TM_ERROR_NONE
;
370 hythread_group_t VMCALL
get_java_thread_group(void) {
371 return TM_DEFAULT_GROUP
;
374 static IDATA
init_group_list() {
375 // Initial group, does not contain any actual group, but serves
376 //as a head and a tail of this list;
377 hythread_group_t dummy
;
380 //this group will exist as long as TM lives, so it's ok to have
381 //the same pool for them
383 dummy
= (hythread_group_t
)apr_pcalloc(TM_POOL
, sizeof(HyThreadGroup
));
386 dummy
->next
= dummy
->prev
= dummy
;
390 lock_table
= (HyFatLockTable
*) malloc (sizeof(HyFatLockTable
));
391 memset(lock_table
, 0, sizeof(HyFatLockTable
));
392 lock_table
->tables
[0] = (hythread_monitor_t
*)calloc(HY_FAT_TABLE_ENTRIES
,
393 sizeof(hythread_monitor_t
));
394 lock_table
->live_objs
= (unsigned char *)calloc(HY_FAT_TABLE_ENTRIES
,
395 sizeof(unsigned char));
396 lock_table
->size
= HY_FAT_TABLE_ENTRIES
;
397 lock_table
->array_cursor
= 0;
400 assert (lock_table
->tables
[0]);
401 assert (lock_table
->live_objs
);
403 if (port_mutex_create(&lock_table
->mutex
, APR_THREAD_MUTEX_NESTED
)) {
404 return TM_ERROR_OUT_OF_MEMORY
;
407 if (hycond_create(&lock_table
->write
)) {
408 return TM_ERROR_OUT_OF_MEMORY
;
411 if (hycond_create(&lock_table
->read
)) {
412 return TM_ERROR_OUT_OF_MEMORY
;
415 lock_table
->readers_reading
= 0;
416 lock_table
->readers_waiting
= 0;
417 lock_table
->writers_waiting
= 0;
418 lock_table
->state
= HYTHREAD_LOCKTABLE_IDLE
;
420 return TM_ERROR_NONE
;
423 static IDATA
destroy_group_list() {
424 hythread_group_t cur
;
425 IDATA status
,status2
;
428 // This method works only if there are no running threads.
429 // there is no good way to kill running threads
430 status
=hythread_global_lock();
431 if (status
!= TM_ERROR_NONE
) return status
;
433 cur
= group_list
->next
;
434 status
= TM_ERROR_NONE
;
436 while (cur
!= group_list
) {
437 if (hythread_group_release(cur
) == TM_ERROR_NONE
) {
438 cur
= group_list
->next
;
440 status
= TM_ERROR_RUNNING_THREADS
;
445 free(lock_table
->live_objs
);
447 for (i
= 0; i
< HY_MAX_FAT_TABLES
&& lock_table
->tables
[i
]; i
++) {
448 free(lock_table
->tables
[i
]);
451 port_mutex_destroy(&lock_table
->mutex
);
452 hycond_destroy(&lock_table
->write
);
453 hycond_destroy(&lock_table
->read
);
457 status2
=hythread_global_unlock();
458 if (status2
!= TM_ERROR_NONE
) return status2
;
463 IDATA
acquire_start_lock() {
464 return port_mutex_lock(&TM_START_LOCK
);
467 IDATA
release_start_lock() {
468 return port_mutex_unlock(&TM_START_LOCK
);
472 // very simple Map implementation
473 // current scenario use only one global so it works well
474 // need to be hashtable in the future
476 #define TABLE_SIZE 256
477 const char *names
[TABLE_SIZE
];
478 UDATA data
[TABLE_SIZE
];
482 * return index in array if found, -1 otherwise
484 int find_entry (const char* name
) {
487 for (i
= 0; i
< size
; i
++) {
488 if (names
[i
] == name
) {
493 for (i
= 0; i
< size
; i
++) {
494 if (strcmp(names
[i
], name
) == 0) {
500 //add entry to the end of the array
501 // return new entry index, -1 if failed.
502 int add_entry(const char* name
) {
504 if (index
>= TABLE_SIZE
-1) {
513 * Fetch or create a 'named global'.
515 * Return a pointer to the data associated with a named global with the specified name.<br>
516 * A new named global is created if a named global with the specified name can't be found.
518 * @param[in] name name of named global to read/create
519 * @return a pointer to a UDATA associated with name<br>
523 UDATA
* VMCALL
hythread_global (const char* name
) {
524 //hythread_monitor_enter(*p_global_monitor);
525 int index
= find_entry(name
);
527 index
= add_entry(name
);
530 //hythread_monitor_exit(*p_global_monitor);
534 //hythread_monitor_exit(*p_global_monitor);