X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fruntime%2Fwin32-os.c;h=49358a14370c9f93a9d61dd353c2f1755a7cd51c;hb=37d3828773e2f847bb1ed7522b0af4fb8e736fc8;hp=33d05f43c3d2e71ef3c7554ce8ab13318e7c8534;hpb=ed1910efb36f71b5ebe33b5ffffd7195e15644de;p=sbcl.git diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c index 33d05f4..49358a1 100644 --- a/src/runtime/win32-os.c +++ b/src/runtime/win32-os.c @@ -680,6 +680,54 @@ void os_preinit() } #endif /* LISP_FEATURE_SB_THREAD */ + +#ifdef LISP_FEATURE_X86_64 +/* Windows has 32-bit 'longs', so printf...%lX (and other %l patterns) doesn't + * work well with address-sized values, like it's done all over the place in + * SBCL. And msvcrt uses I64, not LL, for printing long longs. + * + * I've already had enough search/replace with longs/words/intptr_t for today, + * so I prefer to solve this problem with a format string translator. */ + +/* There is (will be) defines for printf and friends. */ + +static int translating_vfprintf(FILE*stream, const char *fmt, va_list args) +{ + char translated[1024]; + int i=0, delta = 0; + + while (fmt[i-delta] && iwin32_context)->Eip))[0] != 0x0b0f) + if (((unsigned short *)*os_context_pc_addr(ctx))[0] != 0x0b0f) return -1; #endif @@ -1328,6 +1373,13 @@ handle_exception(EXCEPTION_RECORD *exception_record, context.sigmask = self ? self->os_thread->blocked_signal_set : 0; #endif + os_context_register_t oldbp = NULL; + if (self) { + oldbp = self ? self->carried_base_pointer : 0; + self->carried_base_pointer + = (os_context_register_t) voidreg(win32_context, bp); + } + /* For EXCEPTION_ACCESS_VIOLATION only. */ void *fault_address = (void *)exception_record->ExceptionInformation[1]; @@ -1358,11 +1410,9 @@ handle_exception(EXCEPTION_RECORD *exception_record, rc = handle_breakpoint_trap(ctx, self); break; -#if defined(LISP_FEATURE_X86) case EXCEPTION_SINGLE_STEP: rc = handle_single_step(ctx); break; -#endif default: rc = -1; @@ -1372,11 +1422,53 @@ handle_exception(EXCEPTION_RECORD *exception_record, /* All else failed, drop through to the lisp-side exception handler. */ signal_internal_error_or_lose(ctx, exception_record, fault_address); + if (self) + self->carried_base_pointer = oldbp; + errno = lastErrno; SetLastError(lastError); return ExceptionContinueExecution; } +#ifdef LISP_FEATURE_X86_64 + +#define RESTORING_ERRNO() \ + int sbcl__lastErrno = errno; \ + RUN_BODY_ONCE(restoring_errno, errno = sbcl__lastErrno) + +LONG +veh(EXCEPTION_POINTERS *ep) +{ + EXCEPTION_DISPOSITION disp; + + RESTORING_ERRNO() { + if (!pthread_self()) + return EXCEPTION_CONTINUE_SEARCH; + } + + disp = handle_exception(ep->ExceptionRecord,0,ep->ContextRecord,0); + + switch (disp) + { + case ExceptionContinueExecution: + return EXCEPTION_CONTINUE_EXECUTION; + case ExceptionContinueSearch: + return EXCEPTION_CONTINUE_SEARCH; + default: + fprintf(stderr,"Exception handler is mad\n"); + ExitProcess(0); + } +} +#endif + +os_context_register_t +carry_frame_pointer(os_context_register_t default_value) +{ + struct thread* self = arch_os_get_current_thread(); + os_context_register_t bp = self->carried_base_pointer; + return bp ? bp : default_value; +} + void wos_install_interrupt_handlers(struct lisp_exception_frame *handler) { @@ -1495,6 +1587,8 @@ boolean io_begin_interruptible(HANDLE handle) return 1; } +static pthread_mutex_t interrupt_io_lock = PTHREAD_MUTEX_INITIALIZER; + /* Unmark current thread as (probably) doing synchronous I/O; if an * I/O cancellation was requested, postpone it until next * io_begin_interruptible */ @@ -1503,8 +1597,10 @@ io_end_interruptible(HANDLE handle) { if (!ptr_CancelIoEx) return; + pthread_mutex_lock(&interrupt_io_lock); __sync_bool_compare_and_swap(&this_thread->synchronous_io_handle_and_flag, handle, 0); + pthread_mutex_unlock(&interrupt_io_lock); } /* Documented limit for ReadConsole/WriteConsole is 64K bytes. @@ -1776,64 +1872,8 @@ win32_maybe_interrupt_io(void* thread) { struct thread *th = thread; boolean done = 0; - /* Kludge. (?) - * - * ICBW about all of this. But it seems to me that this procedure is - * a race condition. In theory. One that is hard produce (I can't - * come up with a test case that exploits it), and might only be a bug - * if users are doing weird things with I/O, possibly from FFI. But a - * race is a race, so shouldn't this function and io_end_interruptible - * cooperate more? - * - * Here's my thinking: - * - * A.. - * ... stuffs its handle into its structure. - * B.. - * ... calls us to wake the thread, finds the handle. - * But just before we actually call CancelSynchronousIo/CancelIoEx, - * something weird happens in the scheduler and the system is - * so extremely busy that the interrupter doesn't get scheduled - * for a while, giving the interruptee lots of time to continue. - * A.. Didn't actually have to block, calls io_end_interruptible (in - * which the handle flag already invalid, but it doesn't care - * about that and still continues). - * ... Proceeds to do unrelated I/O, e.g. goes into FFI code - * (possible, because the CSP page hasn't been armed yet), which - * does I/O from a C library, completely unrelated to SBCL's - * routines. - * B.. The scheduler gives us time for the interrupter again. - * We call CancelSynchronousIo/CancelIoEx. - * A.. Interruptee gets an expected error in unrelated I/O during FFI. - * Interruptee's C code is unhappy and dies. - * - * Note that CancelSynchronousIo and CancelIoEx have a rather different - * effect here. In the normal (CancelIoEx) case, we only ever kill - * I/O on the file handle in question. I think we could ask users - * to please not both use Lisp streams (unix-read/write) _and_ FFI code - * on the same file handle in quick succession. - * - * CancelSynchronousIo seems more dangerous though. Here we interrupt - * I/O on any other handle, even ones we're not actually responsible for, - * because this functions deals with the thread handle, not the file - * handle. - * - * Options: - * - Use mutexes. Somewhere, somehow. Presumably one mutex per - * target thread, acquired around win32_maybe_interrupt_io and - * io_end_interruptible. (That's one mutex use per I/O - * operation, but I can't imagine that compared to our FFI overhead - * that's much of a problem.) - * - In io_end_interruptible, detect that the flag has been - * invalidated, and in that case, do something clever (what?) to - * wait for the imminent gc_stop_the_world, which implicitly tells - * us that win32_maybe_interrupt_io must have exited. Except if - * some _third_ thread is also beginning to call interrupt-thread - * and wake_thread at the same time...? - * - Revert the whole CancelSynchronousIo business after all. - * - I'm wrong and everything is OK already. - */ if (ptr_CancelIoEx) { + pthread_mutex_lock(&interrupt_io_lock); HANDLE h = (HANDLE) InterlockedExchangePointer((volatile LPVOID *) &th->synchronous_io_handle_and_flag, @@ -1846,13 +1886,14 @@ win32_maybe_interrupt_io(void* thread) } if (ptr_CancelSynchronousIo) { pthread_mutex_lock(&th->os_thread->fiber_lock); - done = ptr_CancelSynchronousIo(th->os_thread->fiber_group->handle); + done = !!ptr_CancelSynchronousIo(th->os_thread->fiber_group->handle); pthread_mutex_unlock(&th->os_thread->fiber_lock); } - return (!!done)|(!!ptr_CancelIoEx(h,NULL)); + done |= !!ptr_CancelIoEx(h,NULL); } + pthread_mutex_unlock(&interrupt_io_lock); } - return 0; + return done; } static const LARGE_INTEGER zero_large_offset = {.QuadPart = 0LL}; @@ -2021,8 +2062,6 @@ win32_unix_read(HANDLE handle, void * buf, int count) return read_bytes; } -void __stdcall RtlUnwind(void *, void *, void *, void *); /* I don't have winternl.h */ - /* We used to have a scratch() function listing all symbols needed by * Lisp. Much rejoicing commenced upon its removal. However, I would * like cold init to fail aggressively when encountering unused symbols.