X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fwin32-os.c;h=1d5d5908f4263bb759ca37004e39e2a97092acba;hb=5f0bd05a15aaf93f46baf9b8aa3e9b0bfbca26ab;hp=9172d8d0629427cb3a30bb6c03bb6ea98d74455d;hpb=f057566fe993f008a9b34dc87b026e7c8ef2611d;p=sbcl.git diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c index 9172d8d..1d5d590 100644 --- a/src/runtime/win32-os.c +++ b/src/runtime/win32-os.c @@ -70,6 +70,7 @@ os_vm_size_t os_vm_page_size; #include "gc.h" #include "gencgc-internal.h" #include +#include #if 0 int linux_sparc_siginfo_bug = 0; @@ -680,6 +681,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 @@ -1332,6 +1374,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]; @@ -1362,11 +1411,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; @@ -1376,11 +1423,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) { @@ -1441,6 +1530,25 @@ char *dirname(char *path) return buf; } +// 0 - not a socket or other error, 1 - has input, 2 - has no input +int +socket_input_available(HANDLE socket) +{ + unsigned long count = 0, count_size = 0; + int wsaErrno = GetLastError(); + int err = WSAIoctl((SOCKET)socket, FIONREAD, NULL, 0, + &count, sizeof(count), &count_size, NULL, NULL); + + int ret; + + if (err == 0) { + ret = (count > 0) ? 1 : 2; + } else + ret = 0; + SetLastError(wsaErrno); + return ret; +} + /* Unofficial but widely used property of console handles: they have #b11 in two minor bits, opposed to other handles, that are machine-word-aligned. Properly emulated even on wine. @@ -1480,6 +1588,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 */ @@ -1488,8 +1598,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. @@ -1761,64 +1873,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, @@ -1831,21 +1887,21 @@ 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}; int -win32_unix_write(FDTYPE fd, void * buf, int count) +win32_unix_write(HANDLE handle, void * buf, int count) { - HANDLE handle; DWORD written_bytes; OVERLAPPED overlapped; struct thread * self = arch_os_get_current_thread(); @@ -1854,7 +1910,6 @@ win32_unix_write(FDTYPE fd, void * buf, int count) BOOL seekable; BOOL ok; - handle =(HANDLE)maybe_get_osfhandle(fd); if (console_handle_p(handle)) return win32_write_unicode_console(handle,buf,count); @@ -1918,9 +1973,8 @@ win32_unix_write(FDTYPE fd, void * buf, int count) } int -win32_unix_read(FDTYPE fd, void * buf, int count) +win32_unix_read(HANDLE handle, void * buf, int count) { - HANDLE handle; OVERLAPPED overlapped = {.Internal=0}; DWORD read_bytes = 0; struct thread * self = arch_os_get_current_thread(); @@ -1930,8 +1984,6 @@ win32_unix_read(FDTYPE fd, void * buf, int count) LARGE_INTEGER file_position; BOOL seekable; - handle = (HANDLE)maybe_get_osfhandle(fd); - if (console_handle_p(handle)) return win32_read_unicode_console(handle,buf,count); @@ -2011,8 +2063,6 @@ win32_unix_read(FDTYPE fd, 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. @@ -2031,6 +2081,9 @@ void scratch(void) /* a function from shell32.dll */ SHGetFolderPathA(0, 0, 0, 0, 0); + + /* from advapi32.dll */ + CryptGenRandom(0, 0, 0); } char *