--- gcv4\src\gc_thread.h 2006-10-16 13:07:10.000000000 +-0600
+++ gcv4\src\gc_thread.h 2006-12-19 11:40:23.000000000 +-0600
@@ -116,12 +116,16 @@
void reset(bool);
void wait_for_work();
void signal_work_is_done();
+ void send_shutdown_request();
+
+ bool is_shutdown_requested() { return _gc_shutdown_request; }
+
inline gc_thread_action get_task_to_do() {
return _task_to_do;
}
inline void set_task_to_do(gc_thread_action task) {
_task_to_do = task;
@@ -192,12 +196,14 @@
return stash;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
private:
+ // true if current thread was requested to stop, false otherwise
+ volatile bool _gc_shutdown_request;
int _sweep_start_index;
int _num_chunks_to_sweep;
#ifdef _DEBUG
chunk_sweep_stats _sweep_stats[GC_MAX_CHUNKS];
--- gcv4\src\gc_threads.cpp 2006-10-16 13:07:09.000000000 +-0600
+++ gcv4\src\gc_threads.cpp 2006-12-19 12:30:43.000000000 +-0600
@@ -60,12 +60,13 @@
extern bool mark_scan_load_balanced;
extern bool cross_block_compaction;
extern bool sweeps_during_gc;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void gc_thread_shutdown_callback(void * data);
int __cdecl gc_thread_func (void *arg);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GC_Mark_Activity::GC_Mark_Activity(Garbage_Collector *p_gc) {
assert(p_gc);
_p_gc = p_gc;
@@ -99,12 +100,13 @@
}
GC_Thread::GC_Thread(Garbage_Collector *p_gc, int gc_thread_id)
: GC_Mark_Activity(p_gc)
{
+ _gc_shutdown_request = false;
_id = gc_thread_id;
stash = NULL;
if (sweeps_during_gc) {
@@ -120,13 +122,14 @@
assert(stat == TM_ERROR_NONE);
//////////////////
stat = hysem_create(&_gc_thread_work_done_event, 0, 1);
assert(stat == TM_ERROR_NONE);
_thread_handle=NULL;
- stat = hythread_create_with_group(&_thread_handle, get_thread_group(), 0, 0, 0, gc_thread_func, this);
+ stat = hythread_create_with_group(&_thread_handle, get_thread_group(), 0, 0, 0,
+ gc_thread_func, this, gc_thread_shutdown_callback, this);
if (stat != TM_ERROR_NONE) {
DIE("GC_Thread::GC_Thread(..): CreateThread() failed...exiting...");
}
// Reset every GC
_num_bytes_recovered_by_sweep = 0;
@@ -186,26 +189,42 @@
{
// I am done with my job. SIGNAL MASTER THREAD
IDATA UNUSED sstat = hysem_post(_gc_thread_work_done_event);
assert(sstat == TM_ERROR_NONE);
}
+void
+GC_Thread::send_shutdown_request() {
+ _gc_shutdown_request = true;
+ IDATA UNUSED wstat = hysem_post(_gc_thread_start_work_event);
+ assert(wstat == TM_ERROR_NONE);
+}
volatile POINTER_SIZE_INT dummy_for_good_cache_performance = 0;
+void gc_thread_shutdown_callback(void * data) {
+ GC_Thread *p_gc_thread = (GC_Thread *) data;
+ p_gc_thread->send_shutdown_request();
+}
int __cdecl gc_thread_func (void *arg)
{
GC_Thread *p_gc_thread = (GC_Thread *) arg;
assert(p_gc_thread);
apr_time_t task_start_time, task_end_time;
while(true) {
//I will go to sleep forever or until the next time I am woken up with work
p_gc_thread->wait_for_work();
+
+ if (p_gc_thread->is_shutdown_requested()) {
+ return 0;
+ }
+
+
// When thread is woken up, it has work to do.
assert(p_gc_thread->get_task_to_do() != GC_BOGUS_TASK);
if (p_gc_thread->get_task_to_do() == GC_MARK_SCAN_TASK) {
gc_time_start_hook(&task_start_time);
--- include\open\hythread_ext.h 2006-12-08 18:48:39.000000000 +-0600
+++ include\open\hythread_ext.h 2006-12-19 11:19:12.000000000 +-0600
@@ -134,44 +134,53 @@
typedef struct HyThread *hythread_iterator_t;
typedef struct HyThreadLibrary *hythread_library_t;
typedef I_32 hythread_thin_monitor_t;
typedef void (*hythread_event_callback_proc)(void);
+typedef void (* hythread_shutdown_callback_t)(void *);
+
//@}
/** @name Thread Manager initialization / shutdown
*/
//@{
//temporary, should be static for the file containing dinamic library
//initialization
////
+#define TM_LIBRARY_STATE_GET 0
+#define TM_LIBRARY_STATE_INITIALIZED 1
+#define TM_LIBRARY_STATE_BLOCKED 2
+
IDATA VMCALL hythread_global_lock();
IDATA VMCALL hythread_global_unlock();
void VMCALL hythread_init(hythread_library_t lib);
void VMCALL hythread_shutdown();
IDATA VMCALL hythread_lib_create(hythread_library_t * lib);
void VMCALL hythread_lib_destroy(hythread_library_t lib);
+IDATA VMCALL hythread_lib_set_state(hythread_library_t lib, IDATA state);
//@}
/** @name Basic manipulation
*/
//@{
-IDATA VMCALL hythread_attach_ex(hythread_t *handle, hythread_library_t lib);
-IDATA VMCALL hythread_attach_to_group(hythread_t *handle, hythread_library_t lib, hythread_group_t group);
-IDATA hythread_create_with_group(hythread_t *ret_thread, hythread_group_t group, UDATA stacksize, UDATA priority, UDATA suspend, hythread_entrypoint_t func, void *data);
+IDATA VMCALL hythread_attach_ex(hythread_t *handle, hythread_library_t lib, hythread_shutdown_callback_t callback, void * callback_data);
+IDATA VMCALL hythread_attach_to_group(hythread_t *handle, hythread_library_t lib, hythread_group_t group, hythread_shutdown_callback_t callback, void * callback_data);
+IDATA hythread_create_ex(hythread_t *ret_thread, UDATA stacksize, UDATA priority, UDATA suspend, hythread_entrypoint_t func, void *data, hythread_shutdown_callback_t callback, void * callback_data);
+IDATA hythread_create_with_group(hythread_t *ret_thread, hythread_group_t group, UDATA stacksize, UDATA priority, UDATA suspend, hythread_entrypoint_t func, void *data, hythread_shutdown_callback_t callback, void * callback_data);
UDATA VMCALL hythread_clear_interrupted_other(hythread_t thread);
IDATA VMCALL hythread_join(hythread_t t);
IDATA VMCALL hythread_join_timed(hythread_t t, I_64 millis, IDATA nanos);
IDATA VMCALL hythread_join_interruptable(hythread_t t, I_64 millis, IDATA nanos);
IDATA VMCALL hythread_get_self_id();
IDATA VMCALL hythread_get_id(hythread_t t);
hythread_t VMCALL hythread_get_thread(IDATA id);
IDATA VMCALL hythread_struct_init(hythread_t *ret_thread);
+IDATA VMCALL hythread_cancel_safe(hythread_t thread);
IDATA VMCALL hythread_cancel_all(hythread_group_t group);
IDATA hythread_group_create(hythread_group_t *group);
IDATA VMCALL hythread_group_release(hythread_group_t group);
IDATA VMCALL hythread_group_get_list(hythread_group_t **list, int* size);
void* VMCALL hythread_get_private_data(hythread_t t);
IDATA VMCALL hythread_set_private_data(hythread_t t, void* data);
--- tests\unit\thread\test_native_basic.c 2006-11-24 19:34:16.000000000 +-0600
+++ tests\unit\thread\test_native_basic.c 2006-12-18 19:39:05.000000000 +-0600
@@ -49,13 +49,13 @@
hythread_group_create((hythread_group_t *)&args[0]);
args[1] = apr_palloc(pool, sizeof(jthread_threadattr_t));
((jthread_threadattr_t *)args[1])->stacksize = 1024;
((jthread_threadattr_t *)args[1])->priority = 1;
- hythread_create_with_group(&thread, args[0], 1024, 1, 0, start_proc, args);
+ hythread_create_with_group(&thread, args[0], 1024, 1, 0, start_proc, args, NULL, NULL);
hythread_join(thread);
// TODO: should check that created thread finished without errors.
return TEST_PASSED;
}
@@ -72,13 +72,13 @@
hythread_group_create(&group);
hylatch_create(&start, n);
hylatch_create(&end, 1);
for (i = 0; i < n; i++) {
thread = NULL;
- hythread_create_with_group(&thread, group, 0, 0, 0, start_proc_empty, NULL);
+ hythread_create_with_group(&thread, group, 0, 0, 0, start_proc_empty, NULL, NULL, NULL);
}
// Wait util all threads have started.
hylatch_wait(start);
iterator = hythread_iterator_create(group);
// Notify all threads
@@ -160,13 +160,13 @@
args[1] = apr_palloc(pool, sizeof(jthread_threadattr_t));
((jthread_threadattr_t *)args[1])->stacksize = 1024;
((jthread_threadattr_t *)args[1])->priority = 1;
thread = NULL;
- hythread_create_with_group(&thread, group, 1024, 1, 0, start_proc, args);
+ hythread_create_with_group(&thread, group, 1024, 1, 0, start_proc, args, NULL, NULL);
buf = (char *)apr_pcalloc(pool, sizeof(char)*12);
/*
sprintf(buf, "Thread %d\0", i);
hythread_set_name(thread, buf);
*/
--- thread\src\hythr.def 2006-12-13 12:41:19.000000000 +-0600
+++ thread\src\hythr.def 2006-12-18 19:06:43.000000000 +-0600
@@ -20,12 +20,13 @@
hythread_tls_free
hythread_yield
hythread_suspend
hythread_interrupt
hythread_tls_set
hythread_create
+hythread_create_ex
hythread_monitor_wait
hythread_monitor_wait_interruptable
hythread_monitor_exit
hythread_set_priority
hythread_unpark
hythread_sleep
@@ -47,12 +48,13 @@
hythread_join_timed
hythread_join_interruptable
hythread_get_self_id
hythread_get_id
hythread_get_thread
hythread_struct_init
+hythread_cancel_safe
hythread_cancel_all
hythread_group_create
hythread_group_release
hythread_group_get_list
hythread_get_private_data
hythread_set_private_data
@@ -118,12 +120,13 @@
hythread_init
hythread_shutdown
hythread_lib_create
hythread_lib_destroy
hythread_lib_lock
hythread_lib_unlock
+hythread_lib_set_state
release_start_lock
acquire_start_lock
inflate_lock
is_fat_lock
owns_thin_lock
--- thread\src\hythr.exp 2006-12-13 12:41:19.000000000 +-0600
+++ thread\src\hythr.exp 2006-12-18 19:06:56.000000000 +-0600
@@ -19,12 +19,13 @@
hythread_tls_free;
hythread_yield;
hythread_suspend;
hythread_interrupt;
hythread_tls_set;
hythread_create;
+hythread_create_ex;
hythread_monitor_wait;
hythread_monitor_wait_interruptable;
hythread_monitor_exit;
hythread_set_priority;
hythread_unpark;
hythread_sleep;
@@ -46,12 +47,13 @@
hythread_join_timed;
hythread_join_interruptable;
hythread_get_self_id;
hythread_get_id;
hythread_get_thread;
hythread_struct_init;
+hythread_cancel_safe;
hythread_cancel_all;
hythread_group_create;
hythread_group_release;
hythread_group_get_list;
hythread_get_private_data;
hythread_set_private_data;
@@ -129,12 +131,13 @@
hythread_shutdown;
hythread_lib_create;
hythread_lib_destroy;
hythread_lib_lock;
hythread_lib_unlock;
set_safepoint_callback;
+hythread_lib_set_state;
release_start_lock;
acquire_start_lock;
inflate_lock;
is_fat_lock;
owns_thin_lock;
--- thread\src\thread_init.c 2006-12-08 18:48:39.000000000 +-0600
+++ thread\src\thread_init.c 2006-12-08 16:26:57.000000000 +-0600
@@ -185,12 +185,14 @@
// init global monitor
status=hythread_monitor_init_with_name(&p_global_monitor, 0, "Thread Global Monitor");
assert (status == TM_ERROR_NONE);
mon = (hythread_monitor_t*)hythread_global(GLOBAL_MONITOR_NAME);
*mon = p_global_monitor;
assert(mon);
+
+ hythread_lib_set_state(lib, TM_LIBRARY_STATE_INITIALIZED);
}
/**
* Shut down the threading library associated with the current thread.
*
* @return none
@@ -239,12 +241,39 @@
/**
* Releases the lock over threading subsystem.
*
*/
IDATA VMCALL hythread_global_unlock() {
return hymutex_unlock(TM_LIBRARY->TM_LOCK);;
+}
+
+/**
+ * Sets the global library state.
+ *
+ * @param[in] lib threading library
+ * @param[in] state new state
+ *
+ * @return old state
+ */
+IDATA VMCALL hythread_lib_set_state(hythread_library_t lib, IDATA state) {
+ IDATA status;
+ IDATA old_state;
+
+ status = hythread_global_lock(NULL);
+ assert(status == TM_ERROR_NONE);
+
+ old_state = lib->state;
+
+ if (state != TM_LIBRARY_STATE_GET) {
+ lib->state = state;
+ }
+
+ status = hythread_global_unlock(NULL);
+ assert(status == TM_ERROR_NONE);
+
+ return old_state;
}
hythread_group_t get_java_thread_group(void){
return TM_DEFAULT_GROUP;
}
--- thread\src\thread_native_basic.c 2006-12-20 17:37:31.000000000 +-0600
+++ thread\src\thread_native_basic.c 2006-12-22 17:42:46.000000000 +-0600
@@ -89,15 +89,22 @@
*
* @param[out] new_thread The newly created thread.
* @param[in] group thread group, or NULL; in case of NULL this thread will go to the default group.
* @param[in] attr threadattr to use to determine how to create the thread, or NULL for default attributes
* @param[in] func function to run in the new thread
* @param[in] data argument to be passed to starting function
+ * @param[in] callback shutdown callback (@see hythread_create_ex)
+ * @param[in] callback_data data to be passed to shutdown callback
+ *
* @sa apr_thread_create()
*/
-IDATA VMCALL hythread_create_with_group(hythread_t *ret_thread, hythread_group_t group, UDATA stacksize, UDATA priority, UDATA suspend, hythread_entrypoint_t func, void *data) {
+IDATA VMCALL hythread_create_with_group(hythread_t *ret_thread, hythread_group_t group,
+ UDATA stacksize, UDATA priority, UDATA suspend,
+ hythread_entrypoint_t func, void *data,
+ hythread_shutdown_callback_t callback,
+ void * callback_data) {
apr_threadattr_t *apr_attrs;
hythread_t new_thread;
thread_start_proc_data * start_proc_data;
apr_status_t apr_status;
if (ret_thread) {
@@ -109,12 +116,14 @@
if (new_thread == NULL) {
return TM_ERROR_OUT_OF_MEMORY;
}
new_thread->library = hythread_self()->library;
+ new_thread->shutdown_callback = callback;
+ new_thread->shutdown_data = callback_data;
if (stacksize) {
apr_threadattr_create(&apr_attrs, new_thread->pool);
apr_threadattr_stacksize_set(apr_attrs, stacksize);
new_thread->apr_attrs = apr_attrs;
} else {
new_thread->apr_attrs = NULL;
@@ -162,24 +171,66 @@
* @param[in] data a value to pass to the entrypoint function
*
* @return 0 on success or negative value on failure
*
* @see hythread_exit, hythread_resume
*/
-IDATA VMCALL hythread_create(hythread_t *ret_thread, UDATA stacksize, UDATA priority, UDATA suspend, hythread_entrypoint_t func, void *data) {
- return hythread_create_with_group(ret_thread, NULL, stacksize, priority, suspend, func, data);
+IDATA VMCALL hythread_create(hythread_t *ret_thread, UDATA stacksize, UDATA priority,
+ UDATA suspend, hythread_entrypoint_t func, void *data) {
+ return hythread_create_with_group(ret_thread, NULL, stacksize, priority, suspend, func, data, NULL, NULL);
}
+
/**
+ * Create a new OS thread.
+ *
+ * The created thread is attached to the threading library.
+ *
+ * Unlike POSIX, this doesn't require an attributes structure.
+ * Instead, any interesting attributes (e.g. stacksize) are
+ * passed in with the arguments.
+ *
+ * @param[out] ret_thread a pointer to a hythread_t which will point to the thread (if successfully created)
+ * @param[in] stacksize the size of the new thread's stack (bytes)
+ * 0 indicates use default size
+ * @param[in] priority priorities range from HYTHREAD_PRIORITY_MIN to HYTHREAD_PRIORITY_MAX (inclusive)
+ * @param[in] suspend set to non-zero to create the thread in a suspended state.
+ * @param[in] func pointer to the function which the thread will run
+ * @param[in] data a value to pass to the entrypoint function
+ * @param[in] callback when non null callback function is specified it will be
+ * executed by hythread_cancel(hythread_t thread) to initiate thread shutdown
+ * sequence. If no callback is given then this thread doesn't have a chance to
+ * cleanup its internals and will be forcibly terminated.
+ * Note that by the time of callback execution the VM is already in shutdown
+ * stage thus not all services provided by VM are available. For example,
+ * any attempt to create a new java thread or attach the current one will fail.
+ * @param[in] callback_data data to be passed to shutdown callback
+ *
+ * @return 0 on success or negative value on failure
+ *
+ * @see hythread_exit, hythread_resume
+ */
+IDATA VMCALL hythread_create_ex(hythread_t *ret_thread, UDATA stacksize, UDATA priority,
+ UDATA suspend, hythread_entrypoint_t func, void *data,
+ hythread_shutdown_callback_t callback, void * callback_data) {
+ return hythread_create_with_group(ret_thread, NULL, stacksize, priority,
+ suspend, func, data, callback, callback_data);
+}
+
+
+/**
* Registers the current OS thread with the threading subsystem.
*
* @param[in] handle thread to register
* @param[in] lib thread library to attach to
* @param[in] group thread group, or NULL; in case of NULL this thread will go to the default group
+ * @param[in] callback shutdown callback (@see hythread_create_ex)
+ * @param[in] callback_data data to be passed to shutdown callback
*/
-IDATA hythread_attach_to_group(hythread_t * handle, hythread_library_t lib, hythread_group_t group) {
+IDATA hythread_attach_to_group(hythread_t * handle, hythread_library_t lib, hythread_group_t group,
+ hythread_shutdown_callback_t callback, void * callback_data) {
hythread_t thread;
apr_thread_t *os_handle = NULL;
apr_os_thread_t *os_thread;
apr_status_t apr_status;
if (lib == NULL) {
@@ -201,12 +252,14 @@
thread = allocate_thread();
}
if (thread == NULL) {
return TM_ERROR_OUT_OF_MEMORY;
}
thread->library = lib;
+ thread->shutdown_callback = callback;
+ thread->shutdown_data = callback_data;
os_thread = apr_palloc(thread->pool, sizeof(apr_os_thread_t));
if (os_thread == NULL) {
return TM_ERROR_OUT_OF_MEMORY;
}
*os_thread = apr_os_thread_current();
apr_status = apr_os_thread_put(&os_handle, os_thread, thread->pool);
@@ -234,27 +287,31 @@
* @return 0 on success or negative value on failure
*
* @note (*handle) should be NULL or point to hythread_t structure
* @see hythread_detach
*/
IDATA VMCALL hythread_attach(hythread_t *handle) {
- return hythread_attach_to_group(handle, TM_LIBRARY, NULL);
+ return hythread_attach_to_group(handle, TM_LIBRARY, NULL, NULL, NULL);
}
/**
* Attach an OS thread to the threading library.
*
* @param[out] handle pointer to a hythread_t to be set (will be ignored if null)
- * @param[in] lib thread library to attach thread to
+ * @param[in] lib thread library to attach the thread to
+ * @param[in] callback shutdown callback (@see hythread_create_ex)
+ * @param[in] callback_data data to be passed to shutdown callback
+ *
* @return 0 on success or negative value on failure
*
* @note (*handle) should be NULL or point to hythread_t structure
* @see hythread_detach
*/
-IDATA VMCALL hythread_attach_ex(hythread_t *handle, hythread_library_t lib) {
- return hythread_attach_to_group(handle, lib, NULL);
+IDATA VMCALL hythread_attach_ex(hythread_t *handle, hythread_library_t lib,
+ hythread_shutdown_callback_t callback, void * callback_data) {
+ return hythread_attach_to_group(handle, lib, NULL, callback, callback_data);
}
/**
* Detaches a thread from the threading library.
*
* @note Assumes that the thread being detached is already attached.
@@ -269,36 +326,45 @@
* @return none
*
* @see hythread_attach
*/
void VMCALL hythread_detach(hythread_t thread) {
IDATA status;
-
- if (thread == NULL) {
- thread = hythread_self();
- }
-
+ hythread_t self;
+
// Acquire global TM lock to prevent concurrent acccess to thread list
status = hythread_global_lock(NULL);
assert (status == TM_ERROR_NONE);
+ self = hythread_self();
+ if (thread == NULL) {
+ thread = self;
+ }
+
// No actions required in case the specified thread is detached already.
if (thread->group != NULL) {
- assert(thread == tm_self_tls);
-
- thread_set_self(NULL);
+ if (thread == self) {
+ thread_set_self(NULL);
+ }
+
+ thread->state = TM_THREAD_STATE_TERMINATED | (TM_THREAD_STATE_INTERRUPTED & thread->state);
+ thread->exit_value = 0;
+
fast_thread_array[thread->thread_id] = NULL;
thread->prev->next = thread->next;
thread->next->prev = thread->prev;
thread->group->threads_count--;
thread->group = NULL;
}
- hythread_global_unlock(NULL);
+ status = hythread_global_unlock(NULL);
assert(status == TM_ERROR_NONE);
+
+ // Send join event to those threads who called join on this thread.
+ hylatch_count_down(thread->join_event);
}
/**
* Waits until the selected thread finishes execution.
*
* @param[in] t thread to join
@@ -528,24 +594,57 @@
*/
IDATA VMCALL hythread_get_group(hythread_group_t *group, hythread_t thread) {
(*group) = thread->group;
return TM_ERROR_NONE;
}
+/**
+ * Executes thread's shutdown callback in case it was registered with
+ * thread creation/attaching procedures. There is a gurantee to execute
+ * a shutdown callback on a live thread only in a thread-safe manner.
+ * Though it is possible that the callback is executed several times
+ * before the target thread notices shutdown request.
+ *
+ * @param[in] thread a thread to be terminated by executing its shutdown callback
+ * @return 0 if shutdown callback was successfully excuted
+ */
+IDATA VMCALL hythread_cancel_safe(hythread_t thread) {
+ IDATA status;
+ IDATA res;
+
+ res = -1;
+ if (thread->shutdown_callback) {
+ status = hythread_global_lock();
+ assert(status == TM_ERROR_NONE);
+
+ if (!hythread_is_terminated(thread)) {
+ thread->shutdown_callback(thread->shutdown_data);
+ res = 0;
+ }
+
+ status = hythread_global_unlock();
+ assert(status == TM_ERROR_NONE);
+ }
+
+ return res;
+}
+
/**
* Terminates a running thread.
*
* @note This should only be used as a last resort. The system may be in
* an unpredictable state once a thread is cancelled. In addition, the thread
* may not even stop running if it refuses to cancel.
*
* @param[in] thread a thread to be terminated
* @return none
*/
void VMCALL hythread_cancel(hythread_t thread) {
- apr_thread_cancel(thread->os_handle);
+ if (apr_thread_cancel(thread->os_handle) == APR_SUCCESS) {
+ hythread_detach(thread);
+ }
}
/**
* Terminates all running threads in the given group.
*
* @param[in] group thread group
@@ -595,13 +694,19 @@
assert(thread);
assert(group);
// Acquire global TM lock to prevent concurrent acccess to thread list
status = hythread_global_lock(NULL);
- if (status != TM_ERROR_NONE) return status;
+ assert(status == TM_ERROR_NONE);
+
+ if (hythread_lib_set_state(thread->library, TM_LIBRARY_STATE_GET) == TM_LIBRARY_STATE_BLOCKED) {
+ status = hythread_global_unlock(NULL);
+ assert(status == TM_ERROR_NONE);
+ return TM_ERROR_START;
+ }
thread_set_self(thread);
assert(thread == tm_self_tls);
thread->state |= TM_THREAD_STATE_ALIVE | TM_THREAD_STATE_RUNNABLE;
@@ -620,13 +725,17 @@
group->threads_count++;
cur = group->thread_list->next;
prev = cur->prev;
thread->next = cur;
thread->prev = prev;
prev->next = cur->prev = thread;
- return hythread_global_unlock(NULL);
+
+ status = hythread_global_unlock(NULL);
+ assert(status == TM_ERROR_NONE);
+
+ return TM_ERROR_NONE;
}
/*
* Allocates and initializes a new thread_t structure
*
* @return created and initialized thread_t structure
@@ -660,12 +769,15 @@
assert (status == TM_ERROR_NONE);
status = hymutex_create(&ptr->mutex, TM_MUTEX_NESTED);
assert (status == TM_ERROR_NONE);
status = hycond_create(&ptr->condition);
assert (status == TM_ERROR_NONE);
+ ptr->shutdown_callback = NULL;
+ ptr->shutdown_data = NULL;
+
ptr->state = TM_THREAD_STATE_ALLOCATED;
return ptr;
}
static void reset_thread(hythread_t thread) {
apr_status_t apr_status;
@@ -687,13 +799,16 @@
status = hylatch_set(thread->join_event, 1);
assert (status == TM_ERROR_NONE);
status = hylatch_set(thread->safe_region_event, 1);
assert (status == TM_ERROR_NONE);
status = hysem_set(thread->resume_event, 0);
assert (status == TM_ERROR_NONE);
-
+
+ thread->shutdown_callback = NULL;
+ thread->shutdown_data = NULL;
+
thread->state = TM_THREAD_STATE_ALLOCATED;
}
// Wrapper around user thread start proc. Used to perform some duty jobs
// right after thread is started.
//////
@@ -718,26 +833,16 @@
status = hythread_set_priority(thread, thread->priority);
//assert (status == TM_ERROR_NONE);//now we down - fixme
thread->state |= TM_THREAD_STATE_RUNNABLE;
// Do actual call of the thread body supplied by the user.
start_proc_data->start_proc(start_proc_data->start_proc_args);
-
- // Shutdown sequence.
- status = hythread_global_lock(NULL);
- assert (status == TM_ERROR_NONE);
- assert(hythread_is_suspend_enabled());
- thread->state = TM_THREAD_STATE_TERMINATED | (TM_THREAD_STATE_INTERRUPTED & thread->state);
- thread->exit_value = 0;
+
+ assert(hythread_is_suspend_enabled());
hythread_detach(thread);
- // Send join event to those threads who called join on this thread.
- hylatch_count_down(thread->join_event);
-
- status = hythread_global_unlock(NULL);
- assert (status == TM_ERROR_NONE);
// TODO: It seems it is there is no need to call apr_thread_exit.
// Current thread should automatically exit upon returning from this function.
return (void *)(IDATA)apr_thread_exit(thd, APR_SUCCESS);
}
--- thread\src\thread_private.h 2006-12-13 12:40:47.000000000 +-0600
+++ thread\src\thread_private.h 2006-12-15 18:20:02.000000000 +-0600
@@ -147,18 +147,18 @@
/**
* current capacity of the thread local storage
*/
extern int16 tm_tls_size;
-
typedef struct HyThreadLibrary {
IDATA a;
hymutex_t TM_LOCK;
IDATA nondaemon_thread_count;
hycond_t nondaemon_thread_cond;
+ IDATA state;
} HyThreadLibrary;
/**
* Native thread control structure.
@@ -235,15 +235,20 @@
* Placeholder for any data to be associated with this thread.
* Java layer is using it to keep java-specific context.
*/
void *private_data;
/**
- * Flag indicating there was request to exit
+ * Callback to be executed upon thread cancelation.
+ */
+ hythread_shutdown_callback_t shutdown_callback;
+
+ /**
+ * Pointer to the data for shutdown callback.
*/
- Boolean exit_request;
+ void * shutdown_data;
/**
* Exit value of this thread
*/
IDATA exit_value;
--- vmcore\src\init\vm_init.cpp 2006-12-20 16:20:31.000000000 +-0600
+++ vmcore\src\init\vm_init.cpp 2006-12-19 17:35:04.000000000 +-0600
@@ -570,13 +570,13 @@
hythread_t native_thread;
jint status;
native_thread = hythread_self();
if (!native_thread) {
status = hythread_attach_to_group(&native_thread,
- ((JavaVM_Internal *)java_vm)->vm_env->hythread_lib, NULL);
+ ((JavaVM_Internal *)java_vm)->vm_env->hythread_lib, NULL, NULL, NULL);
if (status != TM_ERROR_NONE) return JNI_ERR;
}
assert(native_thread);
status = vm_attach(java_vm, &jni_env);
if (status != JNI_OK) return status;
@@ -601,13 +601,13 @@
JNIEnv * jni_env;
TRACE("Initializing VM");
vm_env = java_vm->vm_env;
- if (hythread_attach_ex(NULL, vm_env->hythread_lib) != TM_ERROR_NONE) {
+ if (hythread_attach_ex(NULL, vm_env->hythread_lib, NULL, NULL) != TM_ERROR_NONE) {
return JNI_ERR;
}
assert(hythread_is_suspend_enabled());
status = check_platform();
--- vmcore\src\init\vm_shutdown.cpp 2006-12-22 17:06:24.000000000 +-0600
+++ vmcore\src\init\vm_shutdown.cpp 2006-12-22 17:51:06.000000000 +-0600
@@ -184,12 +184,71 @@
}
}
}
}
/**
+ * Stops running native threads by executing shutdown callback.
+ *
+ * @param[in] vm_env a global VM environment
+ */
+static void vm_shutdown_stop_native_threads(Global_Env * vm_env) {
+ hythread_t self;
+ hythread_t * running_threads;
+ hythread_t native_thread;
+ hythread_iterator_t it;
+ hythread_group_t * group_list;
+ int group_count;
+ int size;
+ jint status;
+
+ self = hythread_self();
+
+ status = hythread_global_lock();
+ assert(status == TM_ERROR_NONE);
+
+ status = hythread_group_get_list(&group_list, &group_count);
+
+ size = 0;
+ for (int i = 0; i < group_count; i++) {
+ it = hythread_iterator_create(group_list[i]);
+ size += hythread_iterator_size(it);
+ hythread_iterator_release(&it);
+ }
+
+ running_threads = (hythread_t *)apr_palloc(vm_env->mem_pool, size * sizeof(hythread_t));
+
+ size = 0;
+ for (int i = 0; i < group_count; i++) {
+ it = hythread_iterator_create(group_list[i]);
+ native_thread = hythread_iterator_next(&it);
+ while(native_thread != NULL && native_thread != self) {
+ running_threads[size] = native_thread;
+ ++size;
+ native_thread = hythread_iterator_next(&it);
+ }
+ hythread_iterator_release(&it);
+ }
+
+ status = hythread_global_unlock();
+ assert(status == TM_ERROR_NONE);
+
+ for (int i = 0; i < size; i++) {
+ if (hythread_cancel_safe(running_threads[i]) != TM_ERROR_NONE) {
+ running_threads[i] = NULL;
+ }
+ }
+
+ for (int i = 0; i < size; i++) {
+ if (running_threads[i]) {
+ hythread_join(running_threads[i]);
+ }
+ }
+}
+
+/**
* Waits until all non-daemon threads finish their execution,
* initiates VM shutdown sequence and stops running threads if any.
*
* @param[in] java_vm JVM that should be destroyed
* @param[in] java_thread current java thread
*/
@@ -239,29 +298,29 @@
status = jthread_detach(java_thread);
if (status != TM_ERROR_NONE) return JNI_ERR;
// Call Agent_OnUnload() for agents and unload agents.
java_vm->vm_env->TI->Shutdown(java_vm);
- // Block thread creation.
- // TODO: investigate how to achive that with ThreadManager
-
// Starting this moment any exception occured in java thread will cause
// entire java stack unwinding to the most recent native frame.
// JNI is not available as well.
assert(java_vm->vm_env->vm_state == Global_Env::VM_RUNNING);
java_vm->vm_env->vm_state = Global_Env::VM_SHUTDOWNING;
+ // Block thread creation.
+ hythread_lib_set_state(java_vm->vm_env->hythread_lib, TM_LIBRARY_STATE_BLOCKED);
+
// Stop all (except current) java and native threads
// before destroying VM-wide data.
// Stop java threads
vm_shutdown_stop_java_threads(java_vm->vm_env);
- // TODO: ups we don't stop native threads as well :-((
- // We are lucky! Currently, there are no such threads.
+ // Stop native threads.
+ vm_shutdown_stop_native_threads(java_vm->vm_env);
return JNI_OK;
}
static int vm_interrupt_process(void * data) {
hythread_t * threadBuf;