Author: bonefish Date: 2011-05-22 02:19:20 +0200 (Sun, 22 May 2011) New Revision: 41642 Changeset: https://dev.haiku-os.org/changeset/41642 Added: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals_asm.S haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.cpp haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.cpp Removed: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.c haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.c Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/arch/x86/arch_thread.h haiku/branches/developer/bonefish/signals/headers/private/system/arch/x86/arch_commpage_defs.h haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/Jamfile haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_interrupts.S haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_thread.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/asm_offsets.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.h haiku/branches/developer/bonefish/signals/src/system/libroot/libroot_versions haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/Jamfile Log: * Added private SA_BEOS_COMPATIBLE_HANDLER sigaction::sa_flags flag to indicate that the signal handler shall be invoked in a BeOS compatible manner. * Used ELF symbol versioning to provide backwards compatible versions of signal() and sigaction(), that set the SA_BEOS_COMPATIBLE_HANDLER flag. * Added signal handler wrapper function x86_signal_frame_function_beos(), which works similar to x86_signal_frame_function() (i.e. is also copied to the commpage, calls the signal handler and the _kern_restore_signal_frame() syscall afterwards), but calls the signal handler in a BeOS compatible manner. That is it copies the vregs onto the stack (passing them by value) and back afterwards. This wrapper function is used for sigactions with the SA_BEOS_COMPATIBLE_HANDLER flag. Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/arch/x86/arch_thread.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/arch/x86/arch_thread.h 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/arch/x86/arch_thread.h 2011-05-22 00:19:20 UTC (rev 41642) @@ -24,9 +24,6 @@ void x86_restart_syscall(struct iframe* frame); -void i386_return_from_signal(); -void i386_end_return_from_signal(); - // override empty macro #undef arch_syscall_64_bit_return_value void arch_syscall_64_bit_return_value(void); Modified: haiku/branches/developer/bonefish/signals/headers/private/system/arch/x86/arch_commpage_defs.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/system/arch/x86/arch_commpage_defs.h 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/headers/private/system/arch/x86/arch_commpage_defs.h 2011-05-22 00:19:20 UTC (rev 41642) @@ -14,6 +14,8 @@ #define COMMPAGE_ENTRY_X86_MEMSET (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 2) #define COMMPAGE_ENTRY_X86_SIGNAL_HANDLER \ (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3) +#define COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS \ + (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 4) #define ARCH_USER_COMMPAGE_ADDR (0xffff0000) Modified: haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h 2011-05-22 00:19:20 UTC (rev 41642) @@ -25,4 +25,10 @@ // use only) +// additional sigaction::sa_flags flag +#define SA_BEOS_COMPATIBLE_HANDLER 0x80000000 + // BeOS compatible signal handler, i.e. the vregs argument is passed + // per-value, not per-pointer + + #endif /* _SYSTEM_SIGNAL_DEFS_H */ Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/Jamfile =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/Jamfile 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/Jamfile 2011-05-22 00:19:20 UTC (rev 41642) @@ -42,6 +42,7 @@ syscall.S vm86.cpp x86_signals.cpp + x86_signals_asm.S x86_syscalls.cpp # paging Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_interrupts.S =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_interrupts.S 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_interrupts.S 2011-05-22 00:19:20 UTC (rev 41642) @@ -798,25 +798,6 @@ FUNCTION_END(x86_sysenter) -/*! Is copied to the signal stack call to restore the original frame when - the signal handler exits. - The copying code (in arch_thread.c::arch_setup_signal_frame()) copies - everything between the i386_return_from_signal and i386_end_return_from_signal - symbols. -*/ -FUNCTION(i386_return_from_signal): - addl $12, %esp // Flushes the 3 arguments to sa_handler - movl $SYSCALL_RESTORE_SIGNAL_FRAME, %eax - // This syscall will restore the cpu context to the - // one existing before calling the signal handler - movl $0, %ecx - lea 4(%esp), %edx - int $99 - ret -FUNCTION_END(i386_return_from_signal) -SYMBOL(i386_end_return_from_signal): - - /*! void i386_restore_frame_from_syscall(struct iframe iframe); Pops the regs of the iframe from the stack to make it current and then return to userland. Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_thread.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_thread.cpp 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_thread.cpp 2011-05-22 00:19:20 UTC (rev 41642) @@ -559,7 +559,8 @@ // Adjust the iframe's esp and eip, so that the thread will continue with // the prepared stack, executing the signal handler wrapper function. frame->user_esp = (addr_t)userStack; - frame->eip = x86_get_user_signal_handler_wrapper(); + frame->eip = x86_get_user_signal_handler_wrapper( + (action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0); return B_OK; } Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/asm_offsets.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/asm_offsets.cpp 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/asm_offsets.cpp 2011-05-22 00:19:20 UTC (rev 41642) @@ -13,6 +13,7 @@ #include <arch_cpu.h> #include <cpu.h> +#include <ksignal.h> #include <ksyscalls.h> #include <thread_types.h> @@ -66,4 +67,20 @@ memcpy); DEFINE_OFFSET_MACRO(X86_OPTIMIZED_FUNCTIONS, x86_optimized_functions, memset); + + // struct signal_frame_data + DEFINE_SIZEOF_MACRO(SIGNAL_FRAME_DATA, signal_frame_data); + DEFINE_OFFSET_MACRO(SIGNAL_FRAME_DATA, signal_frame_data, info); + DEFINE_OFFSET_MACRO(SIGNAL_FRAME_DATA, signal_frame_data, context); + DEFINE_OFFSET_MACRO(SIGNAL_FRAME_DATA, signal_frame_data, user_data); + DEFINE_OFFSET_MACRO(SIGNAL_FRAME_DATA, signal_frame_data, handler); + + // struct ucontext_t + DEFINE_OFFSET_MACRO(UCONTEXT_T, __ucontext_t, uc_mcontext); + + // struct vregs + DEFINE_SIZEOF_MACRO(VREGS, vregs); + + // struct siginfo_t + DEFINE_OFFSET_MACRO(SIGINFO_T, __siginfo_t, si_signo); } Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.cpp 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.cpp 2011-05-22 00:19:20 UTC (rev 41642) @@ -18,6 +18,10 @@ #include "syscall_numbers.h" +// implemented in assembly +extern "C" void x86_signal_frame_function_beos(signal_frame_data* frameData); + + extern "C" void x86_signal_frame_function(signal_frame_data* frameData) { @@ -36,14 +40,12 @@ handler(frameData->info.si_signo, &frameData->info, &frameData->context, frameData->user_data); } else { - // Simple handler function -- we call it BeOS style, i.e. with - // additional user data pointer and vregs parameters. - // Note that the vregs* parameter is not a pointer in the handler - // prototype as documented in BeOS. At least for x86 that doesn't make - // a difference for the callee, though, as it always gets a pointer. The - // difference is on the caller side only, where the object would have to - // be copied in the non-pointer case. We don't want that, since the - // vregs changes the handler makes must be applied when it returns. + // Simple handler function -- we call it with additional user data + // pointer and vregs parameters. Note that unlike in BeOS the last + // parameter is a pointer to a vregs structure, while in BeOS the + // structure was passed be value. For setting up a BeOS binary + // compatible signal handler call x86_signal_frame_function_beos() is + // used instead. void (*handler)(int, void*, vregs*) = (void (*)(int, void*, vregs*))frameData->handler; handler(frameData->info.si_signo, frameData->user_data, @@ -71,34 +73,53 @@ } -void -x86_initialize_commpage_signal_handler() +static void +register_signal_handler_function(const char* functionName, int32 commpageIndex, + const char* commpageSymbolName, addr_t expectedAddress) { // look up the x86_signal_frame_function() symbol -- we have its address, // but also need its size elf_symbol_info symbolInfo; - if (elf_lookup_kernel_symbol("x86_signal_frame_function", &symbolInfo) + if (elf_lookup_kernel_symbol(functionName, &symbolInfo) != B_OK) { panic("x86_initialize_commpage_signal_handler(): Failed to find " - "signal frame function!"); + "signal frame function \"%s\"!", functionName); } - ASSERT((addr_t)&x86_signal_frame_function == symbolInfo.address); + ASSERT(expectedAddress == symbolInfo.address); // fill in the commpage table entry - fill_commpage_entry(COMMPAGE_ENTRY_X86_SIGNAL_HANDLER, - (void*)symbolInfo.address, symbolInfo.size); + fill_commpage_entry(commpageIndex, (void*)symbolInfo.address, + symbolInfo.size); - // add syscall to the commpage image + // add symbol to the commpage image image_id image = get_commpage_image(); - elf_add_memory_image_symbol(image, "commpage_signal_handler", - ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER], - symbolInfo.size, B_SYMBOL_TYPE_TEXT); + elf_add_memory_image_symbol(image, commpageSymbolName, + ((addr_t*)USER_COMMPAGE_ADDR)[commpageIndex], symbolInfo.size, + B_SYMBOL_TYPE_TEXT); } +void +x86_initialize_commpage_signal_handler() +{ + // standard handler + register_signal_handler_function("x86_signal_frame_function", + COMMPAGE_ENTRY_X86_SIGNAL_HANDLER, "commpage_signal_handler", + (addr_t)&x86_signal_frame_function); + + // handler for BeOS backwards compatibility + register_signal_handler_function("x86_signal_frame_function_beos", + COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS, "commpage_signal_handler_beos", + (addr_t)&x86_signal_frame_function_beos); +} + + addr_t -x86_get_user_signal_handler_wrapper() +x86_get_user_signal_handler_wrapper(bool beosHandler) { - return ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER]; + int32 index = beosHandler + ? COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS + : COMMPAGE_ENTRY_X86_SIGNAL_HANDLER; + return ((addr_t*)USER_COMMPAGE_ADDR)[index]; } Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.h =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.h 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals.h 2011-05-22 00:19:20 UTC (rev 41642) @@ -10,7 +10,7 @@ void x86_initialize_commpage_signal_handler(); -addr_t x86_get_user_signal_handler_wrapper(); +addr_t x86_get_user_signal_handler_wrapper(bool beosHandler); #endif // _KERNEL_ARCH_X86_SIGNALS_H Added: haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals_asm.S =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals_asm.S (rev 0) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/x86_signals_asm.S 2011-05-22 00:19:20 UTC (rev 41642) @@ -0,0 +1,71 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include <asm_defs.h> +#include <commpage_defs.h> + +#include "asm_offsets.h" +#include "syscall_numbers.h" + + +/*! \fn void x86_signal_frame_function_beos(signal_frame_data* frameData) + \brief Wrapper function for BeOS-style signal handler functions. + \param frameData The signal frame data. +*/ +FUNCTION(x86_signal_frame_function_beos): + // set up a stack frame + push %ebp + mov %esp, %ebp + + // Move our parameter to %esi, so we can conveniently work with it. Note + // that we're free to use non-scratch registers without saving them, since + // we don't have any caller to save them for. The caller will restore the + // interrupted environment anyway. + mov 8(%ebp), %esi + + // push the parameters for the handler function + + // make space for the vregs parameter + lea -VREGS_sizeof(%esp), %esp + mov %esp, %edi + + // copy the vregs via memcpy() + pushl $VREGS_sizeof + lea SIGNAL_FRAME_DATA_context + UCONTEXT_T_uc_mcontext(%esi), %eax + push %eax + push %edi + movl USER_COMMPAGE_ADDR + 4 * COMMPAGE_ENTRY_X86_MEMCPY, %eax + call *%eax + addl $12, %esp + + // the vregs are on the stack -- push user data and signal number + movl SIGNAL_FRAME_DATA_user_data(%esi), %eax + push %eax + movl SIGNAL_FRAME_DATA_info+SIGINFO_T_si_signo(%esi), %eax + push %eax + + // call the signal handler + movl SIGNAL_FRAME_DATA_handler(%esi), %eax + call *%eax + addl $8, %esp // pop only signal number and user data arguments + + // copy the vregs back to the frameData structure + pushl $VREGS_sizeof + push %edi + lea SIGNAL_FRAME_DATA_context + UCONTEXT_T_uc_mcontext(%esi), %eax + push %eax + movl USER_COMMPAGE_ADDR + 4 * COMMPAGE_ENTRY_X86_MEMCPY, %eax + call *%eax + addl $12 + VREGS_sizeof, %esp + + // call the _kern_restore_signal_frame() syscall -- does not return (here) + pushl %esi + pushl $0 // dummy return value + movl $SYSCALL_RESTORE_SIGNAL_FRAME, %eax + int $99 + + // never gets here +FUNCTION_END(x86_signal_frame_function_beos) Modified: haiku/branches/developer/bonefish/signals/src/system/libroot/libroot_versions =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/libroot_versions 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/libroot_versions 2011-05-22 00:19:20 UTC (rev 41642) @@ -3,3 +3,6 @@ LIBROOT_1_ALPHA1 { } LIBROOT_BASE; + +LIBROOT_1_ALPHA3 { +} LIBROOT_1_ALPHA1; Modified: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/Jamfile =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/Jamfile 2011-05-22 00:05:39 UTC (rev 41641) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/Jamfile 2011-05-22 00:19:20 UTC (rev 41642) @@ -12,12 +12,12 @@ send_signal.c set_signal_disposition.cpp set_signal_stack.c - sigaction.c + sigaction.cpp sigaltstack.c sighold.cpp sigignore.cpp siginterrupt.cpp - signal.c + signal.cpp sigpause.cpp sigpending.c sigprocmask.c Copied: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.cpp (from rev 41601, haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/sigaction.cpp 2011-05-22 00:19:20 UTC (rev 41642) @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2011, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Daniel Reinhold, danielre@xxxxxxxxxxxx + * Ingo Weinhod, ingo_weinhold@xxxxxx + */ + + +#include <errno.h> +#include <signal.h> + +#include <syscall_utils.h> + +#include <signal_defs.h> +#include <symbol_versioning.h> +#include <syscalls.h> + + +extern "C" int +__sigaction_beos(int signal, const struct sigaction* action, + struct sigaction* oldAction) +{ + // If a new action is given, copy it and set the SA_BEOS_COMPATIBLE_HANDLER + // flag to indicate BeOS compatible behavior. + struct sigaction newAction; + if (action != NULL) { + newAction = *action; + newAction.sa_flags |= SA_BEOS_COMPATIBLE_HANDLER; + action = &newAction; + } + + status_t status = _kern_sigaction(signal, action, oldAction); + if (status != B_OK) + RETURN_AND_SET_ERRNO(status); + + // clear SA_BEOS_COMPATIBLE_HANDLER in the returned action + if (oldAction != NULL) + oldAction->sa_flags &= ~(int)SA_BEOS_COMPATIBLE_HANDLER; + + return 0; +} + + +extern "C" int +__sigaction_current(int signal, const struct sigaction* action, + struct sigaction* oldAction) +{ + RETURN_AND_SET_ERRNO(_kern_sigaction(signal, action, oldAction)); +} + + +DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__sigaction_beos", "sigaction@", "BASE"); + +DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__sigaction_current", "sigaction@@", + "1_ALPHA3"); Copied: haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.cpp (from rev 41601, haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.c) =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.cpp (rev 0) +++ haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/signal.cpp 2011-05-22 00:19:20 UTC (rev 41642) @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2011, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Daniel Reinhold (danielre@xxxxxxxxxxxx) + */ + + +#include <signal.h> +#include <stdio.h> + +#include <symbol_versioning.h> + + +extern "C" int __sigaction_beos(int signal, const struct sigaction* action, + struct sigaction* oldAction); +extern "C" int __sigaction_current(int signal, const struct sigaction* action, + struct sigaction* oldAction); + + +extern "C" __sighandler_t +__signal_beos(int sig, __sighandler_t signalHandler) +{ + struct sigaction newAction, oldAction; + + // setup the replacement sigaction + newAction.sa_handler = signalHandler; + newAction.sa_mask = 0; + newAction.sa_flags = 0; + + if (__sigaction_beos(sig, &newAction, &oldAction) != 0) + return SIG_ERR; + + // success, return the original handler + return oldAction.sa_handler; +} + + +extern "C" __sighandler_t +__signal_current(int sig, __sighandler_t signalHandler) +{ + struct sigaction newAction, oldAction; + + // setup the replacement sigaction + newAction.sa_handler = signalHandler; + newAction.sa_mask = 0; + newAction.sa_flags = 0; + + if (__sigaction_current(sig, &newAction, &oldAction) != 0) + return SIG_ERR; + + // success, return the original handler + return oldAction.sa_handler; +} + + +DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__signal_beos", "signal@", "BASE"); + +DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__signal_current", "signal@@", + "1_ALPHA3");