[r815644] Change hythread API to use 'const char*' for constant strings rather than
[drlvm.git] / vm / thread / src / thread_init.c
blob7b18f92e354a66a6505ccf7f2b07b45dece6976f
1 /*
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.
18 /**
19 * @file thread_init.c
20 * @brief hythread init/shutdown functions
23 #undef LOG_DOMAIN
24 #define LOG_DOMAIN "tm.init"
26 #include <open/hythread_ext.h>
27 #include "port_mutex.h"
28 #include "thread_private.h"
30 #ifdef HY_NO_THR
31 #include "thread_classlib_defs.h"
32 #endif /* HY_NO_THR */
34 //global constants:
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;
42 //TLS key
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;
55 IDATA groups_count;
57 static IDATA init_group_list();
58 static IDATA destroy_group_list();
60 #ifdef WIN32
61 #include <windows.h>
62 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpres) {
63 if (dwReason == DLL_PROCESS_ATTACH) {
64 hythread_lib_create(&TM_LIBRARY);
66 return TRUE;
68 #else
69 void hythread_library_init(void) {
70 hythread_lib_create(&TM_LIBRARY);
72 #endif
75 #ifdef HY_NO_THR
77 /**
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
86 UDATA VMCALL
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)
92 return 0;
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() */
105 return 0;
109 * Shutdown the thread library - forwards call to hythread_shutdown()
111 HY_CFUNC THREXPORT I_32 VMCALL
112 hythread_shutdown_library (struct HyThreadLibraryInternal *threadLibrary)
114 hythread_shutdown();
115 return 0;
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;
128 if (0 == size)
130 return -1;
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)
140 return -1;
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;
155 return 0;
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.
171 if (TM_LIBRARY) {
172 *lib = TM_LIBRARY;
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;
185 hythread_init(*lib);
186 return TM_ERROR_NONE;
190 * Shut down the threading library.
192 * @param lib the library
193 * @return none
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;
215 IDATA status;
216 hythread_monitor_t *mon;
218 // Current implementation doesn't support more than one library instance.
219 if (TM_LIBRARY == NULL) {
220 TM_LIBRARY = lib;
222 assert(TM_LIBRARY == lib);
224 if (hythread_library_state != TM_LIBRARY_STATUS_NOT_INITIALIZED)
225 return;
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
252 ////
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;
263 assert(mon);
267 * Prepares to shutdown the hythread library.
269 * @return none
271 * @see hythread_init
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.
287 * @return none
289 * @see hythread_init
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) {
301 IDATA status;
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) {
314 IDATA status;
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() {
327 IDATA status;
328 hythread_t self = hythread_self();
330 // we need not care about suspension if the thread
331 // is not even attached to hythread
332 if (self == NULL) {
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() {
363 IDATA status;
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
382 ////
383 dummy = (hythread_group_t)apr_pcalloc(TM_POOL, sizeof(HyThreadGroup));
384 assert(dummy);
386 dummy->next = dummy->prev = dummy;
387 group_list = dummy;
388 groups_count = 0;
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;
399 assert (lock_table);
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;
426 int i;
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;
439 } else {
440 status = TM_ERROR_RUNNING_THREADS;
441 cur = cur->next;
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);
455 free(lock_table);
457 status2=hythread_global_unlock();
458 if (status2 != TM_ERROR_NONE) return status2;
460 return status;
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];
479 int size = 0;
482 * return index in array if found, -1 otherwise
484 int find_entry (const char* name) {
485 // quick pass
486 int i;
487 for (i = 0; i < size; i++) {
488 if (names[i] == name) {
489 return i;
492 // strcmp pass.
493 for (i = 0; i < size; i++) {
494 if (strcmp(names[i], name) == 0) {
495 return i;
498 return -1;
500 //add entry to the end of the array
501 // return new entry index, -1 if failed.
502 int add_entry(const char* name) {
503 int index = size++;
504 if (index >= TABLE_SIZE-1) {
505 return -1;
507 names[index] = name;
508 data[index] = 0;
509 return index;
512 /**
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>
520 * 0 on failure.
523 UDATA* VMCALL hythread_global (const char* name) {
524 //hythread_monitor_enter(*p_global_monitor);
525 int index = find_entry(name);
526 if (index == -1) {
527 index = add_entry(name);
528 assert(index >=0);
529 if (index < 0) {
530 //hythread_monitor_exit(*p_global_monitor);
531 return NULL;
534 //hythread_monitor_exit(*p_global_monitor);
535 return data+index;