From 97727c3f2f5f176c7d135130cc0bd51a3d8daf7e Mon Sep 17 00:00:00 2001 From: Ilya Berezhniuk Date: Mon, 21 Apr 2008 17:35:37 +0400 Subject: [PATCH] HARMONY-5617 --- make/vm/port.xml | 3 + make/vm/port_ch.xml | 5 + vm/include/open/hythread_ext.h | 6 - vm/port/include/port_general.h | 10 + vm/port/include/port_thread.h | 236 +++++++- vm/port/src/crash_handler/port_crash_handler.cpp | 6 - vm/port/src/crash_handler/stack_dump.cpp | 26 +- vm/port/src/memaccess/linux/memaccess.cpp | 38 +- vm/port/src/signals/include/signals_internal.h | 55 +-- vm/port/src/signals/linux/signals_common.cpp | 167 +++-- vm/port/src/signals/linux/signals_ipf.cpp | 111 +++- vm/port/src/signals/port_signals.cpp | 21 +- vm/port/src/signals/win/signals_common.cpp | 171 +++-- vm/port/src/signals/win/signals_ia32.cpp | 2 +- vm/port/src/thread/include/port_thread_internal.h | 196 ++++++ vm/port/src/thread/linux/port_thread_tls_os.c | 158 +++++ vm/port/src/thread/linux/thread_os.c | 719 +++++++++++++++----- vm/port/src/thread/win/port_thread_tls_os.c | 127 ++++ vm/port/src/thread/win/thread_os.c | 505 ++++++++++++--- vm/thread/src/hythr.def | 1 - vm/thread/src/hythr.exp | 1 - vm/thread/src/linux/os_thread.c | 212 ------ vm/thread/src/thread_native_attrs.c | 2 +- vm/thread/src/thread_native_basic.c | 34 +- vm/thread/src/thread_private.h | 10 - vm/thread/src/win/os_thread.c | 176 ----- vm/vmcore/include/exceptions.h | 3 - vm/vmcore/src/exception/exceptions.cpp | 9 +- vm/vmcore/src/exception/exceptions_jit.cpp | 21 +- vm/vmcore/src/thread/thread_generic.cpp | 7 - vm/vmcore/src/thread/thread_java_basic.cpp | 7 +- .../src/util/linux/ia32_em64t/signals_common.cpp | 390 ----------- vm/vmcore/src/util/linux/include/signals_common.h | 63 -- vm/vmcore/src/util/linux/signals_ipf.cpp | 347 ---------- vm/vmcore/src/util/signals.cpp | 155 +++++ .../win/ia32_em64t/nt_exception_filter_common.cpp | 292 -------- vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp | 208 ------ 37 files changed, 2288 insertions(+), 2212 deletions(-) create mode 100644 vm/port/src/thread/include/port_thread_internal.h create mode 100644 vm/port/src/thread/linux/port_thread_tls_os.c create mode 100644 vm/port/src/thread/win/port_thread_tls_os.c delete mode 100644 vm/thread/src/linux/os_thread.c delete mode 100644 vm/thread/src/win/os_thread.c delete mode 100644 vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp delete mode 100644 vm/vmcore/src/util/linux/include/signals_common.h delete mode 100644 vm/vmcore/src/util/linux/signals_ipf.cpp delete mode 100644 vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp delete mode 100644 vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp diff --git a/make/vm/port.xml b/make/vm/port.xml index d00bb49..3c1dbdf 100644 --- a/make/vm/port.xml +++ b/make/vm/port.xml @@ -29,6 +29,7 @@ + @@ -50,10 +51,12 @@ + + diff --git a/make/vm/port_ch.xml b/make/vm/port_ch.xml index 41317c6..54b0c93 100644 --- a/make/vm/port_ch.xml +++ b/make/vm/port_ch.xml @@ -30,6 +30,7 @@ + @@ -42,9 +43,13 @@ + + + + diff --git a/vm/include/open/hythread_ext.h b/vm/include/open/hythread_ext.h index a6af327..f0070e4 100644 --- a/vm/include/open/hythread_ext.h +++ b/vm/include/open/hythread_ext.h @@ -346,11 +346,6 @@ typedef struct HyThread { char need_to_free; /** - * Size of thread's stack, set on creation - */ - UDATA stacksize; - - /** * Flag of interruption */ uint32 interrupted; @@ -445,7 +440,6 @@ IDATA VMCALL hythread_group_get_list(hythread_group_t **list, int* size); UDATA VMCALL hythread_tls_get_offset(hythread_tls_key_t key); UDATA VMCALL hythread_tls_get_request_offset(); UDATA VMCALL hythread_get_thread_times(hythread_t thread, int64* pkernel, int64* puser); -UDATA hythread_get_thread_stacksize(hythread_t thread); UDATA VMCALL hythread_uses_fast_tls(void); IDATA VMCALL hythread_get_hythread_offset_in_tls(void); IDATA VMCALL hythread_get_struct_size(); diff --git a/vm/port/include/port_general.h b/vm/port/include/port_general.h index 754dd4c..4a18e35 100644 --- a/vm/port/include/port_general.h +++ b/vm/port/include/port_general.h @@ -58,5 +58,15 @@ #endif /* __cplusplus */ +#ifdef _IA32_ +#ifdef WIN32 +#define PORT_CDECL __cdecl +#else /* !WIN32 */ +#define PORT_CDECL __attribute__ ((cdecl)) +#endif /* WIN32 */ +#else /* _IA32_ */ +#define PORT_CDECL +#endif /* _IA32_ */ + #endif /* _PORT_GENERAL_H_ */ diff --git a/vm/port/include/port_thread.h b/vm/port/include/port_thread.h index 83f68c3..82ee98c 100644 --- a/vm/port/include/port_thread.h +++ b/vm/port/include/port_thread.h @@ -50,6 +50,7 @@ static _syscall0(pid_t, gettid)/* static definition */ #endif /* LINUX || FREEBSD */ + /* To skip platform_types.h inclusion */ typedef struct Registers Registers; @@ -71,18 +72,251 @@ PORT_INLINE int port_gettid() #endif } -void port_thread_yield_other(osthread_t thread); +/** + * The type of pointer to thread start function + * Function receives single argument - user-defined pointer + */ +typedef int (PORT_CDECL *port_threadfunc_t)(void*); + +/** + * Creates new thread. + * + * @param[out] handle on success, thread handle is stored in memory pointed by handle + * @param stacksize size of stack to be allocated for a new thread + * @param priority priority of a new thread + * @param func function to be started on a new thread + * @param data value to be passed to a function started on a new thread + * + * @return 0 on success, system error otherwise. + */ +int port_thread_create(osthread_t* phandle, size_t stacksize, int priority, + port_threadfunc_t func, void *data); + +/** + * Attaches current thread to the porting library. + * + * This includes setting guard page in thread's stack memory and setting + * alternative stack for stack overflow processing. + * This function should be called for any thread which can produce expected + * hardware signals/exceptions, to guarantee proper signals processing. + * + * @return 0 on success, system error otherwise. + * + * @sa port_thread_detach() + */ +int port_thread_attach(); + +/** + * Detaches current thread from the porting library. + * This includes restoring thread's stack settings. + * + * @return 0 on success, system error otherwise. + * + * @sa port_thread_attach() + */ +int port_thread_detach(); + +/** + * Restores guard page after stack overflow processing, when + * port_thread_postpone_guard_page() function was used + * to postpone authomatic gurd page restoring. + * + * @return 0 on success, system error otherwise. + * + * @sa port_thread_postpone_guard_page() + * @sa port_thread_clear_guard_page() + */ +int port_thread_restore_guard_page(); + +/** + * Clears guard page in thread's stack on demand. + * Guard page is cleared automatically for stack overflow processing; this + * function allows clearing it when needed for other purposes. + * Guard page can be restored with + * port_thread_postpone_guard_page() function. + * + * @return 0 on success, system error otherwise. + * + * @sa port_thread_restore_guard_page() + */ +int port_thread_clear_guard_page(); + +/** + * Postpones automatic guard page restoring after stack overflow processing. + * + * This function can be used inside of STACK_OVERFLOW signal callback to + * disable automatic guard poge restoring. This is useful when the program + * expects to consume some more stack before unwinding to SO handler. + * + * @sa port_thread_restore_guard_page() + */ +void port_thread_postpone_guard_page(); + + +/** + * Returns stack bottom address for the current thread. + * + * @return NULL on error + */ +void* port_thread_get_stack_address(); + + +/** + * Returns total thread's stack size for the current thread. + * + * @return 0 on error + */ +size_t port_thread_get_stack_size(); + + +/** + * Returns effective stack size for the current thread. + * Effective stack size is an area from stack bottom to guard page. + * + * Return value depends thread's state. When the thread is not in signal, + * return value is a total stack size excluding system page, i.e. + * (port_thread_get_stack_size() - ). When processing a signal, + * return value is the same when guard page is cleared, and is a size of area + * from stack bottom to Port's guard page otherwise. + * + * @return 0 on error + */ +size_t port_thread_get_effective_stack_size(); + + +/** + * Adjusts priority of the running thread. + * + * @param thread handle of thread + * @param priority new priority value + * + * @return 0 on success, system error otherwise + */ +int port_thread_set_priority(osthread_t thread, int priority); + +/** + * Returns os handle of the current thread. + * + * @return current thread handle on success, NULL on error + * + * @note The handle returned need to be freed by port_thread_free_handle() + * @sa port_thread_free_handle() + */ +osthread_t port_thread_current(); + +/** + * Frees thread handle returned by port_thread_current() + * + * @param os_thread thread handle + * + * @sa port_thread_current() + */ +int port_thread_free_handle(osthread_t os_thread); + +/** + * Joins the os thread. + * + * @param os_thread thread handle + * + * @return 0 on success, systerm error otherwise + */ +int port_thread_join(osthread_t os_thread); + +/** + * Terminates the os thread. + * + * @param os_thread thread to terminate + */ int port_thread_cancel(osthread_t os_thread); +/** + * Causes the current thread to stop execution. + * + * @param status return status of a thread + */ +void port_thread_exit(int status); +/** + * Queries amount of user and kernel times consumed by the thread, + * in nanoseconds. + * + * @param os_thread thread handle + * @param[out] pkernel a pointer to a variable to store kernel time to + * @param[out] puser a pointer to a variable to store user time to + * + * @return 0 on success, system error otherwise + */ +int port_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser); + +/** + * Causes the other thread to have a memory barrier by suspending + * and resuming it. + * + * @param thread thread handle + */ +void port_thread_yield_other(osthread_t thread); + +/** + * Suspend given thread + * + * @param thread The thread to suspend + */ int port_thread_suspend(osthread_t thread); + +/** + * Resume given thread + * + * @param thread The thread to resume + */ int port_thread_resume(osthread_t thread); + +/** + * Returnd suspend count for the given thread + * + * @param thread The thread to check + * + * @return suspend count of the thread, -1 if error + */ int port_thread_get_suspend_count(osthread_t thread); +/** + * Get context for given thread + * + * @param thread The thread to process + * @param context Pointer to platform-dependent context structure + * + * @return 0 if successful, -1 otherwise + * + * @note The thread must be suspended + */ int port_thread_get_context(osthread_t thread, thread_context_t* pcontext); + +/** + * Set context for given thread + * + * @param thread The thread to process + * @param context Pointer to platform-dependent context structure + * + * @return 0 if successful, -1 otherwise + * + * @note The thread must be suspended + */ int port_thread_set_context(osthread_t thread, thread_context_t* pcontext); +/** + * Translates platform-dependent thread context to Registers structure + * + * @param regs Pointer to Registers structure + * @param context Pointer to platform-dependent context structure + */ void port_thread_context_to_regs(Registers* regs, thread_context_t* context); + +/** + * Translates Registers structure to platform-dependent thread context + * + * @param context Pointer to platform-dependent context structure + * @param regs Pointer to Registers structure + */ void port_thread_regs_to_context(thread_context_t* context, Registers* regs); diff --git a/vm/port/src/crash_handler/port_crash_handler.cpp b/vm/port/src/crash_handler/port_crash_handler.cpp index 5bbc0ff..db8c674 100644 --- a/vm/port/src/crash_handler/port_crash_handler.cpp +++ b/vm/port/src/crash_handler/port_crash_handler.cpp @@ -58,9 +58,6 @@ Boolean port_init_crash_handler( if (port_mutex_create(&g_mutex, APR_THREAD_MUTEX_NESTED) != APR_SUCCESS) return FALSE; - if (init_private_tls_data() != 0) - return FALSE; - for (unsigned iii = 0; iii < count; iii++) { assert(registrations[iii].signum >= PORT_SIGNAL_MIN); @@ -136,9 +133,6 @@ Boolean port_shutdown_crash_handler() if (shutdown_signals() != 0) return FALSE; - if (free_private_tls_data() != 0) - return FALSE; - for (crash_additional_actions *a = crash_actions; NULL != a;) { crash_additional_actions *next = a->next; diff --git a/vm/port/src/crash_handler/stack_dump.cpp b/vm/port/src/crash_handler/stack_dump.cpp index 02ad796..96046fb 100644 --- a/vm/port/src/crash_handler/stack_dump.cpp +++ b/vm/port/src/crash_handler/stack_dump.cpp @@ -58,8 +58,12 @@ static const char* vm_fmt_tbl[] = { "%s\n", // No signature no sourcefile }; -static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi) +static void sd_print_vm_line(FILE* file, int count, Registers* regs, port_stack_frame_info* fi) { + static char pi_blanks[2*sizeof(void*) + 3]; + static void* pi_blanks_set_res = memset(pi_blanks, ' ', sizeof(pi_blanks)); + static char pi_blanks_zero_res = (pi_blanks[sizeof(pi_blanks) - 1] = 0); + if (!fi->method_name) return; @@ -68,6 +72,11 @@ static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi) else fprintf(file, " "); // additional VM info - indent + if (regs) + fprintf(file, "0x%"W_PI_FMT" ", regs->get_ip()); + else + fprintf(file, "%s ", pi_blanks); // additional VM info - indent + const void* args[5] = {fi->method_class_name, fi->method_name, fi->method_signature, fi->source_file_name, (const void*)(size_t)fi->source_line_number}; @@ -93,13 +102,13 @@ static void sd_print_vm_line(FILE* file, int count, port_stack_frame_info* fi) } -static void sd_print_c_line(FILE* file, int count, CFunInfo* cfi) +static void sd_print_c_line(FILE* file, int count, Registers* regs, CFunInfo* cfi) { if (!cfi->name) return; - fprintf(file, "%3d: %s (%s:%d)\n", - count, cfi->name, + fprintf(file, "%3d: 0x%"W_PI_FMT" %s (%s:%d)\n", + count, regs->get_ip(), cfi->name, cfi->filename ? cfi->filename : "??", cfi->line); } @@ -124,6 +133,7 @@ static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind) fprintf(stderr, "\nStack trace:\n"); Registers locregs = *regs; + Registers tmpregs = locregs; UnwindContext uwcontext; bool hasnative = false; @@ -155,10 +165,11 @@ static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind) // Unwinding with VM callback if (unwind && uwresult == 0) { - sd_print_vm_line(stderr, framenum++, &uwinfo); + sd_print_vm_line(stderr, framenum++, &tmpregs, &uwinfo); // Cleanup frame info except 'iteration_state' memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state)); // Try unwinding by the callback for next iteration + tmpregs = locregs; uwresult = unwind(&locregs, &uwinfo); continue; } @@ -167,11 +178,11 @@ static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind) CFunInfo cfi = {0}; native_module_t* module = port_find_module(uwcontext.modules, locregs.get_ip()); sd_get_c_method_info(&cfi, module, locregs.get_ip()); - sd_print_c_line(stderr, framenum++, &cfi); + sd_print_c_line(stderr, framenum++, &locregs, &cfi); if (unwind && uwresult < 0 && uwinfo.method_name) { // VM has not unwound but has provided additional frame info - sd_print_vm_line(stderr, -1, &uwinfo); // Print as additional info + sd_print_vm_line(stderr, -1, NULL, &uwinfo); // Print as additional info } if (!hasnative) // Native unwinding is not initialized @@ -186,6 +197,7 @@ static void sd_print_stack(Registers* regs, port_unwind_compiled_frame unwind) // Cleanup frame info except 'iteration_state' memset(&uwinfo, 0, offsetof(port_stack_frame_info, iteration_state)); // Try unwinding by the callback for next iteration + tmpregs = locregs; uwresult = unwind(&locregs, &uwinfo); } diff --git a/vm/port/src/memaccess/linux/memaccess.cpp b/vm/port/src/memaccess/linux/memaccess.cpp index acb8c55..e6bb9c8 100644 --- a/vm/port/src/memaccess/linux/memaccess.cpp +++ b/vm/port/src/memaccess/linux/memaccess.cpp @@ -24,9 +24,11 @@ #include "port_general.h" #include "port_barriers.h" +#include "port_malloc.h" #include "signals_internal.h" #include "port_memaccess.h" +#include "port_thread_internal.h" extern "C" void port_memcpy_asm(void* dst, const void* src, size_t size, @@ -35,22 +37,28 @@ extern "C" void port_memcpy_asm(void* dst, const void* src, size_t size, static int memcpy_internal(void* dst, const void* src, size_t size, int from) { - port_tls_data tlsdata; + int res; + port_tls_data_t* tlsdata = get_private_tls_data(); - if (!get_private_tls_data()) + if (!tlsdata) { - if (set_private_tls_data(&tlsdata) != 0) - return -1; + tlsdata = (port_tls_data_t*)STD_ALLOCA(sizeof(port_tls_data_t)); + + res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); + + if (res != 0) + return res; } - tlsdata.violation_flag = 1; + tlsdata->violation_flag = 1; void* memcpyaddr = (void*)&memcpy; - port_memcpy_asm(dst, src, size, &tlsdata.restart_address, memcpyaddr); + port_memcpy_asm(dst, src, size, &tlsdata->restart_address, memcpyaddr); - if (tlsdata.violation_flag == 1) + if (tlsdata->violation_flag == 1) { - pthread_setspecific(port_tls_key, NULL); + tlsdata->violation_flag = 0; + port_thread_detach_temporary(); return 0; } @@ -76,14 +84,20 @@ static int memcpy_internal(void* dst, const void* src, size_t size, int from) } if (result != 0) + { + tlsdata->violation_flag = 0; + port_thread_detach_temporary(); return -1; + } - tlsdata.violation_flag = 1; + tlsdata->violation_flag = 1; - port_memcpy_asm(dst, src, size, &tlsdata.restart_address, memcpyaddr); + port_memcpy_asm(dst, src, size, &tlsdata->restart_address, memcpyaddr); - pthread_setspecific(port_tls_key, NULL); - return (tlsdata.violation_flag == 1) ? 0 : -1; + res = (tlsdata->violation_flag == 1) ? 0 : -1; + tlsdata->violation_flag = 0; + port_thread_detach_temporary(); + return res; } diff --git a/vm/port/src/signals/include/signals_internal.h b/vm/port/src/signals/include/signals_internal.h index f37601b..8496f8d 100644 --- a/vm/port/src/signals/include/signals_internal.h +++ b/vm/port/src/signals/include/signals_internal.h @@ -19,67 +19,14 @@ #define _SIGNALS_INTERNAL_H_ #include "port_general.h" -#include "port_thread.h" #include "open/platform_types.h" #include "open/hythread_ext.h" /* For windows.h */ - -/* Thread-specific structure */ -typedef struct -{ - /* Previous crash handling stage to restart crash processing */ - int crash_stage; - -#ifndef WIN32 /* UNIX */ - /* Flag and restart address for memory access violation detection */ - int violation_flag; - void* restart_address; -#endif /* UNIX */ - - /* Flag to indicate that debugger should be attached right in OS handler */ - Boolean debugger; - /* Flag to produce minidump/core on the second exception catch */ - Boolean produce_core; - -} port_tls_data; - - -#ifdef WIN32 -typedef DWORD port_tls_key_t; -#else -typedef pthread_key_t port_tls_key_t; -#endif - - #ifdef __cplusplus extern "C" { #endif -extern port_tls_key_t port_tls_key; - -int init_private_tls_data(); -int free_private_tls_data(); - -PORT_INLINE port_tls_data* get_private_tls_data() -{ -#ifdef WIN32 - return (port_tls_data*)TlsGetValue(port_tls_key); -#else - return (port_tls_data*)pthread_getspecific(port_tls_key); -#endif -} - -PORT_INLINE int set_private_tls_data(port_tls_data* data) -{ -#ifdef WIN32 - return TlsSetValue(port_tls_key, data) ? 0 : -1; -#else - return pthread_setspecific(port_tls_key, data); -#endif -} - - /* Transfer control to specified register context */ void port_transfer_to_regs(Registers* regs); @@ -153,7 +100,7 @@ LONG NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_exception); /* Internal exception handler */ LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception); -void __cdecl port_win_dbg_break(void); +void PORT_CDECL port_win_dbg_break(void); #else /* UNIX */ diff --git a/vm/port/src/signals/linux/signals_common.cpp b/vm/port/src/signals/linux/signals_common.cpp index 3e59778..6a9c932 100644 --- a/vm/port/src/signals/linux/signals_common.cpp +++ b/vm/port/src/signals/linux/signals_common.cpp @@ -27,64 +27,45 @@ #include "stack_dump.h" #include "../linux/include/gdb_crash_handler.h" #include "signals_internal.h" +#include "port_thread_internal.h" -port_tls_key_t port_tls_key; +#define FLAG_CORE ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) +#define FLAG_DBG ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0) -int init_private_tls_data() -{ - return (pthread_key_create(&port_tls_key, NULL) == 0) ? 0 : -1; -} -int free_private_tls_data() +bool is_stack_overflow(port_tls_data_t* tlsdata, void* fault_addr) { - return (pthread_key_delete(port_tls_key) == 0) ? 0 : -1; -} - - -// Because application can set up some protected area in stack region, -// we need to re-enable access to this area because we need to operate -// with the original stack of the thread -// Application should take care of restoring this protected area after -// signal processing -// FIXME This is workaround only; it also can break crash processing for SIGSEGV -// Ideally all the functionality on guard pages should be in Port. -// Unfortunately, it can involve thread creation in Port, additional -// thread wrapper, and moving general TLS operations to Port, so -// it's postponed -static void clear_stack_protection(Registers* regs, void* fault_addr) -{ - if (!fault_addr) // is not SO - return; - - size_t fault = (size_t)fault_addr; - size_t sp = (size_t)regs->get_sp(); - size_t diff = (fault > sp) ? (fault - sp) : (sp - fault); - size_t page_size = (size_t)sysconf(_SC_PAGE_SIZE); - - if (diff > page_size) - return; // Most probably is not SO + if (!tlsdata || !fault_addr) + return false; - size_t start = sp & ~(page_size - 1); - size_t size = page_size; - - if (sp - start < 0x400) + if (tlsdata->guard_page_addr) { - start -= page_size; - size += page_size; + return (fault_addr >= tlsdata->guard_page_addr && + (size_t)fault_addr < (size_t)tlsdata->guard_page_addr + + tlsdata->guard_page_size); } - int res = mprotect((void*)start, size, PROT_READ | PROT_WRITE); + size_t stack_top = + (size_t)tlsdata->stack_addr - tlsdata->stack_size + tlsdata->guard_page_size; + + // Determine that fault is beyond stack top + return ((size_t)fault_addr < stack_top && + (size_t)fault_addr > stack_top - tlsdata->stack_size); } static void c_handler(Registers* pregs, size_t signum, void* fault_addr) { // this exception handler is executed *after* OS signal handler returned int result; + port_tls_data_t* tlsdata = get_private_tls_data(); switch ((int)signum) { case SIGSEGV: - result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE); + if (tlsdata->restore_guard_page) + result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, pregs, fault_addr, FALSE); + else + result = port_process_signal(PORT_SIGNAL_GPF, pregs, fault_addr, FALSE); break; case SIGFPE: result = port_process_signal(PORT_SIGNAL_ARITHMETIC, pregs, fault_addr, FALSE); @@ -108,25 +89,35 @@ static void c_handler(Registers* pregs, size_t signum, void* fault_addr) } if (result == 0) + { + // Restore guard page if needed + if (tlsdata->restore_guard_page) + { + port_thread_restore_guard_page(); + tlsdata->restore_guard_page = FALSE; + + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); + } return; + } // We've got a crash + if (signum == SIGSEGV) + { + port_thread_restore_guard_page(); // To catch SO again + tlsdata->restore_guard_page = FALSE; + } + if (result > 0) // invoke debugger { // Prepare second catch of signal to attach GDB from signal handler - port_tls_data* tlsdata = get_private_tls_data(); - if (!tlsdata) - { // STD_MALLOC can be harmful here - tlsdata = (port_tls_data*)STD_MALLOC(sizeof(port_tls_data)); - memset(tlsdata, 0, sizeof(port_tls_data)); - set_private_tls_data(tlsdata); - } - + //assert(tlsdata); // Should be attached - provided by general_signal_handler tlsdata->debugger = TRUE; return; // To produce signal again } // result < 0 - exit process - if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + if (FLAG_CORE) { // Return to the same place to produce the same crash and generate core signal(signum, SIG_DFL); // setup default handler return; @@ -145,9 +136,10 @@ static void general_signal_handler(int signum, siginfo_t* info, void* context) // Convert OS context to Registers port_thread_context_to_regs(®s, (ucontext_t*)context); + void* fault_addr = info ? info->si_addr : NULL; // Check if SIGSEGV is produced by port_read/write_memory - port_tls_data* tlsdata = get_private_tls_data(); + port_tls_data_t* tlsdata = get_private_tls_data(); if (tlsdata && tlsdata->violation_flag) { tlsdata->violation_flag = 0; @@ -155,25 +147,87 @@ static void general_signal_handler(int signum, siginfo_t* info, void* context) return; } - if (tlsdata && tlsdata->debugger) + if (!tlsdata) // Tread is not attached - attach thread temporarily + { + int res; + tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); + + if (tlsdata) // Try to attach the thread + res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); + + if (!tlsdata || res != 0) + { // Can't process correctly; perform default actions + if (FLAG_DBG) + { + bool result = gdb_crash_handler(®s); + _exit(-1); // Exit process if not sucessful... + } + + if (FLAG_CORE && + signum != SIGABRT) // SIGABRT can't be rethrown + { + signal(signum, SIG_DFL); // setup default handler + return; + } + + _exit(-1); + } + + // SIGSEGV can represent SO which can't be processed out of signal handler + if (signum == SIGSEGV && // This can occur only when a user set an alternative stack + is_stack_overflow(tlsdata, fault_addr)) + { + int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); + + if (result == 0) + { + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); + return; + } + + if (result > 0) + tlsdata->debugger = TRUE; + else + { + if (FLAG_CORE) + { // Rethrow crash to generate core + signal(signum, SIG_DFL); // setup default handler + return; + } + _exit(-1); + } + } + } + + if (tlsdata->debugger) { bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler - (port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0) + FLAG_DBG) { // So attaching GDB right here bool result = gdb_crash_handler(®s); _exit(-1); // Exit process if not sucessful... } - if (signum == SIGSEGV) - clear_stack_protection(®s, info->si_addr); + if (signum == SIGSEGV && + is_stack_overflow(tlsdata, fault_addr)) + { + // Second SO while previous SO is not processed yet - is GPF + if (tlsdata->restore_guard_page) + tlsdata->restore_guard_page = FALSE; + else + { // To process signal on protected stack area + port_thread_clear_guard_page(); + tlsdata->restore_guard_page = TRUE; + } + } // Prepare registers for transfering control out of signal handler void* callback = (void*)&c_handler; - void* fault_addr = info ? info->si_addr : NULL; port_set_longjump_regs(callback, ®s, 3, ®s, (void*)(size_t)signum, fault_addr); @@ -223,7 +277,8 @@ int initialize_signals() for (size_t i = 0; i < sizeof(signals_used)/sizeof(signals_used[0]); i++) { - if (!sd_is_handler_registered(signals_used[i].port_sig)) + if (!sd_is_handler_registered(signals_used[i].port_sig) && + signals_used[i].signal != SIGSEGV) // Sigsegv is needed for port_memaccess continue; sigemptyset(&sa.sa_mask); diff --git a/vm/port/src/signals/linux/signals_ipf.cpp b/vm/port/src/signals/linux/signals_ipf.cpp index 4ee4944..33b6309 100644 --- a/vm/port/src/signals/linux/signals_ipf.cpp +++ b/vm/port/src/signals/linux/signals_ipf.cpp @@ -21,37 +21,53 @@ #include "open/platform_types.h" #include "port_crash_handler.h" +#include "port_malloc.h" #include "stack_dump.h" #include "../linux/include/gdb_crash_handler.h" #include "signals_internal.h" +#include "port_thread_internal.h" -port_tls_key_t port_tls_key; +#define FLAG_CORE ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) +#define FLAG_DBG ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0) -int init_private_tls_data() -{ - return (pthread_key_create(&port_tls_key, NULL) == 0) ? 0 : -1; +/* Out-of-signal-handler signal processing is not implemented for IPF + +static void c_handler(Registers* pregs, size_t signum, void* fault_addr) +{ // this exception handler is executed *after* VEH handler returned } +*/ -int free_private_tls_data() +bool is_stack_overflow(port_tls_data_t* tlsdata, void* fault_addr) { - return (pthread_key_delete(port_tls_key) == 0) ? 0 : -1; -} + if (!tlsdata || !fault_addr) + return false; + if (tlsdata->guard_page_addr) + { + return (fault_addr >= tlsdata->guard_page_addr && + (size_t)fault_addr < (size_t)tlsdata->guard_page_addr + + tlsdata->guard_page_size); + } -/* Out-of-signal-handler signal processing is not implemented for IPF + size_t stack_top = + (size_t)tlsdata->stack_addr - tlsdata->stack_size + tlsdata->guard_page_size; -static void c_handler(Registers* pregs, size_t signum, void* fault_addr) -{ // this exception handler is executed *after* VEH handler returned + // Determine that fault is beyond stack top + return ((size_t)fault_addr < stack_top && + (size_t)fault_addr > stack_top - tlsdata->stack_size); } -*/ static void general_signal_handler(int signum, siginfo_t* info, void* context) { Registers regs; + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!context) + return; + /* Not implemented // Check if SIGSEGV is produced by port_read/write_memory - port_tls_data* tlsdata = get_private_tls_data(); if (tlsdata && tlsdata->violation_flag) { tlsdata->violation_flag = 0; @@ -63,6 +79,60 @@ static void general_signal_handler(int signum, siginfo_t* info, void* context) port_thread_context_to_regs(®s, (ucontext_t*)context); void* fault_addr = info ? info->si_addr : NULL; + + if (!tlsdata) // Tread is not attached - attach thread temporarily + { + int res; + tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); + + if (tlsdata) // Try to attach the thread + res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); + + if (!tlsdata || res != 0) + { // Can't process correctly; perform default actions + if (FLAG_DBG) + { + bool result = gdb_crash_handler(®s); + _exit(-1); // Exit process if not sucessful... + } + + if (FLAG_CORE && + signum != SIGABRT) // SIGABRT can't be rethrown + { + signal(signum, SIG_DFL); // setup default handler + return; + } + + _exit(-1); + } + + // SIGSEGV can represent SO which can't be processed out of signal handler + if (signum == SIGSEGV && // This can occur only when a user set an alternative stack + is_stack_overflow(tlsdata, fault_addr)) + { + int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); + + if (result == 0) + { + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); + return; + } + + if (result > 0) + tlsdata->debugger = TRUE; + else + { + if (FLAG_CORE) + { // Rethrow crash to generate core + signal(signum, SIG_DFL); // setup default handler + return; + } + _exit(-1); + } + } + } + int result; switch ((int)signum) @@ -91,21 +161,26 @@ static void general_signal_handler(int signum, siginfo_t* info, void* context) result = port_process_signal(PORT_SIGNAL_UNKNOWN, ®s, fault_addr, TRUE); } - if (result == 0) + // Convert Registers back to OS context + port_thread_regs_to_context((ucontext_t*)context, ®s); + + if (result == 0) // Signal was processed - continue execution + { + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); return; + } // We've got a crash if (result > 0) { // result > 0 - invoke debugger bool result = gdb_crash_handler(®s); - // Continue with exiting process if not sucessful... + // Continue with making core or exiting process if not successful... } - // Convert Registers back to OS context - port_thread_regs_to_context((ucontext_t*)context, ®s); - // result < 0 - exit process - if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + if (FLAG_CORE && + signum != SIGABRT) // SIGABRT can't be rethrown { // Return to the same place to produce the same crash and generate core signal(signum, SIG_DFL); // setup default handler return; diff --git a/vm/port/src/signals/port_signals.cpp b/vm/port/src/signals/port_signals.cpp index 23e2629..7501f19 100644 --- a/vm/port/src/signals/port_signals.cpp +++ b/vm/port/src/signals/port_signals.cpp @@ -26,12 +26,20 @@ int port_set_breakpoint(void* addr, unsigned char* prev) if (!addr || !prev) return -1; + unsigned char buf; unsigned char instr = INSTRUMENTATION_BYTE; - if (port_read_memory(addr, 1, prev) != 0) + int err = port_read_memory(addr, 1, &buf); + if (err != 0) return err; + + if (buf == instr) return -1; - return port_write_memory(addr, 1, &instr); + err = port_write_memory(addr, 1, &instr); + if (err != 0) return err; + + *prev = buf; + return 0; } int port_clear_breakpoint(void* addr, unsigned char prev) @@ -39,6 +47,15 @@ int port_clear_breakpoint(void* addr, unsigned char prev) if (!addr) return -1; + unsigned char buf; + unsigned char instr = INSTRUMENTATION_BYTE; + + int err = port_read_memory(addr, 1, &buf); + if (err != 0) return err; + + if (buf != instr) + return -1; + return port_write_memory(addr, 1, &prev); } diff --git a/vm/port/src/signals/win/signals_common.cpp b/vm/port/src/signals/win/signals_common.cpp index c777df8..a6d72e7 100644 --- a/vm/port/src/signals/win/signals_common.cpp +++ b/vm/port/src/signals/win/signals_common.cpp @@ -27,6 +27,7 @@ #include "port_crash_handler.h" #include "stack_dump.h" #include "signals_internal.h" +#include "port_thread_internal.h" #if INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 @@ -37,10 +38,11 @@ #error Unknown value of INSTRUMENTATION_BYTE #endif +#define FLAG_CORE ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) +#define FLAG_DBG ((port_crash_handler_get_flags() & PORT_CRASH_CALL_DEBUGGER) != 0) -port_tls_key_t port_tls_key = TLS_OUT_OF_INDEXES; -typedef void (__cdecl *sigh_t)(int); // Signal handler type +typedef void (PORT_CDECL *sigh_t)(int); // Signal handler type static PVOID veh = NULL; static sigh_t prev_sig = (sigh_t)SIG_ERR; @@ -53,20 +55,22 @@ static _HFILE report_files[3]; static bool asserts_disabled = false; -int init_private_tls_data() +static void show_debugger_dialog() { - DWORD key = TlsAlloc(); - - if (key == TLS_OUT_OF_INDEXES) - return -1; + int result = MessageBox(NULL, + "Crash handler has been requested to call the debugger\n\n" + "Press Retry to attach to the debugger\n" + "Press Cancel to terminate the application", + "Crash Handler", + MB_RETRYCANCEL | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL); - port_tls_key = key; - return 0; -} + if (result == IDCANCEL) + { + _exit(3); + return; + } -int free_private_tls_data() -{ - return TlsFree(port_tls_key) ? 0 : -1; + port_win_dbg_break(); // Call the debugger } @@ -74,7 +78,6 @@ static void c_handler(Registers* pregs, void* fault_addr, size_t code, size_t flags) { // this exception handler is executed *after* VEH handler returned int result; - Registers regs = *pregs; Boolean iscrash = (DWORD)flags == EXCEPTION_NONCONTINUABLE; switch ((DWORD)code) @@ -99,69 +102,127 @@ static void c_handler(Registers* pregs, result = port_process_signal(PORT_SIGNAL_UNKNOWN, pregs, fault_addr, TRUE); } + port_tls_data_t* tlsdata = get_private_tls_data(); + if (result == 0) + { + // Restore guard page if needed + if (tlsdata->restore_guard_page) + { + port_thread_restore_guard_page(); + tlsdata->restore_guard_page = FALSE; + + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); + } return; + } - if (result > 0 || // Assert dialog - (port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + if (result > 0 /*Assert dialog*/|| FLAG_CORE) { // Prepare second catch of this exception to produce minidump (because // we've lost LPEXCEPTION_POINTERS structure) and/or show assert dialog - // FIXME: This will not work for stack overflow, because guard page - // is disabled automatically - need to restore it somehow - port_tls_data* tlsdata = get_private_tls_data(); - if (!tlsdata) - { // STD_MALLOC can be harmful here - tlsdata = (port_tls_data*)STD_MALLOC(sizeof(port_tls_data)); - memset(tlsdata, 0, sizeof(port_tls_data)); - set_private_tls_data(tlsdata); - } - - if ((port_crash_handler_get_flags() & PORT_CRASH_DUMP_PROCESS_CORE) != 0) + if (FLAG_CORE) tlsdata->produce_core = TRUE; if (result > 0) tlsdata->debugger = TRUE; + // To catch STACK_OVERFLOW + port_thread_restore_guard_page(); return; // To produce exception again } - _exit(-1); + _exit(-1); // We need neither dump nor assert dialog } void prepare_assert_dialog(Registers* regs) { + // To catch STACK_OVERFLOW + port_thread_restore_guard_page(); shutdown_signals(); } LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception) { + DWORD code = nt_exception->ExceptionRecord->ExceptionCode; + void* fault_addr = nt_exception->ExceptionRecord->ExceptionAddress; + Registers regs; // Convert NT context to Registers port_thread_context_to_regs(®s, nt_exception->ContextRecord); // Check if TLS structure is set - probably we should produce minidump - port_tls_data* tlsdata = get_private_tls_data(); + port_tls_data_t* tlsdata = get_private_tls_data(); - if (tlsdata) + if (!tlsdata) // Tread is not attached - attach thread temporarily { - if (tlsdata->produce_core) - { - tlsdata->produce_core = FALSE; - create_minidump(nt_exception); - if (!tlsdata->debugger) + int res; + tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); + + if (tlsdata) // Try to attach the thread + res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0); + + if (!tlsdata || res != 0) + { // Can't process correctly; perform default actions + if (FLAG_CORE) + create_minidump(nt_exception); + + if (FLAG_DBG) + { + show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work _exit(-1); + return EXCEPTION_CONTINUE_SEARCH; // Assert dialog + } + + _exit(-1); } - if (tlsdata->debugger) + // SO for alien thread can't be processed out of VEH + if (code == STATUS_STACK_OVERFLOW && + sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW)) { - // Go to handler to restore CRT/VEH settings and crash once again - port_set_longjump_regs(&prepare_assert_dialog, ®s, 1, ®s); - port_thread_regs_to_context(nt_exception->ContextRecord, ®s); - return EXCEPTION_CONTINUE_EXECUTION; + int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, ®s, fault_addr, FALSE); + + if (result == 0) + { + if (port_thread_detach_temporary() == 0) + STD_FREE(tlsdata); + return EXCEPTION_CONTINUE_EXECUTION; + } + + if (FLAG_CORE) + create_minidump(nt_exception); + + if (result > 0) + { + show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work + _exit(-1); + shutdown_signals(); + return EXCEPTION_CONTINUE_SEARCH; // Assert dialog + } + + _exit(-1); } } - switch (nt_exception->ExceptionRecord->ExceptionCode) + if (tlsdata->produce_core) + { + create_minidump(nt_exception); + if (!tlsdata->debugger) + _exit(-1); + } + + if (tlsdata->debugger) + { + show_debugger_dialog(); // Workaround + _exit(-1); + // Go to handler to restore CRT/VEH settings and crash once again +// port_set_longjump_regs(&prepare_assert_dialog, ®s, 1, ®s); +// port_thread_regs_to_context(nt_exception->ContextRecord, ®s); +// return EXCEPTION_CONTINUE_EXECUTION; + } + + switch (code) { case STATUS_STACK_OVERFLOW: if (!sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW)) @@ -187,6 +248,12 @@ LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception return EXCEPTION_CONTINUE_SEARCH; } + if (code == STATUS_STACK_OVERFLOW) + { + if (!tlsdata->restore_guard_page) + tlsdata->restore_guard_page = TRUE; + } + // Prepare to transfering control out of VEH handler port_set_longjump_regs(&c_handler, ®s, 4, ®s, nt_exception->ExceptionRecord->ExceptionAddress, @@ -258,25 +325,7 @@ static void restore_assert_dialogs() #endif // _DEBUG } -static void show_debugger_dialog() -{ - int result = MessageBox(NULL, - "ABORT handler has requested to call the debugger\n\n" - "Press Retry to attach to the debugger\n" - "Press Cancel to terminate the application", - "Crash Handler", - MB_RETRYCANCEL | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL); - - if (result == IDCANCEL) - { - _exit(3); - return; - } - - port_win_dbg_break(); // Call the debugger -} - -static void __cdecl sigabrt_handler(int signum) +static void PORT_CDECL sigabrt_handler(int signum) { int result = port_process_signal(PORT_SIGNAL_ABORT, NULL, NULL, FALSE); // There no reason for checking for 0 - abort() will do _exit(3) anyway @@ -291,7 +340,7 @@ static void __cdecl sigabrt_handler(int signum) _exit(3); } -static void __cdecl final_sigabrt_handler(int signum) +static void PORT_CDECL final_sigabrt_handler(int signum) { _exit(3); } diff --git a/vm/port/src/signals/win/signals_ia32.cpp b/vm/port/src/signals/win/signals_ia32.cpp index 6f32351..55e7e70 100644 --- a/vm/port/src/signals/win/signals_ia32.cpp +++ b/vm/port/src/signals/win/signals_ia32.cpp @@ -36,7 +36,7 @@ LONG __declspec(naked) NTAPI vectored_exception_handler(LPEXCEPTION_POINTERS nt_ } } -void __declspec(naked) __cdecl port_win_dbg_break() +void __declspec(naked) PORT_CDECL port_win_dbg_break() { __asm { int 3 } } diff --git a/vm/port/src/thread/include/port_thread_internal.h b/vm/port/src/thread/include/port_thread_internal.h new file mode 100644 index 0000000..02df984 --- /dev/null +++ b/vm/port/src/thread/include/port_thread_internal.h @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PORT_THREAD_INTERNAL_H_ +#define _PORT_THREAD_INTERNAL_H_ + +#include "port_general.h" +#include "port_thread.h" +#include "open/platform_types.h" +#include "open/hythread_ext.h" /* For windows.h */ +/* UNIX-specific includes */ +#ifndef WIN32 +#include +#endif + +#ifdef WIN32 +typedef DWORD port_tls_key_t; +#else +typedef pthread_key_t port_tls_key_t; +#endif + +typedef enum +{ + THREADREQ_NONE = 0, + THREADREQ_SUS = 1, + THREADREQ_RES = 2, + THREADREQ_YIELD = 3 +} port_suspend_req_t; + + +typedef struct port_thread_info_t port_thread_info_t; +struct port_thread_info_t +{ + osthread_t thread; + thread_context_t context; + int suspend_count; +#ifndef WIN32 + sem_t wake_sem; /* to sem_post from signal handler */ +#endif /* !WIN32 */ + port_thread_info_t* next; +}; + + +typedef struct +{ + port_tls_key_t tls_key; + + size_t guard_page_size; + size_t guard_stack_size; + size_t mem_protect_size; + size_t foreign_stack_size; + + /* Stuff for suspend/resume handling */ + port_thread_info_t* suspended_list; +#ifdef WIN32 + CRITICAL_SECTION crit_section; +#else /* !WIN32 */ + pthread_mutex_t suspend_init_mutex; + pthread_mutex_t suspend_mutex; + port_suspend_req_t req_type; /* request type for signal handler */ + osthread_t suspendee; /* The thread which is processed */ + sem_t yield_sem; /* Semaphore to inform signal sender */ + Boolean signal_set; /* Is SIGUSR2 handler is set up */ +#endif /* !WIN32 */ + +} port_shared_data_t; + + +/* Thread-specific structure */ +typedef struct +{ + /* vv Threading stuff vv */ + void* stack_addr; + size_t stack_size; + void* guard_page_addr; + size_t guard_page_size; + void* guard_stack_addr; + size_t guard_stack_size; + size_t mem_protect_size; + + Boolean guard_page_set; + Boolean restore_guard_page; + + Boolean foreign; /* The thread was attached */ + //Boolean temp; /* Is indicated by 0ed guard_page_addr instead */ + + /* vv Signal handling stuff vv */ +#ifndef WIN32 /* UNIX */ + /* Flag and restart address for memory access violation detection */ + int violation_flag; + void* restart_address; +#endif /* UNIX */ + + /* vv Crash handling stuff vv */ + /* Previous crash handling stage to restart crash processing */ + int crash_stage; + + /* Flag to indicate that debugger should be attached right in OS handler */ + Boolean debugger; + /* Flag to produce minidump/core on the second exception catch */ + Boolean produce_core; + +} port_tls_data_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile port_shared_data_t* port_shared_data; +#define PSD ((port_shared_data_t*)port_shared_data) + + +int init_port_shared_data(); + + +PORT_INLINE port_tls_data_t* get_private_tls_data() +{ + if (!port_shared_data) + { + if (init_port_shared_data() != 0) + return NULL; + } +#ifdef WIN32 + return (port_tls_data_t*)TlsGetValue(port_shared_data->tls_key); +#else +// return (port_tls_data_t*)pthread_getspecific(port_shared_data->tls_key); + { + port_tls_data_t* data = + (port_tls_data_t*)pthread_getspecific(port_shared_data->tls_key); + + pthread_key_t key; + int err = pthread_setspecific(port_shared_data->tls_key, data); + if (err == 0) + return data; + + if (!pthread_key_create(&key, NULL) && key == port_shared_data->tls_key) + return (port_tls_data_t*)pthread_getspecific(port_shared_data->tls_key); + + return NULL; + } +#endif +} + +PORT_INLINE int set_private_tls_data(port_tls_data_t* data) +{ + if (!port_shared_data) + { + if (init_port_shared_data() != 0) + return -1; + } +#ifdef WIN32 + return TlsSetValue(port_shared_data->tls_key, data) ? 0 : -1; +#else + { + pthread_key_t key; + + int err = pthread_setspecific(port_shared_data->tls_key, data); + if (err == 0) + return 0; + + if (!pthread_key_create(&key, NULL) && key == port_shared_data->tls_key) + return pthread_setspecific(port_shared_data->tls_key, data); + + return err; + } +#endif +} + + +/* Is used in both threading and signals */ +int port_thread_attach_local(port_tls_data_t* tlsdata, Boolean temp, + Boolean foreign, size_t stack_size); +/* Detaches temporarily attached thread */ +int port_thread_detach_temporary(); + + +#ifdef __cplusplus +} +#endif + +#endif /* _PORT_THREAD_INTERNAL_H_ */ diff --git a/vm/port/src/thread/linux/port_thread_tls_os.c b/vm/port/src/thread/linux/port_thread_tls_os.c new file mode 100644 index 0000000..d58796f --- /dev/null +++ b/vm/port/src/thread/linux/port_thread_tls_os.c @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef __USE_XOPEN +#include +#include +#include +#include +#include +#include +#include + +#include "port_mutex.h" +#include "port_thread_internal.h" + + +static pthread_mutex_t g_shared_data_mutex = PTHREAD_MUTEX_INITIALIZER; +volatile port_shared_data_t* port_shared_data = NULL; + +#ifdef _EM64T_ +#define MEM_PROTECT_SIZE 0x400 +#elif defined (_IPF_) +#define MEM_PROTECT_SIZE 0 +#else /* _IA32_ */ +#define MEM_PROTECT_SIZE 0x100 +#endif + +static int init_psd_structure(port_shared_data_t* data) +{ + int err; + pthread_attr_t pthread_attr; + size_t stack_size, guard_size; + + memset(data, 0, sizeof(port_shared_data_t)); + + if ((err = pthread_key_create(&data->tls_key, NULL)) != 0) + return err; + + if ((err = pthread_mutex_init(&data->suspend_mutex, NULL)) != 0) + return err; + + if ((err = pthread_mutex_init(&data->suspend_init_mutex, NULL)) != 0) + return err; + + pthread_attr_init(&pthread_attr); + err = pthread_attr_getstacksize(&pthread_attr, &stack_size); + pthread_attr_destroy(&pthread_attr); + + if (err != 0) + return err; + + pthread_attr_init(&pthread_attr); + err = pthread_attr_getguardsize(&pthread_attr, &guard_size); + pthread_attr_destroy(&pthread_attr); + + if (err != 0) + return err; + + if (sem_init(&data->yield_sem, 0, 0) != 0) + return err; + + data->foreign_stack_size = stack_size; + data->guard_page_size = guard_size; + data->mem_protect_size = MEM_PROTECT_SIZE; + data->req_type = THREADREQ_NONE; + + data->guard_stack_size = 64*1024; + + if (data->guard_stack_size < MINSIGSTKSZ) + data->guard_stack_size = + (MINSIGSTKSZ + guard_size - 1) & ~(guard_size - 1); + + return 0; +} + +int init_port_shared_data() +{ +#define INIT_PSD_EXIT(_err_) \ + {err = _err_; goto init_psd_exit;} + + int shmid, err; + char shmstring[25]; + void* sh_ptr = NULL; + size_t page_size = (size_t)sysconf(_SC_PAGE_SIZE); + size_t data_size = + (sizeof(port_shared_data_t) + page_size - 1) & ~(page_size - 1); + + if (port_shared_data) + return 0; + + /* Serialize access to avoid multiple creation */ + err = pthread_mutex_lock(&g_shared_data_mutex); + if (err != 0) + return err; + + /* Another thread acquired the mutex first and initialized data already */ + if (port_shared_data) + INIT_PSD_EXIT(0); /* Success */ + + /* Initialize shared memory for static global objects */ + sprintf(shmstring, "portshmdata_%d", getpid()); + shmid = shm_open(shmstring, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 00600);/* S_IRUSR | S_IWUSR */ + + if (shmid == -1 && errno != EEXIST) + INIT_PSD_EXIT(errno); /* failure */ + + if (shmid == -1) + { /* Shared object have been created already */ + shmid = shm_open(shmstring, O_CREAT | O_RDWR, 00600);/* S_IRUSR | S_IWUSR */ + + if (shmid == -1) + INIT_PSD_EXIT(errno); /* Error occured */ + + sh_ptr = mmap(0, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0); + + if (sh_ptr == (void*)-1) + INIT_PSD_EXIT(errno); /* Another one error */ + + port_shared_data = (port_shared_data_t*)sh_ptr; /* Fill the pointer */ + close(shmid); + INIT_PSD_EXIT(0); + } + + /* Successfully created for the first time */ + err = ftruncate(shmid, data_size); + + if (err != 0) + return errno; + + sh_ptr = mmap(0, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmid, 0); + + if (sh_ptr == (void*)-1) + INIT_PSD_EXIT(errno); /* Failed to attach */ + + err = init_psd_structure((port_shared_data_t*)sh_ptr); + + if (err == 0) + port_shared_data = (port_shared_data_t*)sh_ptr; /* Fill the pointer */ + +init_psd_exit: +#undef INIT_PSD_EXIT + pthread_mutex_unlock(&g_shared_data_mutex); + return err; +} diff --git a/vm/port/src/thread/linux/thread_os.c b/vm/port/src/thread/linux/thread_os.c index 8fbec48..65d1691 100644 --- a/vm/port/src/thread/linux/thread_os.c +++ b/vm/port/src/thread/linux/thread_os.c @@ -17,56 +17,44 @@ #define _GNU_SOURCE #include -#include // sched_param +#include // sched_param #include #include -#include -#include +#include #include -#include "port_thread.h" - - - -typedef enum -{ - THREADREQ_NONE = 0, - THREADREQ_SUS = 1, - THREADREQ_RES = 2, - THREADREQ_YIELD = 3 -} os_suspend_req_t; - -typedef struct os_thread_info_t os_thread_info_t; - -struct os_thread_info_t -{ - osthread_t thread; - int suspend_count; - sem_t wake_sem; /* to sem_post from signal handler */ - thread_context_t context; - - os_thread_info_t* next; -}; - -/* Global mutex to syncronize access to os_thread_info_t list */ -static pthread_mutex_t g_suspend_mutex; -/* Global list with suspended threads info */ -static os_thread_info_t* g_suspended_list; -/* request type for signal handler */ -os_suspend_req_t g_req_type; -/* The thread which is processed */ -static osthread_t g_suspendee; -/* Semaphore used to inform signal sender about signal delivery */ -static sem_t g_yield_sem; +#include "port_malloc.h" +#include "port_thread.h" +#include "port_thread_internal.h" + +// Linux/FreeBSD defines +#if defined(FREEBSD) +#define STACK_MMAP_ATTRS \ + (MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_STACK) +#else +#ifdef _IPF_ +#define STACK_MMAP_ATTRS \ + (MAP_PRIVATE | MAP_ANONYMOUS) +#else /* !_IPF_ */ +#define STACK_MMAP_ATTRS \ + (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN) +#endif /* _IPF_ */ +#endif + +#ifdef _IPF_ +#define STACK_MAPPING_ACCESS (PROT_READ | PROT_WRITE) +#else /* !_IPF_ */ +#define STACK_MAPPING_ACCESS (PROT_READ | PROT_WRITE | PROT_EXEC) +#endif /* _IPF_ */ /* Forward declarations */ static int suspend_init(); static int suspend_init_lock(); -static os_thread_info_t* init_susres_list_item(); -static os_thread_info_t* suspend_add_thread(osthread_t thread); +static port_thread_info_t* init_susres_list_item(); +static port_thread_info_t* suspend_add_thread(osthread_t thread); static void suspend_remove_thread(osthread_t thread); -static os_thread_info_t* suspend_find_thread(osthread_t thread); +static port_thread_info_t* suspend_find_thread(osthread_t thread); static void sigusr2_handler(int signum, siginfo_t* info, void* context); @@ -88,34 +76,480 @@ void get_exceed_time(struct timespec* ptime, long delay) } } -/** - * Terminates the os thread. - */ +typedef void* (PORT_CDECL *pthread_func_t)(void*); + +typedef struct +{ + port_threadfunc_t fun; + void* arg; + size_t stack_size; +} thread_start_struct_t; + +static PORT_CDECL int thread_start_func(void* arg) +{ + int err, result; + port_tls_data_t* tlsdata; + thread_start_struct_t* ptr = (thread_start_struct_t*)arg; + port_threadfunc_t fun = ptr->fun; + size_t stack_size = ptr->stack_size; + arg = ptr->arg; + STD_FREE(ptr); + + tlsdata = (port_tls_data_t*)STD_ALLOCA(sizeof(port_tls_data_t)); + err = port_thread_attach_local(tlsdata, FALSE, FALSE, stack_size); + assert(err == 0); + + result = fun(arg); + + port_thread_detach(); + + return result; +} + +int port_thread_create(/* out */osthread_t* phandle, size_t stacksize, int priority, + port_threadfunc_t func, void *data) +{ + pthread_t thread; + pthread_attr_t attr; + struct sched_param param; + thread_start_struct_t* startstr; + int res; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + if (!func) + return EINVAL; + + startstr = + (thread_start_struct_t*)STD_MALLOC(sizeof(thread_start_struct_t)); + + if (!startstr) + return ENOMEM; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if (stacksize != 0) + { + res = pthread_attr_setstacksize(&attr, stacksize); + if (res) + { + pthread_attr_destroy(&attr); + STD_FREE(startstr); + return res; + } + } + + if (priority) + { + res = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + if (res == 0) + { + param.sched_priority = priority; + res = pthread_attr_setschedparam(&attr, ¶m); + } + /* This does not work anyway on some Linuses + if (res != 0) + { + pthread_attr_destroy(&attr); + STD_FREE(startstr); + return res; + }*/ + } + + startstr->fun = func; + startstr->arg = data; + startstr->stack_size = stacksize; + + res = pthread_create(&thread, &attr, (pthread_func_t)thread_start_func, startstr); + + pthread_attr_destroy(&attr); + + if (res == 0) + { + *phandle = thread; + return 0; + } + + STD_FREE(startstr); + return res; +} + +static int set_guard_page(port_tls_data_t* tlsdata, Boolean set) +{ + int res; + stack_t sigalt; + + if (!tlsdata) + tlsdata = get_private_tls_data(); + + if (!tlsdata) + return -1; + + if (!tlsdata->guard_page_addr) + return 0; + + if ((set && tlsdata->guard_page_set) || + !set && !tlsdata->guard_page_set) + return 0; // Already in needed state + + res = mprotect(tlsdata->guard_page_addr, tlsdata->guard_page_size, + set ? PROT_NONE : (PROT_READ | PROT_WRITE | PROT_EXEC)); + + if (res != 0) + return errno; + + // sets alternative stack + sigalt.ss_sp = tlsdata->guard_stack_addr; + sigalt.ss_size = tlsdata->guard_stack_size; +//#if defined(FREEBSD) + sigalt.ss_flags = set ? 0 : SS_DISABLE; +//#else +// sigalt.ss_flags = set ? SS_ONSTACK : SS_DISABLE; +//#endif + res = sigaltstack(&sigalt, NULL); + + if (res != 0) + return errno; + + tlsdata->guard_page_set = set; + return 0; +} + +int port_thread_restore_guard_page() +{ + return set_guard_page(NULL, TRUE); +} + +int port_thread_clear_guard_page() +{ + return set_guard_page(NULL, FALSE); +} + +void port_thread_postpone_guard_page() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata || !tlsdata->guard_page_addr) + return; + + tlsdata->restore_guard_page = FALSE; +} + +void* port_thread_get_stack_address() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + return tlsdata ? tlsdata->stack_addr : NULL; +} + +size_t port_thread_get_stack_size() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + return tlsdata ? tlsdata->stack_size : 0; +} + +size_t port_thread_get_effective_stack_size() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata) + return 0; + + if (!tlsdata->guard_page_addr || !tlsdata->guard_page_set) + return tlsdata->stack_size + - PSD->guard_page_size + - PSD->mem_protect_size; + + return tlsdata->stack_size - 2*PSD->guard_page_size + - PSD->guard_stack_size - PSD->mem_protect_size; +} + +static int setup_stack(port_tls_data_t* tlsdata) +{ + int res; + void* ptr; + stack_t sigalt; + size_t current_page_addr, mapping_addr, mapping_size; + + if (!port_shared_data) + return -1; + + current_page_addr = ((size_t)&res) & ~(PSD->guard_page_size - 1); + // leave place for mmap work + mapping_addr = current_page_addr - PSD->guard_page_size; + // found size of the stack area which should be maped + mapping_size = tlsdata->stack_size + - ((size_t)tlsdata->stack_addr - mapping_addr); + + if ((size_t)(&res) - PSD->mem_protect_size + < (size_t)tlsdata->guard_page_addr + tlsdata->guard_page_size) + return EINVAL; + + // maps unmapped part of the stack + ptr = (char*)mmap(tlsdata->stack_addr - tlsdata->stack_size, mapping_size, + STACK_MAPPING_ACCESS, STACK_MMAP_ATTRS, -1, 0); + + if (ptr == MAP_FAILED) + return errno; + + res = set_guard_page(tlsdata, TRUE); + + if (res != 0) + return errno; + + return 0; +} + +inline int find_stack_addr_size(void** paddr, size_t* psize) +{ + int err; + pthread_attr_t pthread_attr; + void* stack_addr; + size_t stack_size; + pthread_t thread = pthread_self(); + + if (!paddr) return EINVAL; + + err = pthread_attr_init(&pthread_attr); + if (err != 0) return err; + +#if defined(FREEBSD) + err = pthread_attr_get_np(thread, &pthread_attr); +#else + err = pthread_getattr_np(thread, &pthread_attr); +#endif + if (err != 0) return err; + + err = pthread_attr_getstack(&pthread_attr, &stack_addr, &stack_size); + if (err != 0) return err; + + pthread_attr_destroy(&pthread_attr); + *paddr = (void*)((size_t)stack_addr + stack_size); + *psize = stack_size; + return 0; +} + +static int init_stack(port_tls_data_t* tlsdata, size_t stack_size, Boolean temp) +{ + int err; + size_t stack_begin; + + if (!port_shared_data) + return -1; + + err = find_stack_addr_size(&tlsdata->stack_addr, &tlsdata->stack_size); + if (err != 0) return err; + + if (tlsdata->foreign || temp || stack_size == 0) + tlsdata->stack_size = PSD->foreign_stack_size; + else + tlsdata->stack_size = stack_size; + + tlsdata->guard_page_size = PSD->guard_page_size; + tlsdata->guard_stack_size = PSD->guard_stack_size; + tlsdata->mem_protect_size = PSD->mem_protect_size; + + if (temp) + return 0; + + stack_begin = (size_t)tlsdata->stack_addr - tlsdata->stack_size; + tlsdata->guard_stack_addr = (void*)(stack_begin + tlsdata->guard_page_size); + tlsdata->guard_page_addr = + (void*)((size_t)tlsdata->guard_stack_addr + tlsdata->guard_stack_size); + + return setup_stack(tlsdata); +} + +int port_thread_attach_local(port_tls_data_t* tlsdata, Boolean temp, + Boolean foreign, size_t stack_size) +{ + int res; + + memset(tlsdata, 0, sizeof(port_tls_data_t)); + + tlsdata->foreign = foreign; + res = init_stack(tlsdata, stack_size, temp); + if (res != 0) return res; +/* They are already zeroed + tlsdata->violation_flag = 0; + tlsdata->debugger = FALSE; + tlsdata->produce_core = FALSE;*/ + + res = set_private_tls_data(tlsdata); + + if (res != 0) + set_guard_page(tlsdata, FALSE); + + return res; +} + +int port_thread_attach() +{ + int res; + port_tls_data_t* tlsdata; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + if (get_private_tls_data()) + return 0; + + tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); + + if (!tlsdata) + return ENOMEM; + + res = port_thread_attach_local(tlsdata, FALSE, TRUE, 0); + + if (res != 0) + STD_FREE(tlsdata); + + return res; +} + +int port_thread_detach_temporary() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata || tlsdata->guard_page_addr) + return -1; + + return set_private_tls_data(NULL); +} + +int port_thread_detach() +{ + port_tls_data_t* tlsdata; + int res; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + tlsdata = get_private_tls_data(); + + if (!tlsdata) + return 0; + + if (port_thread_detach_temporary() == 0) + return 0; + + res = set_guard_page(tlsdata, FALSE); + + if (res != 0) + return res; + + if (tlsdata->foreign) + STD_FREE(tlsdata); + + return set_private_tls_data(NULL); +} + +int port_thread_set_priority(osthread_t os_thread, int priority) +{ +#if defined(FREEBSD) + /* Not sure why we don't just use this on linux? - MRH */ + struct sched_param param; + int policy; + int r = pthread_getschedparam(os_thread, &policy, ¶m); + if (r == 0) { + param.sched_priority = priority; + r = pthread_setschedparam(os_thread, policy, ¶m); + } + return r; +#else + // setting thread priority on linux is only supported for current thread + if (os_thread == pthread_self()) { + int r; + struct sched_param param; + pid_t self = gettid(); + param.sched_priority = priority; + r = sched_setparam(self, ¶m); + return r ? errno : 0; + } else { + // setting other thread priority not supported on linux + return 0; + } +#endif +} + +osthread_t port_thread_current() +{ + return pthread_self(); +} + +int port_thread_free_handle(osthread_t os_thread) +{ + return 0; +} + +int port_thread_join(osthread_t os_thread) +{ + int error; + + do { + // FIXME - somehow pthread_join returns before thread is terminated + error = pthread_join(os_thread, NULL); + } while (error != ESRCH && error != EINVAL && error != EDEADLK); + return 0; +} + int port_thread_cancel(osthread_t os_thread) { int status; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!suspend_init_lock()) return -1; pinfo = suspend_find_thread(os_thread); + + if (os_thread == pthread_self()) + { + if (pinfo && status == 0) + suspend_remove_thread(os_thread); + pthread_mutex_unlock(&PSD->suspend_mutex); + return pthread_cancel(os_thread); + } + status = pthread_cancel(os_thread); if (pinfo && status == 0) suspend_remove_thread(os_thread); - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } -/** -* Sends a signal to a thread to make sure thread's write - * buffers are flushed. - */ +void port_thread_exit(int status) +{ + pthread_exit((void*)(size_t)status); +} + +int port_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser) +{ + clockid_t clock_id; + struct timespec tp; + int r; +#ifdef FREEBSD + return EINVAL; /* TOFIX: Implement */ +#else + + r = pthread_getcpuclockid(os_thread, &clock_id); + if (r) return r; + + r = clock_gettime(clock_id, &tp); + if (r) return r; + + *puser = tp.tv_sec * 1000000000ULL + tp.tv_nsec; + return 0; +#endif +} + void port_thread_yield_other(osthread_t os_thread) { struct timespec timeout; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; + int err = -1; if (!suspend_init_lock()) return; @@ -123,37 +557,36 @@ void port_thread_yield_other(osthread_t os_thread) { pinfo = suspend_find_thread(os_thread); if (pinfo && pinfo->suspend_count > 0) { - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return; } - g_suspendee = os_thread; - g_req_type = THREADREQ_YIELD; + PSD->suspendee = os_thread; + PSD->req_type = THREADREQ_YIELD; assert(os_thread); if (pthread_kill(os_thread, SIGUSR2) == 0) { // signal sent, let's do timed wait to make sure the signal // was actually delivered - get_exceed_time(&timeout, 1000000L); - sem_timedwait(&g_yield_sem, &timeout); + get_exceed_time(&timeout, 10000000L); + err = sem_timedwait(&PSD->yield_sem, &timeout); +// sem_wait(&PSD->yield_sem); } else { if (pinfo) suspend_remove_thread(os_thread); } - g_req_type = THREADREQ_NONE; - pthread_mutex_unlock(&g_suspend_mutex); + if (err != 0) + PSD->req_type = THREADREQ_NONE; + + pthread_mutex_unlock(&PSD->suspend_mutex); } -/** - * Suspend given thread - * @param thread The thread to suspend - */ int port_thread_suspend(osthread_t thread) { int status; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!thread) return -1; @@ -168,24 +601,24 @@ int port_thread_suspend(osthread_t thread) if (!pinfo) { - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return -1; } if (pinfo->suspend_count > 0) { ++pinfo->suspend_count; - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return 0; } - g_suspendee = thread; - g_req_type = THREADREQ_SUS; + PSD->suspendee = thread; + PSD->req_type = THREADREQ_SUS; if (pthread_kill(thread, SIGUSR2) != 0) { suspend_remove_thread(thread); - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return -1; } @@ -194,18 +627,14 @@ int port_thread_suspend(osthread_t thread) /* Check result */ status = (pinfo->suspend_count > 0) ? 0 : -1; - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } -/** - * Resume given thread - * @param thread The thread to resume - */ int port_thread_resume(osthread_t thread) { int status; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!thread) return -1; @@ -217,24 +646,24 @@ int port_thread_resume(osthread_t thread) if (!pinfo) { - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return -1; } if (pinfo->suspend_count > 1) { --pinfo->suspend_count; - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return 0; } - g_suspendee = thread; - g_req_type = THREADREQ_RES; + PSD->suspendee = thread; + PSD->req_type = THREADREQ_RES; if ((status = pthread_kill(thread, SIGUSR2)) != 0) { suspend_remove_thread(thread); - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } @@ -243,18 +672,13 @@ int port_thread_resume(osthread_t thread) suspend_remove_thread(thread); - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return 0; } -/** - * Determine suspend count for the given thread - * @param thread The thread to check - * @return -1 if error have occured - */ int port_thread_get_suspend_count(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; int suspend_count; if (!thread) @@ -267,20 +691,14 @@ int port_thread_get_suspend_count(osthread_t thread) suspend_count = pinfo ? pinfo->suspend_count : 0; - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return suspend_count; } -/** - * Get context for given thread - * @param thread The thread to process - * @param context Pointer to platform-dependant context structure - * @note The thread must be suspended - */ int port_thread_get_context(osthread_t thread, thread_context_t *context) { int status = -1; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!thread || !context) return -1; @@ -292,7 +710,7 @@ int port_thread_get_context(osthread_t thread, thread_context_t *context) if (!pinfo) { - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } @@ -302,20 +720,14 @@ int port_thread_get_context(osthread_t thread, thread_context_t *context) status = -1; } - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } -/** - * Set context for given thread - * @param thread The thread to process - * @param context Pointer to platform-dependant context structure - * @note The thread must be suspended - */ int port_thread_set_context(osthread_t thread, thread_context_t *context) { int status = -1; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!thread || !context) return -1; @@ -327,7 +739,7 @@ int port_thread_set_context(osthread_t thread, thread_context_t *context) if (!pinfo) { - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } @@ -337,53 +749,39 @@ int port_thread_set_context(osthread_t thread, thread_context_t *context) status = 0; } - pthread_mutex_unlock(&g_suspend_mutex); + pthread_mutex_unlock(&PSD->suspend_mutex); return status; } static int suspend_init() { - static int initialized = 0; struct sigaction sa; - static pthread_mutex_t suspend_init_mutex = PTHREAD_MUTEX_INITIALIZER; + int result = 1; - if (initialized) + if (port_shared_data && PSD->signal_set) return 1; - pthread_mutex_lock(&suspend_init_mutex); - - if (!initialized) - { - /* Initialize all nesessary objects */ - int status; - pthread_mutex_t mut_init = PTHREAD_MUTEX_INITIALIZER; - - status = sem_init(&g_yield_sem, 0, 0); - - if (status != 0) - { - pthread_mutex_unlock(&suspend_init_mutex); - return 0; - } - - g_suspend_mutex = mut_init; - pthread_mutex_init(&g_suspend_mutex, NULL); + if (!port_shared_data && init_port_shared_data() != 0) + return 0; - g_suspended_list = NULL; - g_req_type = THREADREQ_NONE; + pthread_mutex_lock(&PSD->suspend_init_mutex); + if (!PSD->signal_set) + { /* set signal handler */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_RESTART; sa.sa_sigaction = sigusr2_handler; - sigaction(SIGUSR2, &sa, NULL); - initialized = 1; + if (sigaction(SIGUSR2, &sa, NULL) != 0) + result = 0; + else + PSD->signal_set = 1; } - pthread_mutex_unlock(&suspend_init_mutex); - return 1; + pthread_mutex_unlock(&PSD->suspend_init_mutex); + return result; } static int suspend_init_lock() @@ -391,16 +789,16 @@ static int suspend_init_lock() if (!suspend_init()) return 0; - if (pthread_mutex_lock(&g_suspend_mutex) != 0) + if (pthread_mutex_lock(&PSD->suspend_mutex) != 0) return 0; return 1; } -static os_thread_info_t* init_susres_list_item() +static port_thread_info_t* init_susres_list_item() { - os_thread_info_t* pinfo = - (os_thread_info_t*)malloc(sizeof(os_thread_info_t)); + port_thread_info_t* pinfo = + (port_thread_info_t*)malloc(sizeof(port_thread_info_t)); if (pinfo == NULL) return NULL; @@ -418,25 +816,25 @@ static os_thread_info_t* init_susres_list_item() return pinfo; } -static os_thread_info_t* suspend_add_thread(osthread_t thread) +static port_thread_info_t* suspend_add_thread(osthread_t thread) { - os_thread_info_t* pinfo = init_susres_list_item(); + port_thread_info_t* pinfo = init_susres_list_item(); if (pinfo == NULL) return NULL; pinfo->thread = thread; - pinfo->next = g_suspended_list; - g_suspended_list = pinfo; + pinfo->next = PSD->suspended_list; + PSD->suspended_list = pinfo; return pinfo; } static void suspend_remove_thread(osthread_t thread) { - os_thread_info_t** pprev = &g_suspended_list; - os_thread_info_t* pinfo; + port_thread_info_t** pprev = &PSD->suspended_list; + port_thread_info_t* pinfo; - for (pinfo = g_suspended_list; pinfo; pinfo = pinfo->next) + for (pinfo = PSD->suspended_list; pinfo; pinfo = pinfo->next) { if (pinfo->thread == thread) break; @@ -452,12 +850,12 @@ static void suspend_remove_thread(osthread_t thread) } } -static os_thread_info_t* suspend_find_thread(osthread_t thread) +static port_thread_info_t* suspend_find_thread(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; int status; - for (pinfo = g_suspended_list; pinfo; pinfo = pinfo->next) + for (pinfo = PSD->suspended_list; pinfo; pinfo = pinfo->next) { if (pinfo->thread == thread) break; @@ -470,31 +868,34 @@ static os_thread_info_t* suspend_find_thread(osthread_t thread) static void sigusr2_handler(int signum, siginfo_t* info, void* context) { int status; - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; - if (!suspend_init()) + if (!PSD) return; - if (signum != SIGUSR2) - return; - - /* We have g_suspend_mutex locked already */ + /* We have suspend_mutex locked already */ - if (g_req_type == THREADREQ_YIELD) + if (PSD->req_type == THREADREQ_YIELD) { - g_req_type = THREADREQ_NONE; + PSD->req_type = THREADREQ_NONE; /* Inform requester */ - sem_post(&g_yield_sem); + sem_post(&PSD->yield_sem); return; } - if ((pinfo = suspend_find_thread(g_suspendee)) == NULL) + if (PSD->req_type == THREADREQ_NONE) return; - if (g_req_type == THREADREQ_SUS) + if (!suspend_init() || + (pinfo = suspend_find_thread(PSD->suspendee)) == NULL) + { + return; /* Return to interrupted THREADREQ_SUS handler */ + } + + if (PSD->req_type == THREADREQ_SUS) { pinfo->suspend_count++; - g_req_type = THREADREQ_NONE; + PSD->req_type = THREADREQ_NONE; memcpy(&pinfo->context, context, sizeof(ucontext_t)); /* Inform suspender */ sem_post(&pinfo->wake_sem); @@ -513,10 +914,10 @@ static void sigusr2_handler(int signum, siginfo_t* info, void* context) sem_post(&pinfo->wake_sem); return; } - else if (g_req_type == THREADREQ_RES) + else if (PSD->req_type == THREADREQ_RES) { pinfo->suspend_count--; - g_req_type = THREADREQ_NONE; + PSD->req_type = THREADREQ_NONE; return; /* Return to interrupted THREADREQ_SUS handler */ } } diff --git a/vm/port/src/thread/win/port_thread_tls_os.c b/vm/port/src/thread/win/port_thread_tls_os.c new file mode 100644 index 0000000..7467f0f --- /dev/null +++ b/vm/port/src/thread/win/port_thread_tls_os.c @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "open/platform_types.h" +#include "open/hythread_ext.h" +#include "port_mutex.h" +#include "port_thread_internal.h" + + +static port_shared_data_t g_port_shared_data_struct; +volatile port_shared_data_t* port_shared_data = NULL; + + +#define MEM_PROTECT_SIZE 0x100 + +#ifdef _EM64T_ +#define GUARD_STACK_SIZE (64*1024) +#else /* IA-32 */ +#define GUARD_STACK_SIZE (find_guard_page_size()) +#endif + + +static size_t find_guard_page_size() +{ + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + return system_info.dwPageSize; +} + +static int init_psd_structure(port_shared_data_t* data) +{ + DWORD key; + + if ((key = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return -1; + + data->tls_key = key; + InitializeCriticalSection(&data->crit_section); + data->foreign_stack_size = 0; + data->guard_page_size = find_guard_page_size(); + data->guard_stack_size = GUARD_STACK_SIZE; + data->mem_protect_size = MEM_PROTECT_SIZE; + return 0; +} + +static void deinit_psd_structure(port_shared_data_t* data) +{ + TlsFree(data->tls_key); + DeleteCriticalSection(&data->crit_section); +} + +int init_port_shared_data() +{ + int err = 0; + char shmstring[25]; + HANDLE hMap; + volatile port_shared_data_t** pmem; + void* prev_shmdata; +static CRITICAL_SECTION struct_lock; +static int lock_initialized = 0; + + if (port_shared_data) + return 0; + + sprintf(shmstring, "portshmdata_%d", GetCurrentProcessId()); + + hMap = CreateFileMapping( + INVALID_HANDLE_VALUE, // use paging file + NULL, + PAGE_READWRITE, + 0, sizeof(void*), // size + shmstring); // name + if (hMap == NULL) + return -1; + + pmem = (volatile port_shared_data_t**)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); + + if (pmem == NULL) + return -1; + + if (*pmem) + { + port_shared_data = *pmem; + return 0; + } + + if (lock_initialized == 0) + { + InitializeCriticalSection(&struct_lock); + lock_initialized = 1; + } + + EnterCriticalSection(&struct_lock); + err = init_psd_structure(&g_port_shared_data_struct); + + if (err == 0) + { + prev_shmdata = InterlockedCompareExchangePointer(pmem, + &g_port_shared_data_struct, NULL); + + if (prev_shmdata == NULL) + port_shared_data = &g_port_shared_data_struct; + else /* another thread written the data */ + { + deinit_psd_structure(&g_port_shared_data_struct); + port_shared_data = (port_shared_data_t*)prev_shmdata; + } + } + + LeaveCriticalSection(&struct_lock); + return err; +} diff --git a/vm/port/src/thread/win/thread_os.c b/vm/port/src/thread/win/thread_os.c index a83c63b..58e83d9 100644 --- a/vm/port/src/thread/win/thread_os.c +++ b/vm/port/src/thread/win/thread_os.c @@ -16,39 +16,368 @@ */ -#include +#include "port_atomic.h" +#include "port_malloc.h" #include "port_thread.h" +#include "port_thread_internal.h" -typedef struct os_thread_info_t os_thread_info_t; +/* Forward declarations */ +static int suspend_init_lock(); +static port_thread_info_t* init_susres_list_item(); +static port_thread_info_t* suspend_add_thread(osthread_t thread); +static void suspend_remove_thread(osthread_t thread); +static port_thread_info_t* suspend_find_thread(osthread_t thread); + + +typedef unsigned (__stdcall *beginthread_func_t)(void*); -struct os_thread_info_t +typedef struct { - osthread_t thread; - int suspend_count; - thread_context_t context; + port_threadfunc_t fun; + void* arg; + size_t stack_size; +} thread_start_struct_t; - os_thread_info_t* next; -}; +static unsigned __stdcall thread_start_func(void* arg) +{ + int err, result; + port_tls_data_t* tlsdata; + thread_start_struct_t* ptr = (thread_start_struct_t*)arg; + port_threadfunc_t fun = ptr->fun; + size_t stack_size = ptr->stack_size; + arg = ptr->arg; + STD_FREE(ptr); + tlsdata = (port_tls_data_t*)STD_ALLOCA(sizeof(port_tls_data_t)); + err = port_thread_attach_local(tlsdata, FALSE, FALSE, stack_size); + assert(err == 0); -static CRITICAL_SECTION g_crit_section; -static os_thread_info_t* g_suspended_list = NULL; + result = (int)fun(arg); -/* Forward declarations */ -static int suspend_init_lock(); -static os_thread_info_t* init_susres_list_item(); -static os_thread_info_t* suspend_add_thread(osthread_t thread); -static void suspend_remove_thread(osthread_t thread); -static os_thread_info_t* suspend_find_thread(osthread_t thread); + port_thread_detach(); + + return result; +} -/** - * Terminates the os thread. - */ +int port_thread_create(/* out */osthread_t* phandle, size_t stacksize, int priority, + port_threadfunc_t func, void *data) +{ + uintptr_t handle; + thread_start_struct_t* startstr; + int res; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + if (!func) + return -1; + + startstr = + (thread_start_struct_t*)STD_MALLOC(sizeof(thread_start_struct_t)); + + if (!startstr) + return -1; + + startstr->fun = func; + startstr->arg = data; + startstr->stack_size = stacksize; + + handle = _beginthreadex(NULL, stacksize, thread_start_func, startstr, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL); + + if (handle != (uintptr_t)-1L) + { + *phandle = (HANDLE)handle; + + if (priority) + SetThreadPriority(*phandle, priority); + + return 0; + } + + STD_FREE(startstr); + return res; +} + +static int set_guard_page(port_tls_data_t* tlsdata, Boolean set) +{ + if (!tlsdata) + tlsdata = get_private_tls_data(); + + if (!tlsdata) + return -1; + + if (!tlsdata->guard_page_addr) + return 0; + + if ((set && tlsdata->guard_page_set) || + !set && !tlsdata->guard_page_set) + return 0; // Already in needed state + + if (set) + { + if ((size_t)&set - PSD->mem_protect_size + < (size_t)tlsdata->guard_page_addr + tlsdata->guard_page_size) + return -1; + + if (!VirtualAlloc(tlsdata->guard_page_addr, tlsdata->guard_page_size, + MEM_COMMIT, PAGE_GUARD | PAGE_READWRITE)) + // should be successful always + return -1; + } + else + { + DWORD oldProtect; + + if ((size_t)&set < (size_t)tlsdata->guard_page_addr + tlsdata->guard_page_size) + return -1; + + if (!VirtualProtect(tlsdata->guard_page_addr, tlsdata->guard_page_size, + PAGE_READWRITE, &oldProtect)) + // should be successful always + return -1; + } + + tlsdata->guard_page_set = set; + return 0; +} + +int port_thread_restore_guard_page() +{ + return set_guard_page(NULL, TRUE); +} + +int port_thread_clear_guard_page() +{ + return set_guard_page(NULL, FALSE); +} + +void port_thread_postpone_guard_page() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata || !tlsdata->guard_page_addr) + return; + + tlsdata->restore_guard_page = FALSE; +} + +void* port_thread_get_stack_address() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + return tlsdata ? tlsdata->stack_addr : NULL; +} + +size_t port_thread_get_stack_size() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + return tlsdata ? tlsdata->stack_size : 0; +} + +size_t port_thread_get_effective_stack_size() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata) + return 0; + + if (!tlsdata->guard_page_addr || !tlsdata->guard_page_set) + return tlsdata->stack_size + - PSD->guard_page_size - PSD->mem_protect_size; + + return tlsdata->stack_size - 2*PSD->guard_page_size + - PSD->guard_stack_size - PSD->mem_protect_size; +} + +static int setup_stack(port_tls_data_t* tlsdata) +{ +#ifdef _EM64T_ + ULONG guard_stack_size_param; +#endif + + if (!port_shared_data) + return -1; + +#ifdef _EM64T_ + /* this code in future should be used on both platforms x86-32 and x86-64 */ + guard_stack_size_param = (ULONG)PSD->guard_stack_size; + + if (!SetThreadStackGuarantee(&guard_stack_size_param)) + /* should be successful always */ + return -1; +#endif + + if ((size_t)&tlsdata - PSD->mem_protect_size + < (size_t)tlsdata->guard_page_addr + tlsdata->guard_page_size) + return -1; + + if (!VirtualFree(tlsdata->guard_stack_addr, + tlsdata->guard_stack_size, MEM_DECOMMIT)) + // should be successful always + return -1; + + return 0; +} + +static int find_stack_addr_size(void** paddr, size_t* psize) +{ + size_t reg_size; + MEMORY_BASIC_INFORMATION memory_information; + + VirtualQuery(&memory_information, &memory_information, sizeof(memory_information)); + reg_size = memory_information.RegionSize; + *paddr = (void*)((size_t)memory_information.BaseAddress + reg_size); + *psize = (size_t)*paddr - (size_t)memory_information.AllocationBase; + return 0; +} + +static int init_stack(port_tls_data_t* tlsdata, size_t stack_size, Boolean temp) +{ + int err; + size_t stack_begin; + + if (!port_shared_data) + return -1; + + err = find_stack_addr_size(&tlsdata->stack_addr, &tlsdata->stack_size); + if (err != 0) return err; + + if (stack_size) + tlsdata->stack_size = stack_size; + + tlsdata->guard_page_size = PSD->guard_page_size; + tlsdata->guard_stack_size = PSD->guard_stack_size; + tlsdata->mem_protect_size = PSD->mem_protect_size; + + if (temp) + return 0; + + stack_begin = (size_t)tlsdata->stack_addr - tlsdata->stack_size; + tlsdata->guard_stack_addr = (void*)(stack_begin + tlsdata->guard_page_size); + tlsdata->guard_page_addr = + (void*)((size_t)tlsdata->guard_stack_addr + tlsdata->guard_stack_size); + + return setup_stack(tlsdata); +} + +int port_thread_attach_local(port_tls_data_t* tlsdata, Boolean temp, + Boolean foreign, size_t stack_size) +{ + int res; + + memset(tlsdata, 0, sizeof(port_tls_data_t)); + + tlsdata->foreign = foreign; + res = init_stack(tlsdata, stack_size, temp); + if (res != 0) return res; + + res = set_private_tls_data(tlsdata); + + if (res != 0) + set_guard_page(tlsdata, FALSE); + + return res; +} + +int port_thread_attach() +{ + int res; + port_tls_data_t* tlsdata; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + if (get_private_tls_data()) + return 0; + + tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t)); + + if (!tlsdata) return ENOMEM; + + res = port_thread_attach_local(tlsdata, FALSE, TRUE, 0); + + if (res != 0) + STD_FREE(tlsdata); + + return res; +} + +int port_thread_detach_temporary() +{ + port_tls_data_t* tlsdata = get_private_tls_data(); + + if (!tlsdata || tlsdata->guard_page_addr) + return -1; + + return set_private_tls_data(NULL); +} + +int port_thread_detach() +{ + port_tls_data_t* tlsdata; + int res; + + if (!port_shared_data && (res = init_port_shared_data()) != 0) + return res; + + tlsdata = get_private_tls_data(); + + if (!tlsdata) + return 0; + + if (port_thread_detach_temporary() == 0) + return 0; + + if (tlsdata->foreign) + STD_FREE(tlsdata); + + return set_private_tls_data(NULL); +} + +int port_thread_set_priority(osthread_t os_thread, int priority) +{ + if (SetThreadPriority(os_thread, (int)priority)) { + return 0; + } else { + return GetLastError(); + } +} + +osthread_t port_thread_current() +{ + HANDLE hproc = GetCurrentProcess(); + HANDLE hthread = GetCurrentThread(); + if (!DuplicateHandle(hproc, hthread, + hproc, &hthread, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + return NULL; + } + return hthread; +} + +int port_thread_free_handle(osthread_t os_thread) +{ + BOOL r = CloseHandle(os_thread); + return !r; +} + +int port_thread_join(osthread_t os_thread) +{ + int error = 0; + DWORD r; + r = WaitForSingleObject(os_thread, INFINITE); + if (r == WAIT_OBJECT_0 || r == WAIT_ABANDONED) + r = 0; + else + r = GetLastError(); + CloseHandle(os_thread); + return r; +} + int port_thread_cancel(osthread_t os_thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; int status = TM_ERROR_NONE; if (!suspend_init_lock()) @@ -62,17 +391,42 @@ int port_thread_cancel(osthread_t os_thread) if (!TerminateThread(os_thread, 0)) status = (int)GetLastError(); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return status; } -/** - * Causes the other thread to have a memory barrier by suspending - * and resuming it. - */ +void port_thread_exit(int status) +{ + ExitThread(status); +} + +int port_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser) +{ + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + int r; + + r = GetThreadTimes(os_thread, + &creation_time, &exit_time, &kernel_time, &user_time); + + if (r) { + // according to MSDN, time is counted in 100 ns units, so we need to multiply by 100 + *pkernel = 100 * + (((int64)kernel_time.dwHighDateTime << 32) + | kernel_time.dwLowDateTime); + *puser = 100 * + (((int64)user_time.dwHighDateTime << 32) + | user_time.dwLowDateTime); + return 0; + } else + return GetLastError(); +} + void port_thread_yield_other(osthread_t os_thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; /* * Synchronization is needed to avoid cyclic (mutual) suspension problem. @@ -85,7 +439,7 @@ void port_thread_yield_other(osthread_t os_thread) pinfo = suspend_find_thread(os_thread); if (pinfo && pinfo->suspend_count > 0) { - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return; } @@ -94,17 +448,13 @@ void port_thread_yield_other(osthread_t os_thread) ResumeThread(os_thread); } - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); } -/** - * Suspend given thread - * @param thread The thread to suspend - */ int port_thread_suspend(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; DWORD old_count; if (!thread) @@ -120,14 +470,14 @@ int port_thread_suspend(osthread_t thread) if (!pinfo) { - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_OUT_OF_MEMORY; } if (pinfo->suspend_count > 0) { ++pinfo->suspend_count; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } @@ -136,22 +486,18 @@ int port_thread_suspend(osthread_t thread) if (old_count == (DWORD)-1) { int status = (int)GetLastError(); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return status; } ++pinfo->suspend_count; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } -/** - * Resume given thread - * @param thread The thread to resume - */ int port_thread_resume(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; DWORD old_count; if (!thread) @@ -164,14 +510,14 @@ int port_thread_resume(osthread_t thread) if (!pinfo) { - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_UNATTACHED_THREAD; } if (pinfo->suspend_count > 1) { --pinfo->suspend_count; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } @@ -180,25 +526,20 @@ int port_thread_resume(osthread_t thread) if (old_count == (DWORD)-1) { int status = (int)GetLastError(); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return status; } if (--pinfo->suspend_count == 0) suspend_remove_thread(thread); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } -/** - * Determine suspend count for the given thread - * @param thread The thread to check - * @return -1 if error have occured - */ int port_thread_get_suspend_count(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; int suspend_count; if (!thread) @@ -210,19 +551,13 @@ int port_thread_get_suspend_count(osthread_t thread) pinfo = suspend_find_thread(thread); suspend_count = pinfo ? pinfo->suspend_count : 0; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return suspend_count; } -/** - * Get context for given thread - * @param thread The thread to process - * @param context Pointer to platform-dependant context structure - * @note The thread must be suspended - */ int port_thread_get_context(osthread_t thread, thread_context_t *context) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; CONTEXT local_context; if (!thread || !context) @@ -235,7 +570,7 @@ int port_thread_get_context(osthread_t thread, thread_context_t *context) if (!pinfo) { - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_UNATTACHED_THREAD; } @@ -248,25 +583,19 @@ int port_thread_get_context(osthread_t thread, thread_context_t *context) if (!GetThreadContext(thread, &local_context)) { int status = (int)GetLastError(); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return status; } pinfo->context = local_context; *context = local_context; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } -/** - * Set context for given thread - * @param thread The thread to process - * @param context Pointer to platform-dependant context structure - * @note The thread must be suspended - */ int port_thread_set_context(osthread_t thread, thread_context_t *context) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; if (!thread || !context) return -1; @@ -278,19 +607,19 @@ int port_thread_set_context(osthread_t thread, thread_context_t *context) if (!pinfo) { - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_UNATTACHED_THREAD; } if (!SetThreadContext(thread, context)) { int status = (int)GetLastError(); - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return status; } pinfo->context = *context; - LeaveCriticalSection(&g_crit_section); + LeaveCriticalSection(&PSD->crit_section); return TM_ERROR_NONE; } @@ -304,17 +633,17 @@ static int suspend_init_lock() // Critical section should be initialized only once, // do nothing in case someone else already initialized it. if (port_atomic_cas16((volatile uint16*)&initialized, 1, 0) == 0) - InitializeCriticalSectionAndSpinCount(&g_crit_section, 400); + InitializeCriticalSectionAndSpinCount(&PSD->crit_section, 400); } - EnterCriticalSection(&g_crit_section); + EnterCriticalSection(&PSD->crit_section); return 1; } -static os_thread_info_t* init_susres_list_item() +static port_thread_info_t* init_susres_list_item() { - os_thread_info_t* pinfo = - (os_thread_info_t*)malloc(sizeof(os_thread_info_t)); + port_thread_info_t* pinfo = + (port_thread_info_t*)malloc(sizeof(port_thread_info_t)); if (pinfo) pinfo->suspend_count = 0; @@ -322,26 +651,26 @@ static os_thread_info_t* init_susres_list_item() return pinfo; } -static os_thread_info_t* suspend_add_thread(osthread_t thread) +static port_thread_info_t* suspend_add_thread(osthread_t thread) { - os_thread_info_t* pinfo = init_susres_list_item(); + port_thread_info_t* pinfo = init_susres_list_item(); if (!pinfo) return NULL; pinfo->thread = thread; - pinfo->next = g_suspended_list; - g_suspended_list = pinfo; + pinfo->next = PSD->suspended_list; + PSD->suspended_list = pinfo; return pinfo; } static void suspend_remove_thread(osthread_t thread) { - os_thread_info_t** pprev = &g_suspended_list; - os_thread_info_t* pinfo; + port_thread_info_t** pprev = &PSD->suspended_list; + port_thread_info_t* pinfo; - for (pinfo = g_suspended_list; pinfo; pinfo = pinfo->next) + for (pinfo = PSD->suspended_list; pinfo; pinfo = pinfo->next) { if (pinfo->thread == thread) break; @@ -356,11 +685,11 @@ static void suspend_remove_thread(osthread_t thread) } } -static os_thread_info_t* suspend_find_thread(osthread_t thread) +static port_thread_info_t* suspend_find_thread(osthread_t thread) { - os_thread_info_t* pinfo; + port_thread_info_t* pinfo; - for (pinfo = g_suspended_list; pinfo; pinfo = pinfo->next) + for (pinfo = PSD->suspended_list; pinfo; pinfo = pinfo->next) { if (pinfo->thread == thread) break; diff --git a/vm/thread/src/hythr.def b/vm/thread/src/hythr.def index f024626..ae219a9 100644 --- a/vm/thread/src/hythr.def +++ b/vm/thread/src/hythr.def @@ -53,7 +53,6 @@ hythread_get_self_id hythread_get_id hythread_get_thread hythread_get_thread_times -hythread_get_thread_stacksize hythread_struct_init hythread_cancel_all hythread_group_create diff --git a/vm/thread/src/hythr.exp b/vm/thread/src/hythr.exp index ccfb158..66980be 100644 --- a/vm/thread/src/hythr.exp +++ b/vm/thread/src/hythr.exp @@ -39,7 +39,6 @@ hythread_monitor_wait_timed; hythread_resume; hythread_monitor_notify; hythread_get_priority; -hythread_get_thread_stacksize; hythread_tls_get; hythread_tls_get_request_offset; hythread_get_hythread_offset_in_tls; diff --git a/vm/thread/src/linux/os_thread.c b/vm/thread/src/linux/os_thread.c deleted file mode 100644 index e79b1ba..0000000 --- a/vm/thread/src/linux/os_thread.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include // sched_param -#include -#include -#include -#include - -#include "port_thread.h" -#include "thread_private.h" - - -/** - * Creates new thread. - * - * @param[out] handle on success, thread handle is stored in memory pointed by handle - * @param stacksize size of stack to be allocated for a new thread - * @param priority priority of a new thread - * @param func function to be started on a new thread - * @param data value to be passed to a function started on a new thread - * - * @return 0 on success, TM_ERROR_OUT_OF_MEMORY if system is thread cannot be created because - * of insufficient memory, system error otherwise. - */ -int os_thread_create(/* out */osthread_t* phandle, UDATA stacksize, UDATA priority, - hythread_wrapper_t func, void *data) -{ - pthread_t thread; - pthread_attr_t attr; - int r; - - pthread_attr_init(&attr); - // By default, threads are created in joinable state. - // Since we never use os_thread_join except for canceling a thread, - // we can create threads in detached state instead. - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if (stacksize != 0) { - r = pthread_attr_setstacksize(&attr, stacksize); - if (r) { - pthread_attr_destroy(&attr); - return r; - } - } - - r = pthread_create(&thread, &attr, (void*(*)(void*))func, data); - - pthread_attr_destroy(&attr); - - if (r == 0) { - *phandle = thread; - // priority is set from within the thread context - return 0; - } else { - if (r == EAGAIN || r == ENOMEM) { - // EAGAIN may be returned if PTHREAD_THREADS_MAX limit is exceeded - return TM_ERROR_OUT_OF_MEMORY; - } - return r; - } -} - -/** - * Adjusts priority of the running thread. - * - * @param thread handle of thread - * @param priority new priority value - * - * @return 0 on success, system error otherwise - */ -int os_thread_set_priority(osthread_t os_thread, int priority) -{ -#if defined(FREEBSD) - /* Not sure why we don't just use this on linux? - MRH */ - struct sched_param param; - int policy; - int r = pthread_getschedparam(os_thread, &policy, ¶m); - if (r == 0) { - param.sched_priority = priority; - r = pthread_setschedparam(os_thread, policy, ¶m); - } - return r; -#else - // setting thread priority on linux is only supported for current thread - if (os_thread == pthread_self()) { - int r; - struct sched_param param; - pid_t self = gettid(); - param.sched_priority = priority; - r = sched_setparam(self, ¶m); - return r ? errno : 0; - } else { - // setting other thread priority not supported on linux - return 0; - } -#endif -} - -/** - * Returns os handle of the current thread. - * - * @return current thread handle on success, NULL on error - */ -osthread_t os_thread_current() -{ - return pthread_self(); -} - -/** - * Not used on Linux - * - * @param os_thread thread handle - * - * @return 0 on success, systerm error otherwise - */ -int os_thread_free(osthread_t os_thread) -{ - return 0; -} - -/** - * Joins the os thread. - * - * @param os_thread thread handle - * - * @return 0 on success, systerm error otherwise - */ -int os_thread_join(osthread_t os_thread) -{ - int error; - - do { - // FIXME - somehow pthread_join returns before thread is terminated - error = pthread_join(os_thread, NULL); - } while (error != ESRCH && error != EINVAL && error != EDEADLK); - return 0; -} - -/** - * Causes the current thread to stop execution. - * - * @param status returns status of a thread - */ -void os_thread_exit(IDATA status) -{ - pthread_exit((void*)status); -} - -/** - * Queries amount of user and kernel times consumed by the thread, - * in nanoseconds. - * - * @param os_thread thread handle - * @param[out] pkernel a pointer to a variable to store kernel time to - * @param[out] puser a pointer to a variable to store user time to - * - * @return 0 on success, system error otherwise - */ -int os_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser) -{ - clockid_t clock_id; - struct timespec tp; - int r; -#ifdef FREEBSD - return EINVAL; /* TOFIX: Implement */ -#else - - r = pthread_getcpuclockid(os_thread, &clock_id); - if (r) return r; - - r = clock_gettime(clock_id, &tp); - if (r) return r; - - *puser = tp.tv_sec * 1000000000ULL + tp.tv_nsec; - return 0; -#endif -} - -UDATA os_get_foreign_thread_stack_size() { - int err; - void* stack_addr; - pthread_attr_t pthread_attr; - size_t stack_size; - - static UDATA common_stack_size = -1; - - if (common_stack_size == -1) { - pthread_attr_init(&pthread_attr); - err = pthread_attr_getstacksize(&pthread_attr, &common_stack_size); - pthread_attr_destroy(&pthread_attr); - } - - return common_stack_size; - -} diff --git a/vm/thread/src/thread_native_attrs.c b/vm/thread/src/thread_native_attrs.c index 03dead3..bf911f5 100644 --- a/vm/thread/src/thread_native_attrs.c +++ b/vm/thread/src/thread_native_attrs.c @@ -38,7 +38,7 @@ * @returns 0 on success or negative value on failure (priority wasn't changed) */ IDATA VMCALL hythread_set_priority(hythread_t thread, UDATA priority) { - int r = os_thread_set_priority(thread->os_handle, priority); + int r = port_thread_set_priority(thread->os_handle, priority); if (r) return r; thread->priority = priority; return 0; diff --git a/vm/thread/src/thread_native_basic.c b/vm/thread/src/thread_native_basic.c index ed2d4d2..941d431 100644 --- a/vm/thread/src/thread_native_basic.c +++ b/vm/thread/src/thread_native_basic.c @@ -87,7 +87,6 @@ IDATA VMCALL hythread_create_ex(hythread_t new_thread, self = hythread_self(); new_thread->library = self ? self->library : TM_LIBRARY; new_thread->priority = priority ? priority : HYTHREAD_PRIORITY_NORMAL; - new_thread->stacksize = stacksize ? stacksize : TM_DEFAULT_STACKSIZE; if (!wrapper) { hythread_start_proc_data_t start_proc_data; @@ -112,9 +111,10 @@ IDATA VMCALL hythread_create_ex(hythread_t new_thread, } // Need to make sure thread will not register itself with a thread group - // until os_thread_create returned and initialized thread->os_handle properly. + // until port_thread_create returned and initialized thread->os_handle properly. hythread_global_lock(); - result = os_thread_create(&new_thread->os_handle, new_thread->stacksize, + result = port_thread_create(&new_thread->os_handle, + stacksize ? stacksize : TM_DEFAULT_STACKSIZE, priority, wrapper, data); assert(/* error */ result || new_thread->os_handle /* or thread created ok */); hythread_global_unlock(); @@ -166,6 +166,7 @@ IDATA hythread_attach_ex(hythread_t new_thread, hythread_library_t lib, hythread_group_t group) { + int res; IDATA status; hythread_t self = hythread_self(); @@ -176,13 +177,16 @@ IDATA hythread_attach_ex(hythread_t new_thread, new_thread->library = TM_LIBRARY; if (self) { - // to avoid creating multiple OS handle + // to avoid creating multiple OS handles new_thread->os_handle = self->os_handle; } else { - new_thread->os_handle = os_thread_current(); + new_thread->os_handle = port_thread_current(); } assert(new_thread->os_handle); + res = port_thread_attach(); + assert(res == 0); + CTRACE(("TM: native attached: native: %p ", new_thread)); status = hythread_set_to_group(new_thread, @@ -277,6 +281,9 @@ void VMCALL hythread_detach_ex(hythread_t thread) // Detach if thread is attached to group. hythread_remove_from_group(thread); + if (thread == hythread_self()) // Detach current thread only + port_thread_detach(); + // FIXME - uncomment after TM state transition complete // release thread data //hythread_struct_release(thread); @@ -525,7 +532,7 @@ void VMCALL hythread_cancel(hythread_t thread) { osthread_t os_handle = thread->os_handle; hythread_detach(thread); port_thread_cancel(os_handle); - os_thread_join(os_handle); + port_thread_join(os_handle); } /** @@ -679,7 +686,7 @@ IDATA VMCALL hythread_struct_init(hythread_t new_thread) hythread_monitor_t monitor; // release thread OS handle - result = os_thread_free(new_thread->os_handle); + result = port_thread_free_handle(new_thread->os_handle); assert(0 == result); resume = new_thread->resume_event; @@ -697,7 +704,6 @@ IDATA VMCALL hythread_struct_init(hythread_t new_thread) new_thread->java_status = jstatus; new_thread->priority = HYTHREAD_PRIORITY_NORMAL; - new_thread->stacksize = os_get_foreign_thread_stack_size(); port_mutex_lock(&new_thread->mutex); new_thread->state = TM_THREAD_STATE_NEW; @@ -754,7 +760,7 @@ static int HYTHREAD_PROC hythread_wrapper_start_proc(void *arg) { start_proc = start_proc_data.proc; CTRACE(("TM: native thread started: native: %p tm: %p", - apr_os_thread_current(), thread)); + port_thread_current(), thread)); // check hythread library state if (hythread_lib_state() != TM_LIBRARY_STATUS_INITIALIZED) { @@ -774,7 +780,7 @@ static int HYTHREAD_PROC hythread_wrapper_start_proc(void *arg) { hythread_set_self(NULL); CTRACE(("TM: native thread terminated due to shutdown: native: %p tm: %p", - apr_os_thread_current(), thread)); + port_thread_current(), thread)); // release hythread global lock status = hythread_global_unlock(); @@ -832,7 +838,7 @@ hythread_exit (hythread_monitor_t monitor) { hythread_monitor_exit(monitor); } hythread_detach_ex(NULL); - os_thread_exit(0); + port_thread_exit(0); // unreachable statement abort(); } @@ -847,14 +853,10 @@ hythread_exit (hythread_monitor_t monitor) { * @returns 0 on success, system error code otherwise */ UDATA hythread_get_thread_times(hythread_t thread, int64* pkernel, int64* puser) { - return os_get_thread_times(thread->os_handle, pkernel, puser); + return port_get_thread_times(thread->os_handle, pkernel, puser); } -UDATA hythread_get_thread_stacksize(hythread_t thread) { - return thread->stacksize; -} - IDATA VMCALL hythread_thread_lock(hythread_t thread) { assert(thread); return port_mutex_lock(&thread->mutex); diff --git a/vm/thread/src/thread_private.h b/vm/thread/src/thread_private.h index 5090c4c..ff3c6a5 100644 --- a/vm/thread/src/thread_private.h +++ b/vm/thread/src/thread_private.h @@ -304,17 +304,7 @@ IDATA sem_wait_impl(hysem_t sem, I_64 ms, IDATA nano, IDATA interruptable); /* * portability functions, private for thread module */ -int os_thread_create(osthread_t* phandle, UDATA stacksize, UDATA priority, - hythread_wrapper_t func, void *data); -int os_thread_set_priority(osthread_t thread, int priority); -osthread_t os_thread_current(); -int os_thread_free(osthread_t os_thread); -void os_thread_exit(IDATA status); -int os_thread_join(osthread_t os_thread); -int os_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser); - int os_cond_timedwait(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano); -UDATA os_get_foreign_thread_stack_size(); #ifdef __cplusplus diff --git a/vm/thread/src/win/os_thread.c b/vm/thread/src/win/os_thread.c deleted file mode 100644 index 5009b8c..0000000 --- a/vm/thread/src/win/os_thread.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -# -#include "thread_private.h" - -/** - * Creates new thread. - * - * @param[out] handle on success, thread handle is stored in memory pointed by handle - * @param stacksize size of stack to be allocated for a new thread - * @param priority priority of a new thread - * @param func function to be started on a new thread - * @param data value to be passed to a function started on a new thread - * - * @return 0 on success, TM_ERROR_OUT_OF_MEMORY if system is thread cannot be created because - * of insufficient memory, system error otherwise. - */ -int os_thread_create(/* out */osthread_t* phandle, UDATA stacksize, UDATA priority, - hythread_wrapper_t func, void *data) -{ - HANDLE handle = (HANDLE)_beginthreadex(NULL, stacksize, (unsigned(__stdcall *)(void*))func, data, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL); - - if (handle) { - *phandle = handle; - if (priority) - SetThreadPriority(handle, priority); - return 0; - } else { - int error = GetLastError(); - if (error == ERROR_OUTOFMEMORY) - return TM_ERROR_OUT_OF_MEMORY; - return error; - } -} - -/** - * Adjusts priority of the running thread. - * - * @param thread handle of thread - * @param priority new priority value - * - * @return 0 on success, system error otherwise - */ -int os_thread_set_priority(osthread_t os_thread, int priority) -{ - if (SetThreadPriority(os_thread, (int)priority)) { - return 0; - } else { - return GetLastError(); - } -} - -/** - * Returns os handle of the current thread. - * - * @return current thread handle on success, NULL on error - */ -osthread_t os_thread_current() -{ - HANDLE hproc = GetCurrentProcess(); - HANDLE hthread = GetCurrentThread(); - if (!DuplicateHandle(hproc, hthread, - hproc, &hthread, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - return NULL; - } - return hthread; -} - -/** - * Free native thread handle - * - * @param os_thread thread handle - * - * @return 0 on success, systerm error otherwise - */ -int os_thread_free(osthread_t os_thread) -{ - BOOL r = CloseHandle(os_thread); - return !r; -} - -/** - * Joins the os thread. - * - * @param os_thread thread handle - * - * @return 0 on success, systerm error otherwise - */ -int os_thread_join(osthread_t os_thread) -{ - int error = 0; - DWORD r; - r = WaitForSingleObject(os_thread, INFINITE); - if (r == WAIT_OBJECT_0 || r == WAIT_ABANDONED) - r = 0; - else - r = GetLastError(); - CloseHandle(os_thread); - return r; -} - -/** - * Causes the current thread to stop execution. - * - * @param status returns status of a thread - */ -void os_thread_exit(IDATA status) -{ - ExitThread(status); -} - -/** - * Queries amount of user and kernel times consumed by the thread, - * in nanoseconds. - * - * @param os_thread thread handle - * @param[out] pkernel a pointer to a variable to store kernel time to - * @param[out] puser a pointer to a variable to store user time to - * - * @return 0 on success, system error otherwise - */ -int os_get_thread_times(osthread_t os_thread, int64* pkernel, int64* puser) -{ - FILETIME creation_time; - FILETIME exit_time; - FILETIME kernel_time; - FILETIME user_time; - int r; - - r = GetThreadTimes(os_thread, - &creation_time, &exit_time, &kernel_time, &user_time); - - if (r) { - // according to MSDN, time is counted in 100 ns units, so we need to multiply by 100 - *pkernel = 100 * - (((int64)kernel_time.dwHighDateTime << 32) - | kernel_time.dwLowDateTime); - *puser = 100 * - (((int64)user_time.dwHighDateTime << 32) - | user_time.dwLowDateTime); - return 0; - } else - return GetLastError(); -} - -UDATA os_get_foreign_thread_stack_size() { - void* stack_addr; - size_t stack_size; - size_t reg_size; - MEMORY_BASIC_INFORMATION memory_information; - - VirtualQuery(&memory_information, &memory_information, sizeof(memory_information)); - reg_size = memory_information.RegionSize; - stack_addr = ((char*) memory_information.BaseAddress) + reg_size; - stack_size = ((char*) stack_addr) - ((char*) memory_information.AllocationBase); - - return (UDATA)stack_size; -} - diff --git a/vm/vmcore/include/exceptions.h b/vm/vmcore/include/exceptions.h index 5da1a65..c68cf45 100644 --- a/vm/vmcore/include/exceptions.h +++ b/vm/vmcore/include/exceptions.h @@ -269,10 +269,7 @@ void print_uncaught_exception_message(FILE *f, char* context_message, jthrowable void exn_rethrow(); void exn_rethrow_if_pending(); -bool set_guard_stack(); typedef struct VM_thread * vm_thread_t; -void remove_guard_stack(vm_thread_t vm_thread); -void init_stack_info(); void* get_exception_catch_stack_addr(void* curr_ip); VMEXPORT size_t get_available_stack_size(); VMEXPORT bool check_available_stack_size(size_t required_size); diff --git a/vm/vmcore/src/exception/exceptions.cpp b/vm/vmcore/src/exception/exceptions.cpp index 70862fa..988330a 100644 --- a/vm/vmcore/src/exception/exceptions.cpp +++ b/vm/vmcore/src/exception/exceptions.cpp @@ -35,6 +35,7 @@ #include "object_handles.h" #include "vm_arrays.h" #include "vm_strings.h" +#include "port_thread.h" #include "cci.h" #include "ExpandableMemBlock.h" @@ -120,15 +121,17 @@ void exn_clear() clear_exception_internal(); tmn_suspend_enable_recursive(); - // if quard stack should be restored - restores it + // This will restore quard stack if needed if (p_TLS_vmthread->restore_guard_page) { - bool result = set_guard_stack(); + int res = port_thread_restore_guard_page(); // if guard stack can't be restored raise SOE - if (result == false) { + if (res != 0) { Global_Env *env = VM_Global_State::loader_env; exn_raise_by_class(env->java_lang_StackOverflowError_Class); } + + p_TLS_vmthread->restore_guard_page = false; } } diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp index dff6ddf..852d2d7 100644 --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -652,16 +652,16 @@ void exception_catch_callback() { // si_create_from_registers uses large stack space, // so guard page restored after its invoke. if (p_TLS_vmthread->restore_guard_page) { - bool result = set_guard_stack(); + int res = port_thread_restore_guard_page(); - if (result == false) { + if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); - if ((interpreter_enabled() || (!prev_m2n) - || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { + if ((interpreter_enabled() || (!prev_m2n) || + (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); @@ -672,6 +672,8 @@ void exception_catch_callback() { exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } + + p_TLS_vmthread->restore_guard_page = false; } si_transfer_control(si); @@ -699,16 +701,16 @@ void jvmti_exception_catch_callback() { // but befor ti agent callback invokation, // because it should work on protected page. if (p_TLS_vmthread->restore_guard_page) { - bool result = set_guard_stack(); + int res = port_thread_restore_guard_page(); - if (result == false) { + if (res != 0) { Global_Env *env = VM_Global_State::loader_env; if (si_is_native(si)) { m2n_set_last_frame(prev_m2n); - if ((interpreter_enabled() || (!prev_m2n) - || (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { + if ((interpreter_enabled() || (!prev_m2n) || + (m2n_get_frame_type(prev_m2n) & FRAME_NON_UNWINDABLE))) { exn_raise_by_class(env->java_lang_StackOverflowError_Class); } else { //si_free(si); @@ -719,6 +721,8 @@ void jvmti_exception_catch_callback() { exn_throw_by_class(env->java_lang_StackOverflowError_Class); } } + + p_TLS_vmthread->restore_guard_page = false; } if (!si_is_native(si)) @@ -732,6 +736,7 @@ void jvmti_exception_catch_callback() { *exn_obj = jvmti_jit_exception_catch_event_callback_call( *exn_obj, catch_method_jit, catch_method, catch_method_location); } + si_transfer_control(si); } diff --git a/vm/vmcore/src/thread/thread_generic.cpp b/vm/vmcore/src/thread/thread_generic.cpp index dc80afa..2b0aec4 100644 --- a/vm/vmcore/src/thread/thread_generic.cpp +++ b/vm/vmcore/src/thread/thread_generic.cpp @@ -189,8 +189,6 @@ jint vm_attach(JavaVM * java_vm, JNIEnv ** p_jni_env) jni_env->reserved0 = (void *) 0x1234abcd; *p_jni_env = jni_env; - init_stack_info(); - m2n_null_init(p_m2n); m2n_set_last_frame(p_m2n); @@ -248,11 +246,6 @@ jint vm_detach(jobject java_thread) gc_thread_kill(&p_vm_thread->_gc_private_information); } -#ifdef PLATFORM_POSIX - // Remove guard page on the stack on linux - remove_guard_stack(p_vm_thread); -#endif // PLATFORM_POSIX - if (ti_is_enabled()) { apr_status_t UNREF status; diff --git a/vm/vmcore/src/thread/thread_java_basic.cpp b/vm/vmcore/src/thread/thread_java_basic.cpp index 54ed343..d2cc4e2 100644 --- a/vm/vmcore/src/thread/thread_java_basic.cpp +++ b/vm/vmcore/src/thread/thread_java_basic.cpp @@ -26,6 +26,7 @@ #include "open/vm_properties.h" #include "jthread.h" #include "vm_threads.h" +#include "port_thread.h" #include "jni.h" static jmethodID jthread_get_run_method(JNIEnv * env, jthread java_thread); @@ -86,7 +87,7 @@ int HYTHREAD_PROC jthread_wrapper_start_proc(void *arg) hythread_set_self(NULL); CTRACE(("TM: native thread terminated due to shutdown: native: %p tm: %p", - apr_os_thread_current(), native_thread)); + port_thread_current(), native_thread)); // FIXME - uncomment after TM state transition complete //STD_FREE(native_thread); @@ -127,7 +128,7 @@ int HYTHREAD_PROC jthread_wrapper_start_proc(void *arg) vm_thread->daemon = start_proc_data.daemon; CTRACE(("TM: Java thread started: id=%d OS_handle=%p", - hythread_get_id(native_thread), apr_os_thread_current())); + hythread_get_id(native_thread), port_thread_current())); if (!vm_thread->daemon) { status = hythread_increase_nondaemon_threads_count(native_thread); @@ -179,7 +180,7 @@ int HYTHREAD_PROC jthread_wrapper_start_proc(void *arg) assert(status == TM_ERROR_NONE); CTRACE(("TM: Java thread finished: id=%d OS_handle=%p", - hythread_get_id(native_thread), apr_os_thread_current())); + hythread_get_id(native_thread), port_thread_current())); hythread_detach_ex(native_thread); diff --git a/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp b/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp deleted file mode 100644 index eddd9bf..0000000 --- a/vm/vmcore/src/util/linux/ia32_em64t/signals_common.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#undef __USE_XOPEN -#include - -#include -#if defined(FREEBSD) -#include -#endif -#include - -#define LOG_DOMAIN "signals" -#include "cxxlog.h" -#include "open/platform_types.h" -#include "Class.h" -#include "interpreter.h" -#include "environment.h" -#include "exceptions.h" -#include "exceptions_jit.h" -#include "signals_common.h" -#include "signals.h" - - -/* - * Information about stack - */ -inline void* find_stack_addr() { - int err; - void* stack_addr; - pthread_attr_t pthread_attr; - size_t stack_size; - - pthread_t thread = pthread_self(); - err = pthread_attr_init(&pthread_attr); - assert(!err); -#if defined(FREEBSD) - err = pthread_attr_get_np(thread, &pthread_attr); -#else - err = pthread_getattr_np(thread, &pthread_attr); -#endif - assert(!err); - err = pthread_attr_getstack(&pthread_attr, &stack_addr, &stack_size); - assert(!err); - pthread_attr_destroy(&pthread_attr); - - return (void *)((unsigned char *)stack_addr + stack_size); -} - -#if 0 -inline size_t find_stack_size() { - int err; - size_t stack_size; - pthread_attr_t pthread_attr; - - pthread_attr_init(&pthread_attr); - err = pthread_attr_getstacksize(&pthread_attr, &stack_size); - pthread_attr_destroy(&pthread_attr); - return stack_size; -} -#endif - -static inline size_t find_guard_stack_size() { - return 64*1024; -} - -static inline size_t find_guard_page_size() { - int err; - size_t guard_size; - pthread_attr_t pthread_attr; - - pthread_attr_init(&pthread_attr); - err = pthread_attr_getguardsize(&pthread_attr, &guard_size); - pthread_attr_destroy(&pthread_attr); - - return guard_size; -} - -static size_t common_guard_stack_size; -static size_t common_guard_page_size; - -static inline void* get_stack_addr() { - return jthread_self_vm_thread_unsafe()->stack_addr; -} - -static inline size_t get_stack_size() { - return jthread_self_vm_thread_unsafe()->stack_size; -} - -static inline size_t get_guard_stack_size() { - return common_guard_stack_size; -} - -static inline size_t get_guard_page_size() { - return common_guard_page_size; -} - -#ifdef _IA32_ -static void __attribute__ ((cdecl)) stack_holder(char* addr) { - char buf[1024]; - - if (addr > (buf + ((size_t)1024))) { - return; - } - stack_holder(addr); -} -#endif - -void init_stack_info() { - vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); - - // find stack parametrs - char* stack_addr = (char *)find_stack_addr(); - vm_thread->stack_addr = stack_addr; - size_t stack_size = hythread_get_thread_stacksize(hythread_self()); - assert(stack_size > 0); - - vm_thread->stack_size = stack_size; - - common_guard_stack_size = find_guard_stack_size(); - common_guard_page_size = find_guard_page_size(); - - // stack should be mapped so it's result of future mapping - char* res; - // begin of the stack can be protected by OS, but this part already mapped - // found address of current stack page - char* current_page_addr = - (char*)(((size_t)&res) & (~(common_guard_page_size-1))); - - // leave place for mmap work - char* mapping_page_addr = current_page_addr - common_guard_page_size; - -#ifdef _IA32_ - // makes sure that stack allocated till mapping_page_addr - stack_holder(mapping_page_addr); -#endif - - // found size of the stack area which should be maped - size_t stack_mapping_size = (size_t)mapping_page_addr - - (size_t)stack_addr + stack_size; - - // maps unmapped part of the stack - res = (char*) mmap(stack_addr - stack_size, stack_mapping_size, - PROT_READ | PROT_WRITE | PROT_EXEC, STACK_MMAP_ATTRS, -1, 0); - - // stack should be mapped, checks result - assert(res == (stack_addr - stack_size)); - - // set guard page - set_guard_stack(); -} - -bool set_guard_stack() { - int err; - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - if (((size_t)(&stack_addr) - get_mem_protect_stack_size()) - < ((size_t)((char*)stack_addr - stack_size - + guard_stack_size + 2 * guard_page_size))) { - return false; - } - - err = mprotect(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_NONE ); - - assert(!err); - - // sets alternative, guard stack - stack_t sigalt; - sigalt.ss_sp = stack_addr - stack_size + guard_page_size; -#if defined(FREEBSD) - sigalt.ss_flags = 0; -#else - sigalt.ss_flags = SS_ONSTACK; -#endif - sigalt.ss_size = guard_stack_size; - err = sigaltstack (&sigalt, NULL); - - assert(!err); - - // notify that stack is OK and there are no needs to restore it - jthread_self_vm_thread_unsafe()->restore_guard_page = false; - - return true; -} - -size_t get_available_stack_size() { - char* stack_addr = (char*) get_stack_addr(); - size_t used_stack_size = stack_addr - ((char*)&stack_addr); - size_t available_stack_size; - - if (!(p_TLS_vmthread->restore_guard_page)) { - available_stack_size = get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - } else { - available_stack_size = get_stack_size() - used_stack_size - get_guard_page_size(); - } - - if (available_stack_size > 0) { - return (size_t) available_stack_size; - } - - return 0; -} - -bool check_available_stack_size(size_t required_size) { - size_t available_stack_size = get_available_stack_size(); - - if (available_stack_size < required_size) { - if (available_stack_size < get_guard_stack_size()) { - remove_guard_stack(p_TLS_vmthread); - } - Global_Env *env = VM_Global_State::loader_env; - exn_raise_by_class(env->java_lang_StackOverflowError_Class); - return false; - } else { - return true; - } -} - -bool check_stack_size_enough_for_exception_catch(void* sp) { - char* stack_adrr = (char*) get_stack_addr(); - size_t used_stack_size = ((size_t)stack_adrr) - ((size_t)sp); - size_t available_stack_size = - get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - return get_restore_stack_size() < available_stack_size; -} - -void remove_guard_stack(vm_thread_t vm_thread) { - int err; - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - - err = mprotect(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_READ | PROT_WRITE); - - - stack_t sigalt; - sigalt.ss_sp = stack_addr - stack_size + guard_page_size; - sigalt.ss_flags = SS_DISABLE; - sigalt.ss_size = guard_stack_size; - - err = sigaltstack (&sigalt, NULL); - - vm_thread->restore_guard_page = true; -} - -static bool check_stack_overflow(Registers* regs, void* fault_addr) { - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - char* guard_page_begin = stack_addr - stack_size + guard_page_size + guard_stack_size; - char* guard_page_end = guard_page_begin + guard_page_size; - - // FIXME: Workaround for main thread - guard_page_end += guard_page_size; - - return((guard_page_begin <= fault_addr) && (fault_addr < guard_page_end)); -} - - -Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", ("SOE detected at ip=%p, sp=%p", - regs->get_ip(), regs->get_sp())); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (!vmthread || env == NULL) - return FALSE; // Crash - - remove_guard_stack(vmthread); - vmthread->restore_guard_page = true; - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - Class* exn_class = env->java_lang_StackOverflowError_Class; - - if (is_in_java(regs)) - { - signal_throw_java_exception(regs, exn_class); - } - else if (is_unwindable()) - { - if (hythread_is_suspend_enabled()) - hythread_suspend_disable(); - signal_throw_exception(regs, exn_class); - } else { - exn_raise_by_class(exn_class); - } - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} - -Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", "NPE detected at " << regs->get_ip()); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (!vmthread || env == NULL) - return FALSE; // Crash - - // Stack overflow can occur in native code as well as in interpreter - if (check_stack_overflow(regs, fault_addr)) - { - Boolean result = stack_overflow_handler(signum, regs, fault_addr); - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return result; - } - - if (!is_in_java(regs) || interpreter_enabled()) - return FALSE; // Crash - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} diff --git a/vm/vmcore/src/util/linux/include/signals_common.h b/vm/vmcore/src/util/linux/include/signals_common.h deleted file mode 100644 index 39cd623..0000000 --- a/vm/vmcore/src/util/linux/include/signals_common.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _SIGNALS_COMMON_H_ -#define _SIGNALS_COMMON_H_ - - -#ifdef _IPF_ -#error IPF architecture is not adopted for unified signal handling -#endif - -#ifdef _EM64T_ -// vvvvvvvv EM64T vvvvvvvv - -inline size_t get_mem_protect_stack_size() { return 0x0400; } - -inline size_t get_restore_stack_size() { - return get_mem_protect_stack_size() + 0x0400; -} - -#define DECL_CHANDLER __attribute__ ((used)) - -// ^^^^^^^^ EM64T ^^^^^^^^ -#else // #ifdef _EM64T_ -// vvvvvvvv IA-32 vvvvvvvv - -inline size_t get_mem_protect_stack_size() { return 0x0100; } - -inline size_t get_restore_stack_size() { - return get_mem_protect_stack_size() + 0x0100; -} - -#define DECL_CHANDLER __attribute__ ((used, cdecl)) - -// ^^^^^^^^ IA-32 ^^^^^^^^ -#endif // #ifdef _EM64T_ - - -// Linux/FreeBSD defines -#if defined(FREEBSD) -#define STACK_MMAP_ATTRS \ - (MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_STACK) -#else -#define STACK_MMAP_ATTRS \ - (MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN) -#endif - - -#endif // _SIGNALS_COMMON_H_ diff --git a/vm/vmcore/src/util/linux/signals_ipf.cpp b/vm/vmcore/src/util/linux/signals_ipf.cpp deleted file mode 100644 index 75bb7b4..0000000 --- a/vm/vmcore/src/util/linux/signals_ipf.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#undef __USE_XOPEN -#include - -#include -#if defined(FREEBSD) -#include -#endif - -#define LOG_DOMAIN "signals" -#include "cxxlog.h" -#include "open/platform_types.h" -#include "Class.h" -#include "interpreter.h" -#include "environment.h" -#include "exceptions.h" -#include "exceptions_jit.h" -#include "signals.h" - - -/* - * Information about stack - */ -inline void* find_stack_addr() { - int err; - void* stack_addr; - pthread_attr_t pthread_attr; - size_t stack_size; - - pthread_t thread = pthread_self(); - err = pthread_getattr_np(thread, &pthread_attr); - assert(!err); - err = pthread_attr_getstack(&pthread_attr, &stack_addr, &stack_size); - assert(!err); - pthread_attr_destroy(&pthread_attr); - return (void *)((unsigned char *)stack_addr + stack_size); -} - -#if 0 -inline size_t find_stack_size() { - int err; - size_t stack_size; - pthread_attr_t pthread_attr; - - pthread_attr_init(&pthread_attr); - err = pthread_attr_getstacksize(&pthread_attr, &stack_size); - pthread_attr_destroy(&pthread_attr); - return stack_size; -} -#endif - -static inline size_t find_guard_stack_size() { - return 64*1024; - -} - -static inline size_t find_guard_page_size() { - int err; - size_t guard_size; - pthread_attr_t pthread_attr; - - pthread_attr_init(&pthread_attr); - err = pthread_attr_getguardsize(&pthread_attr, &guard_size); - pthread_attr_destroy(&pthread_attr); - return guard_size; -} - -static size_t common_guard_stack_size; -static size_t common_guard_page_size; - -static inline void* get_stack_addr() { - return jthread_self_vm_thread_unsafe()->stack_addr; -} - -static inline size_t get_stack_size() { - return jthread_self_vm_thread_unsafe()->stack_size; -} - -static inline size_t get_guard_stack_size() { - return common_guard_stack_size; -} - -static inline size_t get_guard_page_size() { - return common_guard_page_size; -} - - -void init_stack_info() { - vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); - vm_thread->stack_addr = find_stack_addr(); - vm_thread->stack_size = hythread_get_thread_stacksize(hythread_self()); - common_guard_stack_size = find_guard_stack_size(); - common_guard_page_size = find_guard_page_size(); - - /* FIXME: doesn't work, BTW, move this code to common file for all linuxes - * to avoid code duplication - * - * set_guard_stack(); - */ -} - -bool set_guard_stack() { - int err; - - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - assert(((size_t)(&stack_addr)) > ((size_t)((char*)stack_addr - stack_size - + guard_stack_size + 2 * guard_page_size))); - - // map the guard page and protect it - void UNUSED *res = mmap(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - assert(res!=MAP_FAILED); - - err = mprotect(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_NONE ); - - assert(!err); - - //map the alternate stack on which we want to handle the signal - void UNUSED *res2 = mmap(stack_addr - stack_size + guard_page_size, - guard_stack_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - - assert(res2!=MAP_FAILED); - - - stack_t sigalt; - sigalt.ss_sp = stack_addr - stack_size + guard_page_size; - sigalt.ss_flags = SS_ONSTACK; - sigalt.ss_size = guard_stack_size; - - err = sigaltstack (&sigalt, NULL); - assert(!err); - - return true; //FIXME HARMONY-5157 -} - -size_t get_available_stack_size() { - char* stack_addr = (char*) get_stack_addr(); - size_t used_stack_size = stack_addr - ((char*)&stack_addr); - int available_stack_size; - - if (((char*)&stack_addr) > (stack_addr - get_stack_size() + get_guard_page_size() + get_guard_stack_size())) { - available_stack_size = get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - } else { - available_stack_size = get_stack_size() - used_stack_size - get_guard_page_size(); - } - - if (available_stack_size > 0) { - return (size_t) available_stack_size; - } else { - return 0; - } -} - -bool check_available_stack_size(size_t required_size) { - size_t available_stack_size = get_available_stack_size(); - - if (available_stack_size < required_size) { - if (available_stack_size < get_guard_stack_size()) { - remove_guard_stack(p_TLS_vmthread); - } - exn_raise_by_name("java/lang/StackOverflowError"); - return false; - } else { - return true; - } -} - -size_t get_restore_stack_size() { - return 0x0200; -} - -bool check_stack_size_enough_for_exception_catch(void* sp) { - char* stack_adrr = (char*) get_stack_addr(); - size_t used_stack_size = ((size_t)stack_adrr) - ((size_t)sp); - size_t available_stack_size = - get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - return get_restore_stack_size() < available_stack_size; -} - -void remove_guard_stack(vm_thread_t vm_thread) { - int err; - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - - err = mprotect(stack_addr - stack_size + guard_page_size + - guard_stack_size, guard_page_size, PROT_READ | PROT_WRITE); - - - stack_t sigalt; - sigalt.ss_sp = stack_addr - stack_size + guard_page_size; - sigalt.ss_flags = SS_DISABLE; - sigalt.ss_size = guard_stack_size; - - err = sigaltstack (&sigalt, NULL); - -} - -static bool check_stack_overflow(Registers* regs, void* fault_addr) { - char* stack_addr = (char*) get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t guard_stack_size = get_guard_stack_size(); - size_t guard_page_size = get_guard_page_size(); - - char* guard_page_begin = stack_addr - stack_size + guard_page_size + guard_stack_size; - char* guard_page_end = guard_page_begin + guard_page_size; - - return((guard_page_begin <= fault_addr) && (fault_addr < guard_page_end)); -} - - -Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", ("SOE detected at ip=%p, sp=%p", - regs->get_ip(), regs->get_sp())); - - assert(0); // Not implemented - abort(); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (!vmthread || env == NULL) - return FALSE; // Crash - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - Class* exn_class = env->java_lang_StackOverflowError_Class; - - if (is_in_java(regs)) - { - signal_throw_java_exception(regs, exn_class); - } - else if (is_unwindable()) - { - if (hythread_is_suspend_enabled()) - hythread_suspend_disable(); - signal_throw_exception(regs, exn_class); - } else { - remove_guard_stack(vmthread); - vmthread->restore_guard_page = true; - exn_raise_by_class(exn_class); - } - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} - -Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", "NPE detected at " << regs->get_ip()); - - assert(0); // Not implemented - abort(); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (check_stack_overflow(regs, fault_addr)) - { - Boolean result = stack_overflow_handler(signum, regs, fault_addr); - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return result; - } - - if (!vmthread || env == NULL || - !is_in_java(regs) || interpreter_enabled()) - return FALSE; // Crash - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} diff --git a/vm/vmcore/src/util/signals.cpp b/vm/vmcore/src/util/signals.cpp index 637486a..e2861c9 100644 --- a/vm/vmcore/src/util/signals.cpp +++ b/vm/vmcore/src/util/signals.cpp @@ -23,9 +23,164 @@ #include "init.h" #include "vm_threads.h" #include "environment.h" +#include "exceptions.h" #include "signals.h" +#ifdef PLATFORM_POSIX + +#if defined(_EM64T_) +#define RESTORE_STACK_SIZE 0x0400 +#elif defined (_IA32_) +#define RESTORE_STACK_SIZE 0x0100 +#else // IPF +#define RESTORE_STACK_SIZE 0x0200 +#endif + +#else // WINDOWS +#define RESTORE_STACK_SIZE 0x0100 +#endif + + +size_t get_available_stack_size() +{ + size_t stack_addr = (size_t)port_thread_get_stack_address(); + size_t stack_size = port_thread_get_effective_stack_size(); + size_t used_stack_size = stack_addr - (size_t)&stack_size; + size_t available_stack_size = stack_size - used_stack_size; + + return (available_stack_size > 0) ? available_stack_size : 0; +} + +bool check_available_stack_size(size_t required_size) +{ + size_t available_stack_size = get_available_stack_size(); + + if (available_stack_size < required_size) + { + port_thread_clear_guard_page(); + p_TLS_vmthread->restore_guard_page = true; + Global_Env *env = VM_Global_State::loader_env; + exn_raise_by_class(env->java_lang_StackOverflowError_Class); + return false; + } + + return true; +} + +static inline size_t get_available_stack_size(void* sp) { + size_t stack_addr = (size_t)port_thread_get_stack_address(); + size_t stack_size = port_thread_get_effective_stack_size(); + size_t used_stack_size = stack_addr - (size_t)sp; + size_t available_stack_size = stack_size - used_stack_size; + + return (available_stack_size > 0) ? available_stack_size : 0; +} + +bool check_stack_size_enough_for_exception_catch(void* sp) +{ + size_t stack_addr = (size_t)port_thread_get_stack_address(); + size_t stack_size = port_thread_get_effective_stack_size(); + size_t used_stack_size = stack_addr - (size_t)sp; + size_t available_stack_size = stack_size - used_stack_size; + + return RESTORE_STACK_SIZE < available_stack_size; +} + +Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) +{ + TRACE2("signals", ("SOE detected at ip=%p, sp=%p", + regs->get_ip(), regs->get_sp())); + + vm_thread_t vmthread = get_thread_ptr(); + Global_Env* env = VM_Global_State::loader_env; + void* saved_ip = regs->get_ip(); + void* new_ip = NULL; + + if (is_in_ti_handler(vmthread, saved_ip)) + { + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); + } + + if (!vmthread || env == NULL) + return FALSE; // Crash + + port_thread_postpone_guard_page(); + vmthread->restore_guard_page = true; + + // Pass exception to NCAI exception handler + bool is_handled = 0; + ncai_process_signal_event((NativeCodePtr)regs->get_ip(), + (jint)signum, false, &is_handled); + if (is_handled) + { + if (new_ip) + regs->set_ip(saved_ip); + return TRUE; + } + + Class* exn_class = env->java_lang_StackOverflowError_Class; + + if (is_in_java(regs)) + { + signal_throw_java_exception(regs, exn_class); + } + else if (is_unwindable()) + { + if (hythread_is_suspend_enabled()) + hythread_suspend_disable(); + signal_throw_exception(regs, exn_class); + } else { + exn_raise_by_class(exn_class); + } + + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); + + return TRUE; +} + +Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) +{ + TRACE2("signals", "NPE detected at " << regs->get_ip()); + + vm_thread_t vmthread = get_thread_ptr(); + Global_Env* env = VM_Global_State::loader_env; + void* saved_ip = regs->get_ip(); + void* new_ip = NULL; + + if (is_in_ti_handler(vmthread, saved_ip)) + { + new_ip = vm_get_ip_from_regs(vmthread); + regs->set_ip(new_ip); + } + + if (!vmthread || env == NULL) + return FALSE; // Crash + + if (!is_in_java(regs) || interpreter_enabled()) + return FALSE; // Crash + + // Pass exception to NCAI exception handler + bool is_handled = 0; + ncai_process_signal_event((NativeCodePtr)regs->get_ip(), + (jint)signum, false, &is_handled); + if (is_handled) + { + if (new_ip) + regs->set_ip(saved_ip); + return TRUE; + } + + signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); + + if (new_ip && regs->get_ip() == new_ip) + regs->set_ip(saved_ip); + + return TRUE; +} + Boolean abort_handler(port_sigtype UNREF signum, Registers* UNREF regs, void* fault_addr) { TRACE2("signals", "Abort detected at " << regs->get_ip()); diff --git a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp b/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp deleted file mode 100644 index b54b76b..0000000 --- a/vm/vmcore/src/util/win/ia32_em64t/nt_exception_filter_common.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#define LOG_DOMAIN "signals" -#include "cxxlog.h" -#include "open/platform_types.h" -#include "Class.h" -#include "interpreter.h" -#include "environment.h" -#include "exceptions.h" -#include "exceptions_jit.h" -#include "compile.h" -#include "signals.h" - - -/* - * Information about stack - */ -static inline void* find_stack_addr() { - void* stack_addr; - size_t reg_size; - MEMORY_BASIC_INFORMATION memory_information; - - VirtualQuery(&memory_information, &memory_information, sizeof(memory_information)); - reg_size = memory_information.RegionSize; - stack_addr =((char*) memory_information.BaseAddress) + reg_size; - - return stack_addr; -} - -static inline size_t find_guard_page_size() { - size_t guard_size; - SYSTEM_INFO system_info; - - GetSystemInfo(&system_info); - guard_size = system_info.dwPageSize; - - return guard_size; -} - -static inline size_t find_guard_stack_size() { -# ifdef _EM64T_ - //this code in future should be used on both platforms x86-32 and x86-64 - return 64*1024; -# else - // guaerded stack size on windows 32 can be equals one page size only :( - return find_guard_page_size(); -# endif -} - -static size_t common_guard_stack_size; -static size_t common_guard_page_size; - -static inline void* get_stack_addr() { - return jthread_self_vm_thread_unsafe()->stack_addr; -} - -static inline size_t get_stack_size() { - return jthread_self_vm_thread_unsafe()->stack_size; -} - -static inline size_t get_guard_stack_size() { - return common_guard_stack_size; -} - -static inline size_t get_guard_page_size() { - return common_guard_page_size; -} - - -void init_stack_info() { - vm_thread_t vm_thread = jthread_self_vm_thread_unsafe(); - vm_thread->stack_addr = find_stack_addr(); - vm_thread->stack_size = hythread_get_thread_stacksize(hythread_self()); - common_guard_stack_size = find_guard_stack_size(); - common_guard_page_size = find_guard_page_size(); - - - //this code in future should be used on both platforms x86-32 and x86-64 -# ifdef _EM64T_ - ULONG guard_stack_size_param = (ULONG)common_guard_stack_size; - - if (!SetThreadStackGuarantee(&guard_stack_size_param)) { - // should be successful always - assert(0); - } -# endif -} - -static inline size_t get_mem_protect_stack_size() { - return 0x0100; -} - -static inline size_t get_restore_stack_size() { - return get_mem_protect_stack_size() + 0x0100; -} - -bool set_guard_stack() { - void* stack_addr = get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t page_size = get_guard_page_size(); - size_t guard_stack_size = get_guard_stack_size(); - - if (((size_t)(&stack_addr) - get_mem_protect_stack_size()) - < ((size_t)((char*)stack_addr - stack_size - + 2 * page_size + guard_stack_size))) { - return false; - } - - if (!VirtualFree((char*)stack_addr - stack_size + page_size, - page_size, MEM_DECOMMIT)) { - // should be successful always - assert(0); - } - - if (!VirtualAlloc( (char*)stack_addr - stack_size + page_size + guard_stack_size, - page_size, MEM_COMMIT, PAGE_GUARD | PAGE_READWRITE)) { - // should be successful always - assert(0); - } - jthread_self_vm_thread_unsafe()->restore_guard_page = false; - - return true; -} - -void remove_guard_stack(vm_thread_t vm_thread) { - void* stack_addr = get_stack_addr(); - size_t stack_size = get_stack_size(); - size_t page_size = get_guard_page_size(); - size_t guard_stack_size = get_guard_stack_size(); - DWORD oldProtect; - - assert(((size_t)(&stack_addr)) > ((size_t)((char*)stack_addr - stack_size + 3 * page_size))); - vm_thread->restore_guard_page = true; - - if (!VirtualProtect((char*)stack_addr - stack_size + page_size + guard_stack_size, - page_size, PAGE_READWRITE, &oldProtect)) { - // should be successful always - assert(0); - } -} - -size_t get_available_stack_size() { - char* stack_addr = (char*) get_stack_addr(); - size_t used_stack_size = ((size_t)stack_addr) - ((size_t)(&stack_addr)); - size_t available_stack_size; - - if (!p_TLS_vmthread->restore_guard_page) { - available_stack_size = get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - } else { - available_stack_size = get_stack_size() - used_stack_size - get_guard_page_size(); - } - - if (available_stack_size > 0) { - return (size_t) available_stack_size; - } else { - return 0; - } -} - -bool check_available_stack_size(size_t required_size) { - size_t available_stack_size = get_available_stack_size(); - if (available_stack_size < required_size) { - if (available_stack_size < get_guard_stack_size()) { - remove_guard_stack(p_TLS_vmthread); - } - Global_Env *env = VM_Global_State::loader_env; - exn_raise_by_class(env->java_lang_StackOverflowError_Class); - return false; - } else { - return true; - } -} - -bool check_stack_size_enough_for_exception_catch(void* sp) { - char* stack_adrr = (char*) get_stack_addr(); - size_t used_stack_size = ((size_t)stack_adrr) - ((size_t)sp); - size_t available_stack_size = - get_stack_size() - used_stack_size - - 2 * get_guard_page_size() - get_guard_stack_size(); - return get_restore_stack_size() < available_stack_size; -} - - - -Boolean stack_overflow_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", ("SOE detected at ip=%p, sp=%p", - regs->get_ip(), regs->get_sp())); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (!vmthread || env == NULL) - return FALSE; // Crash - - vmthread->restore_guard_page = true; - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - Class* exn_class = env->java_lang_StackOverflowError_Class; - - if (is_in_java(regs)) - { - signal_throw_java_exception(regs, exn_class); - } - else if (is_unwindable()) - { - if (hythread_is_suspend_enabled()) - hythread_suspend_disable(); - signal_throw_exception(regs, exn_class); - } else { - exn_raise_by_class(exn_class); - } - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} - -Boolean null_reference_handler(port_sigtype UNREF signum, Registers* regs, void* fault_addr) -{ - TRACE2("signals", "NPE detected at " << regs->get_ip()); - - vm_thread_t vmthread = get_thread_ptr(); - Global_Env* env = VM_Global_State::loader_env; - void* saved_ip = regs->get_ip(); - void* new_ip = NULL; - - if (is_in_ti_handler(vmthread, saved_ip)) - { - new_ip = vm_get_ip_from_regs(vmthread); - regs->set_ip(new_ip); - } - - if (!vmthread || env == NULL || - !is_in_java(regs) || interpreter_enabled()) - return FALSE; // Crash - - // Pass exception to NCAI exception handler - bool is_handled = 0; - ncai_process_signal_event((NativeCodePtr)regs->get_ip(), - (jint)signum, false, &is_handled); - if (is_handled) - { - if (new_ip) - regs->set_ip(saved_ip); - return TRUE; - } - - signal_throw_java_exception(regs, env->java_lang_NullPointerException_Class); - - if (new_ip && regs->get_ip() == new_ip) - regs->set_ip(saved_ip); - - return TRUE; -} diff --git a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp b/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp deleted file mode 100644 index 124a71c..0000000 --- a/vm/vmcore/src/util/win/ipf/nt_exception_filter.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * @author Intel, Evgueni Brevnov - * @version $Revision: 1.1.2.1.4.3 $ - */ -#include "platform_lowlevel.h" - -#include "Class.h" -#include "Environment.h" -#include "exceptions.h" -#include "method_lookup.h" -#include "vm_strings.h" -#include "vm_threads.h" -#include "open/vm_util.h" -#include "compile.h" -#include "../../../arch/ipf/include/vm_ipf.h" - - -// Afremov Pavel 20050117 -#include "../m2n_ipf_internal.h" - -void nt_to_vm_context(PCONTEXT pcontext, Registers* regs) -{ - ABORT("The function is never called"); - // 20030402: This code is broken - regs->pfs = (uint64)(pcontext->RsPFS); - regs->ip = (uint64)(pcontext->StIIP); - regs->bsp = (uint64*) (pcontext->RsBSP); - - regs->gr[ 1] = (uint64)(pcontext->IntGp); - regs->gr[ 2] = (uint64)(pcontext->IntT0); - regs->gr[ 3] = (uint64)(pcontext->IntT1); - regs->gr[ 4] = (uint64)(pcontext->IntS0); - regs->gr[ 5] = (uint64)(pcontext->IntS1); - regs->gr[ 6] = (uint64)(pcontext->IntS2); - regs->gr[ 7] = (uint64)(pcontext->IntS3); - regs->gr[ 8] = (uint64)(pcontext->IntV0); - regs->gr[ 9] = (uint64)(pcontext->IntT2); - regs->gr[ 10] = (uint64)(pcontext->IntT3); - regs->gr[ 11] = (uint64)(pcontext->IntT4); - regs->gr[ 12] = (uint64)(pcontext->IntSp); - regs->gr[ 13] = (uint64)(pcontext->IntTeb); - regs->gr[ 14] = (uint64)(pcontext->IntT5); - regs->gr[ 15] = (uint64)(pcontext->IntT6); - regs->gr[ 16] = (uint64)(pcontext->IntT7); - regs->gr[ 17] = (uint64)(pcontext->IntT8); - regs->gr[ 18] = (uint64)(pcontext->IntT9); - regs->gr[ 19] = (uint64)(pcontext->IntT10); - regs->gr[ 20] = (uint64)(pcontext->IntT11); - regs->gr[ 21] = (uint64)(pcontext->IntT12); - regs->gr[ 22] = (uint64)(pcontext->IntT13); - regs->gr[ 23] = (uint64)(pcontext->IntT14); - regs->gr[ 24] = (uint64)(pcontext->IntT15); - regs->gr[ 25] = (uint64)(pcontext->IntT16); - regs->gr[ 26] = (uint64)(pcontext->IntT17); - regs->gr[ 27] = (uint64)(pcontext->IntT18); - regs->gr[ 28] = (uint64)(pcontext->IntT19); - regs->gr[ 29] = (uint64)(pcontext->IntT20); - regs->gr[ 30] = (uint64)(pcontext->IntT21); - regs->gr[ 31] = (uint64)(pcontext->IntT22); - - uint32 gr_cursor = 32; - uint64 *bsp_cursor = regs->bsp; - - while (gr_cursor<128) { - - if(0x1f8 == (0x1f8 & (uint64)bsp_cursor)) { - bsp_cursor++; - } - - regs->gr[gr_cursor] = *bsp_cursor; - - bsp_cursor++; - gr_cursor++; - } -} - - -void vm_to_nt_context(Registers* regs, PCONTEXT pcontext) -{ - ABORT("The function is never called"); - // 20030402: This code is broken - pcontext->RsPFS = regs->pfs; - pcontext->StIIP = regs->ip; - pcontextRsBSP = (uint64)regs->bsp; - pcontextIntGp = regs->gr[ 1]; - pcontextIntS0 = regs->gr[ 4]; - pcontext->IntS1 = regs->gr[ 5]; - pcontext->IntS2 = regs->gr[ 6]; - pcontext->IntS3 = regs->gr[ 7]; - pcontext->IntV0 = regs->gr[ 8]; - pcontext->IntSp = regs->gr[ 12]; - pcontext->IntTeb = regs->gr[ 13]; -} - - -int NT_exception_filter(LPEXCEPTION_POINTERS p_NT_exception) -{ - - // this filter catches _all_ null ptr exceptions including those caused by - // VM internal code. To elimate confusion over what caused the null ptr - // exception, we first make sure the exception was thrown inside a Java - // method else assert(0); <--- means it was thrown by VM C/C++ code. - - cout << "very top of NT_exception_filter()" << endl; - cout << "ExceptionCode = " << hex << (p_NT_exception->ExceptionRecord->ExceptionCode) << endl; - cout << "StIIP = " << hex << (long)(p_NT_exception->ContextRecord->StIIP) << endl; - cout << "IntSp = " << hex << (long)(p_NT_exception->ContextRecord->IntSp) << endl; - - Global_Env *env = VM_Global_State::loader_env; - - VM_Code_Type vmct = - vm_identify_eip((void *)p_NT_exception->ContextRecord->StIIP); - if(vmct != VM_TYPE_JAVA) { - // For now. What is the correct way of handling a null ptr exception - // thrown from native code? - cout << "error ---- not a java null reference" << endl; - return EXCEPTION_CONTINUE_SEARCH; - } - - Class *exc_clss = 0; - switch(p_NT_exception->ExceptionRecord->ExceptionCode) { - case STATUS_ACCESS_VIOLATION: - // null pointer exception -- see ...\vc\include\winnt.h - { - // Lazy exception object creation - exc_clss = env->java_lang_NullPointerException_Class; - } - break; - - case STATUS_INTEGER_DIVIDE_BY_ZERO: - // divide by zero exception -- see ...\vc\include\winnt.h - { - // Lazy exception object creation - exc_clss = env->java_lang_ArithmeticException_Class; - } - break; - - case STATUS_PRIVILEGED_INSTRUCTION: - { - // privileged exception -- see ...\vc\include\winnt.h - - // the jit/vm uses "outs" (opcode = 0x6e) as an "int 3" - // to set breakpoints in jitted code (for stuff like enumerating - // live references.) - // save the breakpoint eip in the java thread block so that - // vm_at_a_jit_breakpoint() can restore it - - ABORT("Priveleged exception is caugth"); - return EXCEPTION_CONTINUE_EXECUTION; - } - break; - - case STATUS_DATATYPE_MISALIGNMENT: - { - cout << "got a STATUS_DATATYPE_MISALIGNMENT -- let the os handle this" << endl; - return EXCEPTION_CONTINUE_EXECUTION; - } - break; - - default: - ABORT("Unexpected ecxeption code"); - return EXCEPTION_CONTINUE_SEARCH; - } - - Registers regs; - nt_to_vm_context(p_NT_exception->ContextRecord, ®s); - - // The exception object of class exc_clss will be created by vm_null_ptr_throw. - assert(exc_clss); - exn_athrow_regs(®s, exc_clss, true); - - vm_to_nt_context(®s, p_NT_exception->ContextRecord); - - return EXCEPTION_CONTINUE_EXECUTION; -} //NT_exception_filter - -void __cdecl call_the_run_method2( void * p_xx ) -{ - LPEXCEPTION_POINTERS p_NT_exception; - int NT_exception_filter(LPEXCEPTION_POINTERS p_NT_exception); - - // NT null pointer exception support - __try { - call_the_run_method(p_xx); - } - __except ( p_NT_exception = GetExceptionInformation(), - NT_exception_filter(p_NT_exception) ) { - - ABORT("Uncaught exception"); // get here only if NT_null_ptr_filter() screws up - - } // NT null pointer exception support -} -- 1.5.4