posix signals support, 1st pass
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1623 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
54d6a27c67
commit
f510e6ce60
@ -60,6 +60,9 @@ status_t sys_get_next_thread_info(team_id team, int32 *cookie, thread_info *info
|
||||
status_t sys_get_team_info(team_id id, team_info *info);
|
||||
status_t sys_get_next_team_info(int32 *cookie, team_info *info);
|
||||
|
||||
int sys_kill(pid_t pid, int sig);
|
||||
int sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
|
||||
|
||||
region_id sys_vm_create_anonymous_region(const char *name, void **address, int addr_type,
|
||||
addr size, int wiring, int lock);
|
||||
region_id sys_vm_clone_region(const char *name, void **address, int addr_type,
|
||||
|
@ -21,6 +21,7 @@ extern "C" {
|
||||
#include <cbuf.h>
|
||||
#include <vm.h>
|
||||
#include <smp.h>
|
||||
#include <signal.h>
|
||||
#include <arch/thread_struct.h>
|
||||
|
||||
extern spinlock_t thread_spinlock;
|
||||
@ -101,7 +102,11 @@ struct thread {
|
||||
int state;
|
||||
int next_state;
|
||||
union cpu_ent *cpu;
|
||||
int pending_signals;
|
||||
|
||||
sigset_t sig_pending;
|
||||
sigset_t sig_block_mask;
|
||||
struct sigaction sig_action[32];
|
||||
|
||||
bool in_kernel;
|
||||
sem_id sem_blocking;
|
||||
int sem_count;
|
||||
|
@ -178,6 +178,10 @@ 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
|
||||
|
166
headers/posix/signal.h
Normal file
166
headers/posix/signal.h
Normal file
@ -0,0 +1,166 @@
|
||||
#ifndef _SIGNAL_H_
|
||||
#define _SIGNAL_H_
|
||||
|
||||
/*
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
typedef void (*__signal_func_ptr)(int);
|
||||
|
||||
__signal_func_ptr signal(int signal, __signal_func_ptr signal_func);
|
||||
int raise(int signal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SIG_DFL ((__signal_func_ptr) 0)
|
||||
#define SIG_IGN ((__signal_func_ptr) 1)
|
||||
#define SIG_ERR ((__signal_func_ptr)-1)
|
||||
|
||||
/*
|
||||
The numbering of signals for BeOS attempts to maintain
|
||||
some consistency with UN*X conventions so that things
|
||||
like "kill -9" do what you expect.
|
||||
*/
|
||||
#define SIGHUP 1 /* hangup -- tty is gone! */
|
||||
#define SIGINT 2 /* interrupt */
|
||||
#define SIGQUIT 3 /* `quit' special character typed in tty */
|
||||
#define SIGILL 4 /* illegal instruction */
|
||||
#define SIGCHLD 5 /* child process exited */
|
||||
#define SIGABRT 6 /* abort() called, dont' catch */
|
||||
#define SIGPIPE 7 /* write to a pipe w/no readers */
|
||||
#define SIGFPE 8 /* floating point exception */
|
||||
#define SIGKILL 9 /* kill a team (not catchable) */
|
||||
#define SIGSTOP 10 /* suspend a thread (not catchable) */
|
||||
#define SIGSEGV 11 /* segmentation violation (read: invalid pointer) */
|
||||
#define SIGCONT 12 /* continue execution if suspended */
|
||||
#define SIGTSTP 13 /* `stop' special character typed in tty */
|
||||
#define SIGALRM 14 /* an alarm has gone off (see alarm()) */
|
||||
#define SIGTERM 15 /* termination requested */
|
||||
#define SIGTTIN 16 /* read of tty from bg process */
|
||||
#define SIGTTOU 17 /* write to tty from bg process */
|
||||
#define SIGUSR1 18 /* app defined signal 1 */
|
||||
#define SIGUSR2 19 /* app defined signal 2 */
|
||||
#define SIGWINCH 20 /* tty window size changed */
|
||||
#define SIGKILLTHR 21 /* be specific: kill just the thread, not team */
|
||||
#define SIGTRAP 22
|
||||
|
||||
#define SIGBUS SIGSEGV /* for old style code */
|
||||
|
||||
/*
|
||||
Signal numbers 23-32 are currently free but may be used in future
|
||||
releases. Use them at your own peril (if you do use them, at least
|
||||
be smart and use them backwards from signal 32).
|
||||
*/
|
||||
#define __signal_max 22
|
||||
#define NSIG (__signal_max+1)
|
||||
|
||||
|
||||
|
||||
typedef long sigset_t;
|
||||
|
||||
/*
|
||||
The Posix interface for signal handling functions isn't as useful
|
||||
as it could be. The standard indicates that only a single argument
|
||||
(the signal number) is passed to the signal handler. It is useful
|
||||
to have more information and the BeOS provides two extra arguments.
|
||||
However, to remain compatible with Posix and ANSI C, we declare the
|
||||
sa_handler field of the sigaction struct as type __signal_func_ptr.
|
||||
That means you'll need to cast any function you assign to the
|
||||
sa_handler field. NOTE: C++ member functions can not be signal
|
||||
handlers (because they expect a "this" pointer as the first
|
||||
argument).
|
||||
|
||||
The 3 arguments that the BeOS provides to signal handlers are as
|
||||
follows:
|
||||
- The first argument is the signal number (as an integer).
|
||||
- The next argument is whatever value is put in the sa_userdata field
|
||||
of the sigaction struct.
|
||||
- The last argument is a pointer to a vregs struct (defined
|
||||
below). The vregs struct contains the contents of the volatile
|
||||
registers at the time the signal was delivered to your thread.
|
||||
You can change the fields of the structure. After your signal
|
||||
handler completes, the OS uses this struct to reload the
|
||||
registers for your thread (privileged registers are not loaded
|
||||
of course). The vregs struct is of course terribly machine
|
||||
dependent and is guaranteed to change, potentially even between
|
||||
different models of the PowerPC family. If you use it, you
|
||||
should expect to have to re-work your code when new processors
|
||||
come out. Nonetheless the ability to change the registers does
|
||||
open some interesting programming possibilities.
|
||||
*/
|
||||
struct sigaction {
|
||||
__signal_func_ptr sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void *sa_userdata; /* will be passed to the signal handler */
|
||||
};
|
||||
|
||||
|
||||
typedef struct stack_t {
|
||||
void *ss_sp;
|
||||
size_t ss_size;
|
||||
int ss_flags;
|
||||
} stack_t;
|
||||
|
||||
|
||||
#define SA_NOCLDSTOP 0x01 /* for sa_flags */
|
||||
#define SA_ONESHOT 0x02
|
||||
#define SA_NOMASK 0x04
|
||||
#define SA_NODEFER SA_NOMASK
|
||||
#define SA_RESTART 0x08
|
||||
#define SA_STACK 0x10
|
||||
|
||||
|
||||
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
|
||||
int sigemptyset(sigset_t *set);
|
||||
int sigfillset(sigset_t *set);
|
||||
int sigaddset(sigset_t *set, int signo);
|
||||
int sigdelset(sigset_t *set, int signo);
|
||||
int sigismember(const sigset_t *set, int signo);
|
||||
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
|
||||
extern const char * const sys_siglist[NSIG];
|
||||
const char *strsignal(int sig);
|
||||
const void set_signal_stack(void *ptr, size_t size);
|
||||
int sigaltstack(const stack_t *ss, stack_t *oss); /* XXXdbg */
|
||||
|
||||
extern inline int
|
||||
sigismember(const sigset_t *set, int sig)
|
||||
{
|
||||
sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ;
|
||||
return (*set & mask) ? 1 : 0 ;
|
||||
}
|
||||
extern inline int
|
||||
sigaddset(sigset_t *set, int sig)
|
||||
{
|
||||
sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ;
|
||||
return ((*set |= mask), 0) ;
|
||||
}
|
||||
extern inline int
|
||||
sigdelset(sigset_t *set, int sig)
|
||||
{
|
||||
sigset_t mask = (((sigset_t) 1) << (( sig ) - 1)) ;
|
||||
return ((*set &= ~mask), 0) ;
|
||||
}
|
||||
|
||||
#define SIG_BLOCK 1 /* defines for the how arg of sigprocmask() */
|
||||
#define SIG_UNBLOCK 2
|
||||
#define SIG_SETMASK 3
|
||||
|
||||
int sigpending(sigset_t *set);
|
||||
int sigsuspend(const sigset_t *mask);
|
||||
|
||||
int kill(pid_t pid, int sig);
|
||||
int send_signal(pid_t tid, uint sig);
|
||||
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
@ -18,6 +18,10 @@ void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void
|
||||
//struct thread *arch_thread_get_current_thread(void);
|
||||
//void arch_thread_set_current_thread(struct thread *t);
|
||||
|
||||
void arch_setup_signal_frame(struct thread *t, struct sigaction *sa, int sig, int sig_mask);
|
||||
int64 arch_restore_signal_frame(void);
|
||||
void arch_check_syscall_restart(struct thread *t);
|
||||
|
||||
// for any inline overrides
|
||||
#include <arch_thread.h>
|
||||
|
||||
|
@ -95,6 +95,8 @@ struct iframe {
|
||||
unsigned int edx;
|
||||
unsigned int ecx;
|
||||
unsigned int eax;
|
||||
unsigned int orig_eax;
|
||||
unsigned int orig_edx;
|
||||
unsigned int vector;
|
||||
unsigned int error_code;
|
||||
unsigned int eip;
|
||||
@ -112,6 +114,10 @@ void i386_enter_uspace(addr entry, void *args, addr ustack_top);
|
||||
void i386_set_kstack(addr kstack);
|
||||
void i386_switch_stack_and_call(addr stack, void (*func)(void *), void *arg);
|
||||
void i386_swap_pgdir(addr new_pgdir);
|
||||
void i386_fsave(void *fpu_state);
|
||||
void i386_fxsave(void *fpu_state);
|
||||
void i386_frstor(void *fpu_state);
|
||||
void i386_fxrstor(void *fpu_state);
|
||||
void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state);
|
||||
void i386_fxsave_swap(void *old_fpu_state, void *new_fpu_state);
|
||||
|
||||
|
@ -15,6 +15,9 @@ extern "C" {
|
||||
void i386_push_iframe(struct thread *t, struct iframe *frame);
|
||||
void i386_pop_iframe(struct thread *t);
|
||||
|
||||
void i386_return_from_signal();
|
||||
void i386_end_return_from_signal();
|
||||
|
||||
|
||||
static
|
||||
inline struct thread *
|
||||
|
@ -18,6 +18,7 @@ struct arch_thread {
|
||||
struct farcall interrupt_stack;
|
||||
|
||||
// used to track interrupts on this thread
|
||||
struct iframe *current_iframe;
|
||||
struct iframe *iframes[IFRAME_TRACE_DEPTH];
|
||||
int iframe_ptr;
|
||||
|
||||
|
@ -11,6 +11,7 @@ extern "C" {
|
||||
|
||||
#include <thread_types.h>
|
||||
#include <arch/thread.h>
|
||||
#include <signal.h>
|
||||
|
||||
// Uncomment the line below to compile the single-queue scheduler
|
||||
//#define NEW_SCHEDULER
|
||||
@ -18,6 +19,10 @@ extern "C" {
|
||||
void resched(void);
|
||||
void start_scheduler(void);
|
||||
|
||||
#define BLOCKABLE_SIGS (~((1L << (SIGKILL - 1)) | (1L << (SIGSTOP - 1))))
|
||||
|
||||
void handle_signals(struct thread *t, int state);
|
||||
|
||||
void thread_enqueue(struct thread *t, struct thread_queue *q);
|
||||
struct thread *thread_lookat_queue(struct thread_queue *q);
|
||||
struct thread *thread_dequeue(struct thread_queue *q);
|
||||
@ -45,9 +50,7 @@ int thread_kill_thread_nowait(thread_id id);
|
||||
#define thread_get_current_thread arch_thread_get_current_thread
|
||||
|
||||
struct thread *thread_get_thread_struct(thread_id id);
|
||||
#ifdef NEW_SCHEDULER
|
||||
struct thread *thread_get_thread_struct_locked(thread_id id);
|
||||
#endif /* NEW_SCHEDULER */
|
||||
|
||||
static thread_id thread_get_current_thread_id(void);
|
||||
static inline thread_id
|
||||
@ -98,6 +101,8 @@ int user_setrlimit(int resource, const struct rlimit * rlp);
|
||||
int user_setenv(const char *name, const char *value, int overwrite);
|
||||
int user_getenv(const char *name, char **value);
|
||||
|
||||
int user_sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
|
||||
|
||||
#if 1
|
||||
// XXX remove later
|
||||
int thread_test(void);
|
||||
|
@ -113,6 +113,7 @@ KernelLd kernel
|
||||
<$(SOURCE_GRIST)!core>queue.o
|
||||
<$(SOURCE_GRIST)!core>scheduler.o
|
||||
<$(SOURCE_GRIST)!core>sem.o
|
||||
<$(SOURCE_GRIST)!core>signal.o
|
||||
<$(SOURCE_GRIST)!core>smp.o
|
||||
<$(SOURCE_GRIST)!core>syscalls.o
|
||||
<$(SOURCE_GRIST)!core>sysctl.o
|
||||
@ -159,6 +160,7 @@ KernelLd kernel.so
|
||||
<$(SOURCE_GRIST)!core>queue.o
|
||||
<$(SOURCE_GRIST)!core>scheduler.o
|
||||
<$(SOURCE_GRIST)!core>sem.o
|
||||
<$(SOURCE_GRIST)!core>signal.o
|
||||
<$(SOURCE_GRIST)!core>smp.o
|
||||
<$(SOURCE_GRIST)!core>syscalls.o
|
||||
<$(SOURCE_GRIST)!core>sysctl.o
|
||||
@ -576,6 +578,18 @@ KernelLd fibo :
|
||||
bin/fibo
|
||||
;
|
||||
|
||||
KernelLd sig_test :
|
||||
libglue2.o
|
||||
<$(SOURCE_GRIST)!apps>sig_test.o
|
||||
libroot.so
|
||||
:
|
||||
$(SUBDIR)/ldscripts/$(OBOS_ARCH)/app.ld
|
||||
:
|
||||
:
|
||||
:
|
||||
bin/sig_test
|
||||
;
|
||||
|
||||
KernelLd fortune :
|
||||
libglue2.o
|
||||
<$(SOURCE_GRIST)!apps!fortune>main.o
|
||||
|
@ -1,6 +1,6 @@
|
||||
SubDir OBOS_TOP src kernel apps ;
|
||||
|
||||
KernelObjects false_main.c fibo_main.c init.c true_main.c ;
|
||||
KernelObjects false_main.c fibo_main.c init.c true_main.c sig_test.c ;
|
||||
|
||||
SubInclude OBOS_TOP src kernel apps cpuinfo ;
|
||||
SubInclude OBOS_TOP src kernel apps echo ;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <syscalls.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@ -21,6 +22,7 @@ struct command cmds[] = {
|
||||
{"cat", &cmd_cat},
|
||||
{"cd", &cmd_cd},
|
||||
{"pwd", &cmd_pwd},
|
||||
{"kill", &cmd_kill},
|
||||
{"help", &cmd_help},
|
||||
{NULL, NULL}
|
||||
};
|
||||
@ -185,6 +187,20 @@ int cmd_stat(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_kill(int argc, char *argv[])
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("not enough arguments to kill\n");
|
||||
return 0;
|
||||
}
|
||||
rc = sys_kill(atoi(argv[2]), atoi(argv[1]));
|
||||
if (rc)
|
||||
printf("kill failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_help(int argc, char *argv[])
|
||||
{
|
||||
printf("command list:\n\n");
|
||||
@ -198,6 +214,7 @@ int cmd_help(int argc, char *argv[])
|
||||
printf("cat <file> : dumps the file to stdout\n");
|
||||
printf("mount <path> <device> <fsname> : tries to mount <device> at <path>\n");
|
||||
printf("unmount <path> : tries to unmount at <path>\n");
|
||||
printf("kill <sig> <tid> : sends signal <sig> to thread <tid>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ int cmd_mkdir(int argc, char *argv[]);
|
||||
int cmd_cat(int argc, char *argv[]);
|
||||
int cmd_cd(int argc, char *argv[]);
|
||||
int cmd_pwd(int argc, char *argv[]);
|
||||
int cmd_kill(int argc, char *argv[]);
|
||||
int cmd_help(int argc, char *argv[]);
|
||||
int cmd_create_proc(int argc,char *argv[]);
|
||||
typedef int(cmd_handler_proc)(int argc,char *argv[]);
|
||||
|
80
src/kernel/apps/sig_test.c
Normal file
80
src/kernel/apps/sig_test.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
** Small test for signals handling
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <syscalls.h>
|
||||
|
||||
|
||||
void sig_handler(int);
|
||||
void install_handler(int);
|
||||
int32 thread(void *);
|
||||
|
||||
|
||||
void
|
||||
sig_handler(int sig)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("sig_test (sig_handler): Received signal #%d...\n", sig);
|
||||
printf("Counting for fun: ");
|
||||
for (i=0; i<10; i++)
|
||||
printf("%d ", i);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
install_handler(int sig)
|
||||
{
|
||||
struct sigaction newa;
|
||||
struct sigaction olda;
|
||||
|
||||
memset(&newa, 0, sizeof(newa));
|
||||
|
||||
newa.sa_handler = sig_handler;
|
||||
newa.sa_flags = SA_NOMASK | SA_RESTART;
|
||||
|
||||
if (sys_sigaction(sig, &newa, &olda) < 0) {
|
||||
printf("Failed installing handler for sig #%d!\n", sig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
thread(void *data)
|
||||
{
|
||||
printf("Started snoozing thread...\n");
|
||||
while (1) {
|
||||
if (snooze(1000000000L) == B_INTERRUPTED)
|
||||
printf("sig_test (thread): snooze was interrupted!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("Installing signal handlers...\n");
|
||||
for (i=1; i<=NSIG; i++)
|
||||
install_handler(i);
|
||||
printf("Spawning some threads...\n");
|
||||
for (i=0; i<5; i++)
|
||||
resume_thread(spawn_thread(thread, "sig_test aux thread", B_NORMAL_PRIORITY, NULL));
|
||||
printf("Done. Entering sleep mode...\n");
|
||||
while (1) {
|
||||
if (sys_snooze(1000000000L) == B_INTERRUPTED)
|
||||
// this never gets called as the syscall is always restarted
|
||||
printf("sig_test (main): snooze was interrupted!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ KernelObjects
|
||||
<$(SOURCE_GRIST)>port.c
|
||||
<$(SOURCE_GRIST)>queue.c
|
||||
<$(SOURCE_GRIST)>scheduler.c
|
||||
<$(SOURCE_GRIST)>sem.c
|
||||
<$(SOURCE_GRIST)>sem.c
|
||||
<$(SOURCE_GRIST)>signal.c
|
||||
<$(SOURCE_GRIST)>smp.c
|
||||
<$(SOURCE_GRIST)>syscalls.c
|
||||
<$(SOURCE_GRIST)>sysctl.c
|
||||
|
@ -165,8 +165,10 @@ i386_handle_trap(struct iframe frame)
|
||||
int ret = B_HANDLED_INTERRUPT;
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
if (thread)
|
||||
if (thread) {
|
||||
i386_push_iframe(thread, &frame);
|
||||
thread->arch_info.current_iframe = &frame;
|
||||
}
|
||||
|
||||
// if(frame.vector != 0x20)
|
||||
// dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());
|
||||
@ -249,7 +251,7 @@ i386_handle_trap(struct iframe frame)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (ret == B_INVOKE_SCHEDULER) {
|
||||
int state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
@ -261,6 +263,7 @@ i386_handle_trap(struct iframe frame)
|
||||
if (frame.cs == USER_CODE_SEG || frame.vector == 99) {
|
||||
thread_atkernel_exit();
|
||||
}
|
||||
|
||||
// dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu());
|
||||
|
||||
if (thread)
|
||||
|
@ -15,6 +15,8 @@
|
||||
.align 8; \
|
||||
name: \
|
||||
pushl $vector; \
|
||||
pushl $-1; \
|
||||
pushl $-1; \
|
||||
jmp int_bottom
|
||||
|
||||
#define TRAP(name, vector) \
|
||||
@ -23,6 +25,8 @@ name: \
|
||||
name: \
|
||||
pushl $0; \
|
||||
pushl $vector; \
|
||||
pushl %edx; \
|
||||
pushl %eax; \
|
||||
jmp int_bottom
|
||||
|
||||
TRAP(trap0, 0)
|
||||
@ -92,7 +96,7 @@ int_bottom:
|
||||
pop %es
|
||||
pop %ds
|
||||
popa
|
||||
addl $8,%esp
|
||||
addl $16,%esp
|
||||
iret
|
||||
|
||||
// custom stack -> copy registers to kernel stack and switch there
|
||||
@ -102,22 +106,22 @@ int_bottom:
|
||||
addl _interrupt_stack_offset,%edx
|
||||
lss (%edx),%esp
|
||||
movl %ebx,%ds
|
||||
subl $84,%esp
|
||||
subl $92,%esp
|
||||
movl %esp,%edi
|
||||
movl $19,%ecx
|
||||
movl $21,%ecx
|
||||
rep movsl
|
||||
movl %eax,%ds
|
||||
subl $76,%esi
|
||||
subl $84,%esi
|
||||
movl %esi,(%edi) // save custom stack address
|
||||
movl %ebx,4(%edi)
|
||||
call i386_handle_trap
|
||||
lss 76(%esp),%esp // reload custom stack address
|
||||
lss 84(%esp),%esp // reload custom stack address
|
||||
pop %gs
|
||||
pop %fs
|
||||
pop %es
|
||||
pop %ds
|
||||
popa
|
||||
addl $8,%esp
|
||||
addl $16,%esp
|
||||
iret
|
||||
|
||||
_interrupt_stack_offset:
|
||||
@ -151,3 +155,13 @@ FUNCTION(i386_stack_switch):
|
||||
pushl %ecx
|
||||
popf
|
||||
jmp *%edx
|
||||
|
||||
FUNCTION(i386_return_from_signal):
|
||||
popl %eax // flush the only signal handler parameter
|
||||
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
|
||||
int $99
|
||||
ret
|
||||
FUNCTION(i386_end_return_from_signal):
|
||||
|
||||
|
@ -10,8 +10,11 @@
|
||||
#include <memheap.h>
|
||||
#include <thread.h>
|
||||
#include <arch/thread.h>
|
||||
#include <arch_cpu.h>
|
||||
#include <int.h>
|
||||
#include <string.h>
|
||||
#include <Errors.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
// from arch_interrupts.S
|
||||
@ -194,3 +197,115 @@ arch_thread_enter_uspace(addr entry, void *args, addr ustack_top)
|
||||
i386_enter_uspace(entry, args, ustack_top - 4);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
stack -= 192;
|
||||
code = stack + 25;
|
||||
fpu_state = stack + 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;
|
||||
|
||||
i386_fsave(fpu_state);
|
||||
|
||||
memcpy(code, i386_return_from_signal, (i386_end_return_from_signal - i386_return_from_signal));
|
||||
|
||||
frame->user_esp = (uint32)stack;
|
||||
frame->eip = (uint32)sa->sa_handler;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_signal_frame(void)
|
||||
{
|
||||
struct thread *t = thread_get_current_thread();
|
||||
struct iframe *frame;
|
||||
uint32 fpu_state;
|
||||
|
||||
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));
|
||||
|
||||
i386_frstor((void *)fpu_state);
|
||||
|
||||
dprintf("### arch_restore_signal_frame: exit\n");
|
||||
|
||||
frame->orig_eax = -1; /* disable syscall checks */
|
||||
|
||||
return (int64)frame->eax | ((int64)frame->edx << 32);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
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;
|
||||
}
|
||||
}
|
||||
dprintf("### arch_check_syscall_restart: exit\n");
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,30 @@ FUNCTION(arch_cpu_global_TLB_invalidate):
|
||||
movl %eax,%cr3
|
||||
ret
|
||||
|
||||
/* void i386_fsave(void *fpu_state); */
|
||||
FUNCTION(i386_fsave):
|
||||
movl 4(%esp), %eax
|
||||
fsave (%eax)
|
||||
ret
|
||||
|
||||
/* void i386_fxsave(void *fpu_state); */
|
||||
FUNCTION(i386_fxsave):
|
||||
movl 4(%esp), %eax
|
||||
fxsave (%eax)
|
||||
ret
|
||||
|
||||
/* void i386_frstor(void *fpu_state); */
|
||||
FUNCTION(i386_frstor):
|
||||
movl 4(%esp), %eax
|
||||
frstor (%eax)
|
||||
ret
|
||||
|
||||
/* void i386_fxrstor(void *fpu_state); */
|
||||
FUNCTION(i386_fxrstor):
|
||||
movl 4(%esp), %eax
|
||||
fxrstor (%eax)
|
||||
ret
|
||||
|
||||
/* void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state); */
|
||||
FUNCTION(i386_fsave_swap):
|
||||
movl 4(%esp),%eax
|
||||
|
@ -401,9 +401,9 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
||||
|
||||
TRACE_BLOCK(("acquire_sem_etc(id = %ld): block name = %s, thread = %p, name = %s\n", id, gSems[slot].name, t, t->name));
|
||||
|
||||
// do a quick check to see if the thread has any pending kill signals
|
||||
// do a quick check to see if the thread has any pending signals
|
||||
// this should catch most of the cases where the thread had a signal
|
||||
if ((flags & B_CAN_INTERRUPT) && (t->pending_signals & SIG_KILL)) {
|
||||
if ((flags & B_CAN_INTERRUPT) && t->sig_pending) {
|
||||
gSems[slot].count += count;
|
||||
status = B_INTERRUPTED;
|
||||
goto err;
|
||||
@ -436,9 +436,9 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
||||
|
||||
RELEASE_SEM_LOCK(gSems[slot]);
|
||||
GRAB_THREAD_LOCK();
|
||||
// check again to see if a kill signal is pending.
|
||||
// check again to see if a signal is pending.
|
||||
// it may have been delivered while setting up the sem, though it's pretty unlikely
|
||||
if ((flags & B_CAN_INTERRUPT) && (t->pending_signals & SIG_KILL)) {
|
||||
if ((flags & B_CAN_INTERRUPT) && t->sig_pending) {
|
||||
struct thread_queue wakeup_queue;
|
||||
// ok, so a tiny race happened where a signal was delivered to this thread while
|
||||
// it was setting up the sem. We can only be sure a signal wasn't delivered
|
||||
@ -768,6 +768,8 @@ sem_interrupt_thread(struct thread *t)
|
||||
if ((t->sem_flags & B_CAN_INTERRUPT) == 0)
|
||||
return ERR_SEM_NOT_INTERRUPTABLE;
|
||||
|
||||
t->next_state = B_THREAD_READY;
|
||||
|
||||
slot = t->sem_blocking % MAX_SEMS;
|
||||
|
||||
GRAB_SEM_LOCK(gSems[slot]);
|
||||
|
249
src/kernel/core/signal.c
Normal file
249
src/kernel/core/signal.c
Normal file
@ -0,0 +1,249 @@
|
||||
/* POSIX signals handling routines
|
||||
**
|
||||
** Copyright 2002, Angelo Mottola, a.mottola@libero.it. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <debug.h>
|
||||
#include <thread.h>
|
||||
#include <arch/thread.h>
|
||||
#include <int.h>
|
||||
#include <sem.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <syscalls.h>
|
||||
|
||||
|
||||
const char * const sys_siglist[NSIG] = {
|
||||
"NONE", "HUP", "INT", "QUIT", "ILL", "CHLD", "ABRT", "PIPE",
|
||||
"FPE", "KILL", "STOP", "SEGV", "CONT", "TSTP", "ALRM", "TERM",
|
||||
"TTIN", "TTOU", "USR1", "USR2", "WINCH", "KILLTHR", "TRAP"
|
||||
};
|
||||
|
||||
|
||||
// Expects interrupts off and thread lock held.
|
||||
void
|
||||
handle_signals(struct thread *t, int state)
|
||||
{
|
||||
uint32 sig_mask = t->sig_pending & (~t->sig_block_mask);
|
||||
int i, sig;
|
||||
struct sigaction *handler;
|
||||
|
||||
if (sig_mask) {
|
||||
for (i = 0; i < NSIG; i++) {
|
||||
if (sig_mask & 0x1) {
|
||||
|
||||
sig = i + 1;
|
||||
handler = &t->sig_action[i];
|
||||
sig_mask >>= 1;
|
||||
t->sig_pending &= ~(1L << i);
|
||||
|
||||
dprintf("Thread 0x%lx received signal %s\n", t->id, sys_siglist[sig]);
|
||||
|
||||
if (handler->sa_handler == SIG_IGN) {
|
||||
// signal is to be ignored
|
||||
// XXX apply zombie cleaning on SIGCHLD
|
||||
continue;
|
||||
}
|
||||
if (handler->sa_handler == SIG_DFL) {
|
||||
// default signal behaviour
|
||||
switch (sig) {
|
||||
case SIGCHLD:
|
||||
case SIGWINCH:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGCONT:
|
||||
continue;
|
||||
|
||||
case SIGSTOP:
|
||||
t->next_state = B_THREAD_SUSPENDED;
|
||||
continue;
|
||||
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
case SIGABRT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
dprintf("Shutting down thread 0x%lx due to signal #%d\n", t->id, sig);
|
||||
case SIGKILL:
|
||||
case SIGKILLTHR:
|
||||
default:
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
thread_exit(sig);
|
||||
}
|
||||
}
|
||||
|
||||
// User defined signal handler
|
||||
dprintf("### Setting up custom signal handler frame...\n");
|
||||
arch_setup_signal_frame(t, handler, sig, t->sig_block_mask);
|
||||
|
||||
if (handler->sa_flags & SA_ONESHOT)
|
||||
handler->sa_handler = SIG_DFL;
|
||||
if (!(handler->sa_flags & SA_NOMASK))
|
||||
t->sig_block_mask |= (handler->sa_mask | (1L << sig)) & BLOCKABLE_SIGS;
|
||||
|
||||
return;
|
||||
} else
|
||||
sig_mask >>= 1;
|
||||
}
|
||||
arch_check_syscall_restart(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
send_signal_etc(pid_t tid, uint sig, uint32 flags)
|
||||
{
|
||||
int state;
|
||||
struct thread *t, *main_t;
|
||||
|
||||
if ((sig < 1) || (sig > 32))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t = thread_get_thread_struct_locked(tid);
|
||||
if (!t) {
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
return B_BAD_THREAD_ID;
|
||||
}
|
||||
// XXX check permission
|
||||
|
||||
// Signals to kernel threads will only wake them up
|
||||
if (t->team == team_get_kernel_team()) {
|
||||
if (t->state == B_THREAD_SUSPENDED) {
|
||||
t->state = t->next_state = B_THREAD_READY;
|
||||
thread_enqueue_run_q(t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
t->sig_pending |= (1L << (sig - 1));
|
||||
|
||||
switch (sig) {
|
||||
case SIGKILL:
|
||||
// Forward KILLTHR to the main thread of the team
|
||||
main_t = t->team->main_thread;
|
||||
main_t->sig_pending |= (1L << (SIGKILLTHR - 1));
|
||||
// Wake up main thread
|
||||
if (main_t->state == B_THREAD_SUSPENDED) {
|
||||
main_t->state = main_t->next_state = B_THREAD_READY;
|
||||
thread_enqueue_run_q(main_t);
|
||||
} else if (main_t->state == B_THREAD_WAITING)
|
||||
sem_interrupt_thread(main_t);
|
||||
// Fallthrough
|
||||
case SIGKILLTHR:
|
||||
// Wake up suspended threads and interrupt waiting ones
|
||||
if (t->state == B_THREAD_SUSPENDED) {
|
||||
t->state = t->next_state = B_THREAD_READY;
|
||||
thread_enqueue_run_q(t);
|
||||
} else if (t->state == B_THREAD_WAITING)
|
||||
sem_interrupt_thread(t);
|
||||
break;
|
||||
case SIGCONT:
|
||||
// Wake up thread if it was suspended
|
||||
if ((t->state == B_THREAD_READY) ||
|
||||
(t->state == B_THREAD_SUSPENDED)) {
|
||||
t->state = t->next_state = B_THREAD_READY;
|
||||
thread_enqueue_run_q(t);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (t->sig_pending & ((~t->sig_block_mask) | (1L << (SIGCHLD - 1)))) {
|
||||
// Interrupt thread if it was waiting
|
||||
if (t->state == B_THREAD_WAITING)
|
||||
sem_interrupt_thread(t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & B_DO_NOT_RESCHEDULE))
|
||||
resched();
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
has_signals_pending(struct thread *t)
|
||||
{
|
||||
if (!t)
|
||||
t = thread_get_current_thread();
|
||||
return (t->sig_pending & ~t->sig_block_mask);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sys_kill(pid_t tid, int sig)
|
||||
{
|
||||
return send_signal_etc(tid, sig, 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
user_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
{
|
||||
struct sigaction kact;
|
||||
struct sigaction koact;
|
||||
int rc;
|
||||
|
||||
if ((!act) || (!oact))
|
||||
return EINVAL;
|
||||
|
||||
rc = user_memcpy(&kact, act, sizeof(struct sigaction));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = user_memcpy(&koact, oact, sizeof(struct sigaction));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = sys_sigaction(sig, &kact, &koact);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = user_memcpy(oact, &koact, sizeof(struct sigaction));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
{
|
||||
struct thread *t;
|
||||
int state;
|
||||
|
||||
if ((sig < 1) || (sig > 32))
|
||||
return EINVAL;
|
||||
if ((sig == SIGKILL) || (sig == SIGKILLTHR) || (sig == SIGSTOP))
|
||||
return EINVAL;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t = thread_get_current_thread();
|
||||
|
||||
memcpy(oact, &t->sig_action[sig - 1], sizeof(struct sigaction));
|
||||
memcpy(&t->sig_action[sig - 1], act, sizeof(struct sigaction));
|
||||
|
||||
if (act->sa_handler == SIG_IGN)
|
||||
t->sig_pending &= ~(1L << (sig - 1));
|
||||
else if (act->sa_handler == SIG_DFL) {
|
||||
if ((sig == SIGCONT) || (sig == SIGCHLD) || (sig == SIGWINCH))
|
||||
t->sig_pending &= ~(1L << (sig - 1));
|
||||
}
|
||||
else
|
||||
dprintf("### custom signal handler set\n");
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <kernel.h>
|
||||
#include <ksyscalls.h>
|
||||
#include <syscalls.h>
|
||||
#include <int.h>
|
||||
#include <arch/int.h>
|
||||
#include <debug.h>
|
||||
@ -385,6 +386,15 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re
|
||||
case SYSCALL_GET_NEXT_TEAM_INFO:
|
||||
*call_ret = user_get_next_team_info((int32 *)arg0, (team_info *)arg1);
|
||||
break;
|
||||
case SYSCALL_RETURN_FROM_SIGNAL:
|
||||
*call_ret = arch_restore_signal_frame();
|
||||
break;
|
||||
case SYSCALL_KILL:
|
||||
*call_ret = sys_kill((pid_t)arg0, (int)arg1);
|
||||
break;
|
||||
case SYSCALL_SIGACTION:
|
||||
*call_ret = user_sigaction((int)arg0, (const struct sigaction *)arg1, (struct sigaction *)arg2);
|
||||
break;
|
||||
default:
|
||||
*call_ret = -1;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Threading and team information */
|
||||
/* Threading routines */
|
||||
|
||||
/*
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
@ -75,11 +75,8 @@ static struct thread_queue run_q[(B_MAX_PRIORITY / 2) + 1] = { { NULL, NULL }, }
|
||||
struct thread_queue dead_q;
|
||||
|
||||
static void thread_entry(void);
|
||||
#ifndef NEW_SCHEDULER
|
||||
static struct thread *thread_get_thread_struct_locked(thread_id id);
|
||||
#endif /* not NEW_SCHEDULER */
|
||||
static void thread_kthread_exit(void);
|
||||
static void deliver_signal(struct thread *t, int signal);
|
||||
//static void deliver_signal(struct thread *t, int signal);
|
||||
|
||||
|
||||
// insert a thread onto the tail of a queue
|
||||
@ -266,11 +263,13 @@ create_thread_struct(const char *name)
|
||||
t->q_next = NULL;
|
||||
t->priority = -1;
|
||||
t->args = NULL;
|
||||
t->pending_signals = SIG_NONE;
|
||||
t->sig_pending = 0;
|
||||
t->sig_block_mask = 0;
|
||||
memset(t->sig_action, 0, 32 * sizeof(struct sigaction));
|
||||
t->in_kernel = true;
|
||||
t->user_time = 0;
|
||||
t->kernel_time = 0;
|
||||
t->last_time = 0;
|
||||
t->last_time = 0;
|
||||
|
||||
sprintf(temp, "thread_0x%lx_retcode_sem", t->id);
|
||||
t->return_code_sem = create_sem(0, temp);
|
||||
@ -326,7 +325,9 @@ _create_user_thread_kentry(void)
|
||||
t = thread_get_current_thread();
|
||||
|
||||
// a signal may have been delivered here
|
||||
thread_atkernel_exit();
|
||||
// thread_atkernel_exit();
|
||||
t->last_time = system_time();
|
||||
t->in_kernel = false;
|
||||
|
||||
// jump to the entry point in user space
|
||||
arch_thread_enter_uspace((addr)t->entry, t->args, t->user_stack_base + STACK_SIZE);
|
||||
@ -343,7 +344,9 @@ _create_kernel_thread_kentry(void)
|
||||
struct thread *t;
|
||||
|
||||
t = thread_get_current_thread();
|
||||
|
||||
|
||||
t->last_time = system_time();
|
||||
|
||||
// call the entry function with the appropriate args
|
||||
func = (void *)t->entry;
|
||||
|
||||
@ -466,70 +469,22 @@ thread_create_kernel_thread_etc(const char *name, int (*func)(void *), void *arg
|
||||
int
|
||||
thread_suspend_thread(thread_id id)
|
||||
{
|
||||
int state;
|
||||
struct thread *t;
|
||||
int retval;
|
||||
bool global_resched = false;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t = thread_get_current_thread();
|
||||
if (t->id != id) {
|
||||
t = thread_get_thread_struct_locked(id);
|
||||
}
|
||||
|
||||
if (t != NULL) {
|
||||
if (t->team == team_get_kernel_team()) {
|
||||
// no way
|
||||
retval = EPERM;
|
||||
} else if (t->in_kernel == true) {
|
||||
t->pending_signals |= SIG_SUSPEND;
|
||||
retval = B_NO_ERROR;
|
||||
} else {
|
||||
t->next_state = B_THREAD_SUSPENDED;
|
||||
global_resched = true;
|
||||
retval = B_NO_ERROR;
|
||||
}
|
||||
} else
|
||||
retval = ERR_INVALID_HANDLE;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
if (global_resched)
|
||||
int rv;
|
||||
|
||||
rv = send_signal_etc(id, SIGSTOP, B_DO_NOT_RESCHEDULE);
|
||||
if (rv == B_OK)
|
||||
smp_send_broadcast_ici(SMP_MSG_RESCHEDULE, 0, 0, 0, NULL, SMP_MSG_FLAG_SYNC);
|
||||
|
||||
return retval;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
thread_resume_thread(thread_id id)
|
||||
{
|
||||
int state;
|
||||
struct thread *t;
|
||||
int retval;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t = thread_get_thread_struct_locked(id);
|
||||
if (t != NULL && t->state == B_THREAD_SUSPENDED) {
|
||||
t->state = B_THREAD_READY;
|
||||
t->next_state = B_THREAD_READY;
|
||||
|
||||
thread_enqueue_run_q(t);
|
||||
retval = B_NO_ERROR;
|
||||
} else
|
||||
retval = ERR_INVALID_HANDLE;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
|
||||
return retval;
|
||||
return send_signal_etc(id, SIGCONT, B_DO_NOT_RESCHEDULE);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NEW_SCHEDULER
|
||||
status_t
|
||||
thread_set_priority(thread_id id, int32 priority)
|
||||
@ -614,7 +569,7 @@ _dump_thread_info(struct thread *t)
|
||||
dprintf("(%d)\n", t->cpu->info.cpu_num);
|
||||
else
|
||||
dprintf("\n");
|
||||
dprintf("pending_signals: 0x%x\n", t->pending_signals);
|
||||
dprintf("sig_pending: 0x%lx\n", t->sig_pending);
|
||||
dprintf("in_kernel: %d\n", t->in_kernel);
|
||||
dprintf("sem_blocking:0x%lx\n", t->sem_blocking);
|
||||
dprintf("sem_count: 0x%x\n", t->sem_count);
|
||||
@ -1072,13 +1027,7 @@ thread_exit(int retcode)
|
||||
}
|
||||
RELEASE_TEAM_LOCK();
|
||||
restore_interrupts(state);
|
||||
#if 0
|
||||
// Now wait for all of the threads to die
|
||||
// XXX block on a semaphore
|
||||
while((volatile int)p->num_threads > 0) {
|
||||
snooze(10000); // 10 ms
|
||||
}
|
||||
#endif
|
||||
// wait until all threads in team are dead.
|
||||
acquire_sem_etc(p->death_sem, p->num_threads, 0, 0);
|
||||
delete_sem(p->death_sem);
|
||||
}
|
||||
@ -1125,55 +1074,25 @@ thread_exit(int retcode)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_thread_kill_thread(thread_id id, bool wait_on)
|
||||
{
|
||||
int state;
|
||||
struct thread *t;
|
||||
int rc;
|
||||
|
||||
// dprintf("_thread_kill_thread: id %d, wait_on %d\n", id, wait_on);
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t = thread_get_thread_struct_locked(id);
|
||||
if (t != NULL) {
|
||||
if (t->team == team_get_kernel_team()) {
|
||||
// can't touch this
|
||||
rc = EPERM;
|
||||
} else {
|
||||
deliver_signal(t, SIG_KILL);
|
||||
rc = B_NO_ERROR;
|
||||
if (t->id == thread_get_current_thread()->id)
|
||||
wait_on = false; // can't wait on ourself
|
||||
}
|
||||
} else
|
||||
rc = ERR_INVALID_HANDLE;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (wait_on)
|
||||
thread_wait_on_thread(id, NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
thread_kill_thread(thread_id id)
|
||||
{
|
||||
return _thread_kill_thread(id, true);
|
||||
int rv;
|
||||
|
||||
rv = send_signal_etc(id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
if (id != thread_get_current_thread()->id)
|
||||
thread_wait_on_thread(id, NULL);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
thread_kill_thread_nowait(thread_id id)
|
||||
{
|
||||
return _thread_kill_thread(id, false);
|
||||
return send_signal_etc(id, SIGKILLTHR, B_DO_NOT_RESCHEDULE);
|
||||
}
|
||||
|
||||
|
||||
@ -1192,6 +1111,10 @@ thread_wait_on_thread(thread_id id, int *retcode)
|
||||
struct thread *t;
|
||||
int rc;
|
||||
|
||||
rc = send_signal_etc(id, SIGCONT, 0);
|
||||
if (rc != B_OK)
|
||||
return rc;
|
||||
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
@ -1199,7 +1122,7 @@ thread_wait_on_thread(thread_id id, int *retcode)
|
||||
if (t != NULL) {
|
||||
sem = t->return_code_sem;
|
||||
} else {
|
||||
sem = ERR_INVALID_HANDLE;
|
||||
sem = B_BAD_THREAD_ID;
|
||||
}
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
@ -1244,11 +1167,9 @@ thread_get_thread_struct(thread_id id)
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifndef NEW_SCHEDULER
|
||||
static struct thread *thread_get_thread_struct_locked(thread_id id)
|
||||
#else /* NEW_SCHEDULER */
|
||||
struct thread *thread_get_thread_struct_locked(thread_id id)
|
||||
#endif /* NEW_SCHEDULER */
|
||||
|
||||
struct thread *
|
||||
thread_get_thread_struct_locked(thread_id id)
|
||||
{
|
||||
struct thread_key key;
|
||||
|
||||
@ -1258,61 +1179,6 @@ struct thread *thread_get_thread_struct_locked(thread_id id)
|
||||
}
|
||||
|
||||
|
||||
// sets the pending signal flag on a thread and possibly does some work to wake it up, etc.
|
||||
// expects the thread lock to be held
|
||||
|
||||
static void
|
||||
deliver_signal(struct thread *t, int signal)
|
||||
{
|
||||
// dprintf("deliver_signal: thread %p (%d), signal %d\n", t, t->id, signal);
|
||||
switch (signal) {
|
||||
case SIG_KILL:
|
||||
t->pending_signals |= SIG_KILL;
|
||||
switch (t->state) {
|
||||
case B_THREAD_SUSPENDED:
|
||||
t->state = B_THREAD_READY;
|
||||
t->next_state = B_THREAD_READY;
|
||||
|
||||
thread_enqueue_run_q(t);
|
||||
break;
|
||||
case B_THREAD_WAITING:
|
||||
sem_interrupt_thread(t);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
t->pending_signals |= signal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// expects the thread lock to be held
|
||||
|
||||
static void
|
||||
_check_for_thread_sigs(struct thread *t, int state)
|
||||
{
|
||||
if (t->pending_signals == SIG_NONE)
|
||||
return;
|
||||
|
||||
if (t->pending_signals & SIG_KILL) {
|
||||
t->pending_signals &= ~SIG_KILL;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
thread_exit(0);
|
||||
// never gets to here
|
||||
}
|
||||
if (t->pending_signals & SIG_SUSPEND) {
|
||||
t->pending_signals &= ~SIG_SUSPEND;
|
||||
t->next_state = B_THREAD_SUSPENDED;
|
||||
// XXX will probably want to delay this
|
||||
resched();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// called in the int handler code when a thread enters the kernel for any reason
|
||||
|
||||
void
|
||||
@ -1333,13 +1199,8 @@ thread_atkernel_entry(void)
|
||||
t->user_time += now - t->last_time;
|
||||
t->last_time = now;
|
||||
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
t->in_kernel = true;
|
||||
|
||||
_check_for_thread_sigs(t, state);
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
restore_interrupts(state);
|
||||
}
|
||||
|
||||
@ -1360,7 +1221,7 @@ thread_atkernel_exit(void)
|
||||
state = disable_interrupts();
|
||||
GRAB_THREAD_LOCK();
|
||||
|
||||
_check_for_thread_sigs(t, state);
|
||||
handle_signals(t, state);
|
||||
|
||||
t->in_kernel = false;
|
||||
|
||||
|
@ -150,3 +150,8 @@ SYSCALL6(sys_sysctl, 71)
|
||||
SYSCALL3(sys_setenv, 79)
|
||||
SYSCALL2(sys_getenv, 80)
|
||||
|
||||
/* Signal handling calls */
|
||||
SYSCALL0(sys_return_from_signal, 103)
|
||||
SYSCALL2(sys_kill, 104)
|
||||
SYSCALL3(sys_sigaction, 105)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user