Signals, 2nd pass: syscall restarting now only works on EINTR (removed other exotic retcodes like ERESTARTSYS); signal handlers now receive 3 args, and the vregs struct is used to save the signal context, making the system beos compatible.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1681 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -178,10 +178,6 @@ enum {
|
||||
#define EOPNOTSUPP (B_POSIX_ERROR_BASE + 43)
|
||||
#define ENOTSOCK (B_POSIX_ERROR_BASE + 44)
|
||||
|
||||
#define ERESTARTSYS (B_POSIX_ERROR_BASE + 45)
|
||||
#define ERESTARTNOINTR (B_POSIX_ERROR_BASE + 46)
|
||||
#define ERESTARTNOHAND (B_POSIX_ERROR_BASE + 47)
|
||||
|
||||
#define ENOMEM B_NO_MEMORY
|
||||
#define EACCES B_PERMISSION_DENIED
|
||||
#define EINTR B_INTERRUPTED
|
||||
|
||||
@@ -120,6 +120,9 @@ typedef struct stack_t {
|
||||
#define SA_RESTART 0x08
|
||||
#define SA_STACK 0x10
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
|
||||
int sigemptyset(sigset_t *set);
|
||||
@@ -162,5 +165,167 @@ int sigsuspend(const sigset_t *mask);
|
||||
int kill(pid_t pid, int sig);
|
||||
int send_signal(pid_t tid, uint sig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* signal handlers get this as the last argument */
|
||||
typedef struct vregs vregs;
|
||||
|
||||
#if __POWERPC__
|
||||
struct vregs
|
||||
{
|
||||
ulong pc, /* program counter */
|
||||
r0, /* scratch */
|
||||
r1, /* stack ptr */
|
||||
r2, /* TOC */
|
||||
r3,r4,r5,r6,r7,r8,r9,r10, /* volatile regs */
|
||||
r11,r12; /* scratch regs */
|
||||
|
||||
double f0, /* fp scratch */
|
||||
f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13; /* fp volatile regs */
|
||||
|
||||
ulong filler1, /* place holder */
|
||||
fpscr, /* fp condition codes */
|
||||
ctr, xer, cr, msr, lr; /* misc. status */
|
||||
};
|
||||
#endif /* __POWERPC__ */
|
||||
|
||||
#if __INTEL__
|
||||
|
||||
typedef struct packed_fp_stack {
|
||||
unsigned char st0[10];
|
||||
unsigned char st1[10];
|
||||
unsigned char st2[10];
|
||||
unsigned char st3[10];
|
||||
unsigned char st4[10];
|
||||
unsigned char st5[10];
|
||||
unsigned char st6[10];
|
||||
unsigned char st7[10];
|
||||
} packed_fp_stack;
|
||||
|
||||
typedef struct packed_mmx_regs {
|
||||
unsigned char mm0[10];
|
||||
unsigned char mm1[10];
|
||||
unsigned char mm2[10];
|
||||
unsigned char mm3[10];
|
||||
unsigned char mm4[10];
|
||||
unsigned char mm5[10];
|
||||
unsigned char mm6[10];
|
||||
unsigned char mm7[10];
|
||||
} packed_mmx_regs;
|
||||
|
||||
typedef struct old_extended_regs {
|
||||
unsigned short fp_control;
|
||||
unsigned short _reserved1;
|
||||
unsigned short fp_status;
|
||||
unsigned short _reserved2;
|
||||
unsigned short fp_tag;
|
||||
unsigned short _reserved3;
|
||||
unsigned long fp_eip;
|
||||
unsigned short fp_cs;
|
||||
unsigned short fp_opcode;
|
||||
unsigned long fp_datap;
|
||||
unsigned short fp_ds;
|
||||
unsigned short _reserved4;
|
||||
union {
|
||||
packed_fp_stack fp;
|
||||
packed_mmx_regs mmx;
|
||||
} fp_mmx;
|
||||
} old_extended_regs;
|
||||
|
||||
typedef struct fp_stack {
|
||||
unsigned char st0[10];
|
||||
unsigned char _reserved_42_47[6];
|
||||
unsigned char st1[10];
|
||||
unsigned char _reserved_58_63[6];
|
||||
unsigned char st2[10];
|
||||
unsigned char _reserved_74_79[6];
|
||||
unsigned char st3[10];
|
||||
unsigned char _reserved_90_95[6];
|
||||
unsigned char st4[10];
|
||||
unsigned char _reserved_106_111[6];
|
||||
unsigned char st5[10];
|
||||
unsigned char _reserved_122_127[6];
|
||||
unsigned char st6[10];
|
||||
unsigned char _reserved_138_143[6];
|
||||
unsigned char st7[10];
|
||||
unsigned char _reserved_154_159[6];
|
||||
} fp_stack;
|
||||
|
||||
typedef struct mmx_regs {
|
||||
unsigned char mm0[10];
|
||||
unsigned char _reserved_42_47[6];
|
||||
unsigned char mm1[10];
|
||||
unsigned char _reserved_58_63[6];
|
||||
unsigned char mm2[10];
|
||||
unsigned char _reserved_74_79[6];
|
||||
unsigned char mm3[10];
|
||||
unsigned char _reserved_90_95[6];
|
||||
unsigned char mm4[10];
|
||||
unsigned char _reserved_106_111[6];
|
||||
unsigned char mm5[10];
|
||||
unsigned char _reserved_122_127[6];
|
||||
unsigned char mm6[10];
|
||||
unsigned char _reserved_138_143[6];
|
||||
unsigned char mm7[10];
|
||||
unsigned char _reserved_154_159[6];
|
||||
} mmx_regs;
|
||||
|
||||
typedef struct xmmx_regs {
|
||||
unsigned char xmm0[16];
|
||||
unsigned char xmm1[16];
|
||||
unsigned char xmm2[16];
|
||||
unsigned char xmm3[16];
|
||||
unsigned char xmm4[16];
|
||||
unsigned char xmm5[16];
|
||||
unsigned char xmm6[16];
|
||||
unsigned char xmm7[16];
|
||||
} xmmx_regs;
|
||||
|
||||
typedef struct new_extended_regs {
|
||||
unsigned short fp_control;
|
||||
unsigned short fp_status;
|
||||
unsigned short fp_tag;
|
||||
unsigned short fp_opcode;
|
||||
unsigned long fp_eip;
|
||||
unsigned short fp_cs;
|
||||
unsigned short res_14_15;
|
||||
unsigned long fp_datap;
|
||||
unsigned short fp_ds;
|
||||
unsigned short _reserved_22_23;
|
||||
unsigned long mxcsr;
|
||||
unsigned long _reserved_28_31;
|
||||
union {
|
||||
fp_stack fp;
|
||||
mmx_regs mmx;
|
||||
} fp_mmx;
|
||||
xmmx_regs xmmx;
|
||||
unsigned char _reserved_288_511[224];
|
||||
} new_extended_regs;
|
||||
|
||||
typedef struct extended_regs {
|
||||
union {
|
||||
old_extended_regs old_format;
|
||||
new_extended_regs new_format;
|
||||
} state;
|
||||
unsigned long format;
|
||||
} extended_regs;
|
||||
|
||||
struct vregs {
|
||||
unsigned long eip;
|
||||
unsigned long eflags;
|
||||
unsigned long eax;
|
||||
unsigned long ecx;
|
||||
unsigned long edx;
|
||||
unsigned long esp;
|
||||
unsigned long ebp;
|
||||
unsigned long _reserved_1;
|
||||
extended_regs xregs;
|
||||
unsigned long _reserved_2[3];
|
||||
};
|
||||
|
||||
#endif /* __INTEL__ */
|
||||
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
||||
|
||||
@@ -10,19 +10,26 @@
|
||||
#include <syscalls.h>
|
||||
|
||||
|
||||
void sig_handler(int);
|
||||
void alarm_handler(int);
|
||||
void install_handler(int, __signal_func_ptr);
|
||||
typedef void (*beos_signal_func_ptr)(int, void *, struct vregs *);
|
||||
|
||||
|
||||
void sig_handler(int, void *data, struct vregs *regs);
|
||||
void alarm_handler(int, void *data, struct vregs *regs);
|
||||
void install_handler(int, beos_signal_func_ptr);
|
||||
int32 thread(void *);
|
||||
void usage(void);
|
||||
|
||||
|
||||
void
|
||||
sig_handler(int sig)
|
||||
sig_handler(int sig, void *data, struct vregs *regs)
|
||||
{
|
||||
int i;
|
||||
char buffer[10];
|
||||
|
||||
memcpy(buffer, data, 10);
|
||||
buffer[9] = '\0';
|
||||
printf("sig_test (sig_handler): Received signal #%d...\n", sig);
|
||||
printf("User data at %p (contents: \"%s\"), vregs at %p\n", data, buffer, regs);
|
||||
printf("Counting for fun: ");
|
||||
for (i=0; i<10; i++)
|
||||
printf("%d ", i);
|
||||
@@ -31,22 +38,23 @@ sig_handler(int sig)
|
||||
|
||||
|
||||
void
|
||||
alarm_handler(int sig)
|
||||
alarm_handler(int sig, void *data, struct vregs *regs)
|
||||
{
|
||||
printf("Alarm!\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
install_handler(int sig, __signal_func_ptr handler)
|
||||
install_handler(int sig, beos_signal_func_ptr handler)
|
||||
{
|
||||
struct sigaction newa;
|
||||
struct sigaction olda;
|
||||
|
||||
memset(&newa, 0, sizeof(newa));
|
||||
|
||||
newa.sa_handler = handler;
|
||||
newa.sa_handler = (__signal_func_ptr)handler;
|
||||
newa.sa_flags = SA_NOMASK | SA_RESTART;
|
||||
newa.sa_userdata = "test!";
|
||||
|
||||
if (sys_sigaction(sig, &newa, &olda) < 0) {
|
||||
printf("Failed installing handler for sig #%d!\n", sig);
|
||||
@@ -71,8 +79,8 @@ usage()
|
||||
{
|
||||
printf("usage: sig_test <mode>\n"
|
||||
"where `mode' is one of:\n"
|
||||
"\t1\tInstalls one handler for all signals\n"
|
||||
"\t2\tSame as 1 but also spawns 5 threads with no active handlers\n"
|
||||
"\t1\tInstalls one handler for all signals and spawns 5 threads\n"
|
||||
"\t2\tSame as 1 but does not spawn additional threads\n"
|
||||
"\t3\tSets an alarm via set_alarm\n"
|
||||
"\n");
|
||||
exit(1);
|
||||
|
||||
@@ -157,7 +157,7 @@ FUNCTION(i386_stack_switch):
|
||||
jmp *%edx
|
||||
|
||||
FUNCTION(i386_return_from_signal):
|
||||
popl %eax // flush the only signal handler parameter
|
||||
addl $12, %esp // Flushes the 3 arguments to sa_handler
|
||||
movl $103, %eax // This syscall will restore the cpu context to the
|
||||
movl $0, %ecx // one existing before calling the signal handler
|
||||
lea 4(%esp), %edx
|
||||
|
||||
@@ -202,63 +202,49 @@ void
|
||||
arch_setup_signal_frame(struct thread *t, struct sigaction *sa, int sig, int sig_mask)
|
||||
{
|
||||
struct iframe *frame = t->arch_info.current_iframe;
|
||||
uint32 *stack = (uint32 *)frame->user_esp;
|
||||
uint32 *code;
|
||||
uint32 *fpu_state;
|
||||
uint32 *stack_ptr = (uint32 *)frame->user_esp;
|
||||
uint32 *code_ptr;
|
||||
uint32 *regs_ptr;
|
||||
struct vregs *regs;
|
||||
|
||||
if (frame->orig_eax >= 0) {
|
||||
// we're coming from a syscall
|
||||
switch (frame->eax) {
|
||||
case ERESTARTNOHAND:
|
||||
frame->eax = EINTR;
|
||||
break;
|
||||
case EINTR:
|
||||
case ERESTARTSYS:
|
||||
if (!(sa->sa_flags & SA_RESTART)) {
|
||||
frame->eax = EINTR;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case ERESTARTNOINTR:
|
||||
dprintf("### restarting syscall %d after signal %d\n", frame->orig_eax, sig);
|
||||
frame->eax = frame->orig_eax;
|
||||
frame->edx = frame->orig_edx;
|
||||
frame->eip -= 2;
|
||||
break;
|
||||
if ((frame->eax == EINTR) && (sa->sa_flags & SA_RESTART)) {
|
||||
dprintf("### restarting syscall %d after signal %d\n", frame->orig_eax, sig);
|
||||
frame->eax = frame->orig_eax;
|
||||
frame->edx = frame->orig_edx;
|
||||
frame->eip -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
stack -= 192;
|
||||
code = stack + 25;
|
||||
fpu_state = stack + 64;
|
||||
stack_ptr -= 192;
|
||||
code_ptr = stack_ptr + 32;
|
||||
regs_ptr = stack_ptr + 64;
|
||||
|
||||
stack[0] = (uint32)code; // return address when sa_handler done
|
||||
stack[1] = sig; // only argument to sa_handler
|
||||
stack[2] = frame->gs;
|
||||
stack[3] = frame->fs;
|
||||
stack[4] = frame->es;
|
||||
stack[5] = frame->ds;
|
||||
stack[6] = frame->edi;
|
||||
stack[7] = frame->esi;
|
||||
stack[8] = frame->ebp;
|
||||
stack[9] = frame->esp;
|
||||
stack[10] = frame->ebx;
|
||||
stack[11] = frame->edx;
|
||||
stack[12] = frame->ecx;
|
||||
stack[13] = frame->eax;
|
||||
stack[18] = frame->eip;
|
||||
stack[19] = frame->cs;
|
||||
stack[20] = frame->flags;
|
||||
stack[21] = frame->user_esp;
|
||||
stack[22] = frame->user_ss;
|
||||
stack[23] = sig_mask;
|
||||
stack[24] = (uint32)fpu_state;
|
||||
stack_ptr[0] = (uint32)code_ptr; // return address when sa_handler done
|
||||
stack_ptr[1] = sig; // first argument to sa_handler
|
||||
stack_ptr[2] = (uint32)sa->sa_userdata;// second argument to sa_handler
|
||||
stack_ptr[3] = (uint32)regs_ptr; // third argument to sa_handler
|
||||
|
||||
stack_ptr[4] = sig_mask; // Old signal mask to restore
|
||||
stack_ptr[5] = (uint32)regs_ptr; // Int frame + extra regs to restore
|
||||
|
||||
i386_fsave(fpu_state);
|
||||
memcpy(code_ptr, i386_return_from_signal, (i386_end_return_from_signal - i386_return_from_signal));
|
||||
|
||||
memcpy(code, i386_return_from_signal, (i386_end_return_from_signal - i386_return_from_signal));
|
||||
regs = (struct vregs *)regs_ptr;
|
||||
regs->eip = frame->eip;
|
||||
regs->eflags = frame->flags;
|
||||
regs->eax = frame->eax;
|
||||
regs->ecx = frame->ecx;
|
||||
regs->edx = frame->edx;
|
||||
regs->esp = frame->esp;
|
||||
regs->_reserved_1 = frame->user_esp;
|
||||
regs->_reserved_2[0] = frame->edi;
|
||||
regs->_reserved_2[1] = frame->esi;
|
||||
regs->_reserved_2[2] = frame->ebp;
|
||||
i386_fsave((void *)(®s->xregs));
|
||||
|
||||
frame->user_esp = (uint32)stack;
|
||||
frame->user_esp = (uint32)stack_ptr;
|
||||
frame->eip = (uint32)sa->sa_handler;
|
||||
}
|
||||
|
||||
@@ -268,17 +254,29 @@ arch_restore_signal_frame(void)
|
||||
{
|
||||
struct thread *t = thread_get_current_thread();
|
||||
struct iframe *frame;
|
||||
uint32 fpu_state;
|
||||
uint32 *stack;
|
||||
struct vregs *regs;
|
||||
|
||||
dprintf("### arch_restore_signal_frame: entry\n");
|
||||
|
||||
frame = t->arch_info.current_iframe;
|
||||
t->sig_block_mask = *((sigset_t *)((void *)frame->user_esp + sizeof(struct iframe))) & BLOCKABLE_SIGS;
|
||||
fpu_state = *((uint32 *)((void *)frame->user_esp + sizeof(struct iframe) + sizeof(uint32)));
|
||||
|
||||
memcpy((void *)frame, (void *)frame->user_esp, sizeof(struct iframe));
|
||||
stack = (uint32 *)frame->user_esp;
|
||||
t->sig_block_mask = stack[0];
|
||||
regs = (struct vregs *)stack[1];
|
||||
|
||||
frame->eip = regs->eip;
|
||||
frame->flags = regs->eflags;
|
||||
frame->eax = regs->eax;
|
||||
frame->ecx = regs->ecx;
|
||||
frame->edx = regs->edx;
|
||||
frame->esp = regs->esp;
|
||||
frame->user_esp = regs->_reserved_1;
|
||||
frame->edi = regs->_reserved_2[0];
|
||||
frame->esi = regs->_reserved_2[1];
|
||||
frame->ebp = regs->_reserved_2[2];
|
||||
|
||||
i386_frstor((void *)fpu_state);
|
||||
i386_frstor((void *)(®s->xregs));
|
||||
|
||||
dprintf("### arch_restore_signal_frame: exit\n");
|
||||
|
||||
@@ -293,19 +291,10 @@ arch_check_syscall_restart(struct thread *t)
|
||||
{
|
||||
struct iframe *frame = t->arch_info.current_iframe;
|
||||
|
||||
dprintf("### arch_check_syscall_restart: entry\n");
|
||||
if (frame->orig_eax >= 0) {
|
||||
dprintf("### arch_check_syscall_restart: coming from a syscall\n");
|
||||
if ((frame->eax == ERESTARTNOHAND) ||
|
||||
(frame->eax == EINTR) ||
|
||||
(frame->eax == ERESTARTSYS) ||
|
||||
(frame->eax == ERESTARTNOINTR)) {
|
||||
dprintf("### arch_check_syscall_restart: syscall restart needed\n");
|
||||
frame->eax = frame->orig_eax;
|
||||
frame->edx = frame->orig_edx;
|
||||
frame->eip -= 2;
|
||||
}
|
||||
if ((frame->orig_eax >= 0) && (frame->eax == EINTR)) {
|
||||
frame->eax = frame->orig_eax;
|
||||
frame->edx = frame->orig_edx;
|
||||
frame->eip -= 2;
|
||||
}
|
||||
dprintf("### arch_check_syscall_restart: exit\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,6 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re
|
||||
break;
|
||||
case SYSCALL_EXIT_THREAD:
|
||||
sys_exit_thread((status_t)arg0);
|
||||
// thread_exit((int)arg0);
|
||||
*call_ret = 0;
|
||||
break;
|
||||
case SYSCALL_CREATE_TEAM:
|
||||
|
||||
Reference in New Issue
Block a user