Merged signals-merge branch into trunk with the following changes:

* Reorganized the kernel locking related to threads and teams.
* We now discriminate correctly between process and thread signals. Signal
  handlers have been moved to teams. Fixes #5679.
* Implemented real-time signal support, including signal queuing, SA_SIGINFO
  support, sigqueue(), sigwaitinfo(), sigtimedwait(), waitid(), and the addition
  of the real-time signal range. Closes #1935 and #2695.
* Gave SIGBUS a separate signal number. Fixes #6704.
* Implemented <time.h> clock and timer support, and fixed/completed alarm() and
  [set]itimer(). Closes #5682.
* Implemented support for thread cancellation. Closes #5686.
* Moved send_signal() from <signal.h> to <OS.h>. Fixes #7554.
* Lots over smaller more or less related changes.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42116 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2011-06-12 00:00:23 +00:00
parent ccd31b93f1
commit 24df65921b
235 changed files with 14975 additions and 6594 deletions
+5
View File
@@ -314,6 +314,11 @@ rule CreateAsmStructOffsetsHeader header : source
} }
} }
# Turn off "invalid use of offsetof()" macro warning. We use offsetof() also
# for non-PODs. Since we're using the same compiler for the whole kernel and
# don't do virtual inheritence, that works well enough.
flags += -Wno-invalid-offsetof ;
# locate object, search for source, and set on target variables # locate object, search for source, and set on target variables
Depends $(header) : $(source) ; Depends $(header) : $(source) ;
+7
View File
@@ -311,6 +311,8 @@ typedef struct {
#define B_REAL_TIME_PRIORITY 120 #define B_REAL_TIME_PRIORITY 120
#define B_SYSTEM_TIMEBASE 0 #define B_SYSTEM_TIMEBASE 0
/* time base for snooze_*(), compatible with the clockid_t constants defined
in <time.h> */
#define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY #define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY
@@ -739,6 +741,11 @@ extern int32 is_computer_on(void);
extern double is_computer_on_fire(void); extern double is_computer_on_fire(void);
/* signal related functions */
int send_signal(thread_id threadID, unsigned int signal);
void set_signal_stack(void* base, size_t size);
/* WARNING: Experimental API! */ /* WARNING: Experimental API! */
enum { enum {
+1 -3
View File
@@ -151,7 +151,7 @@ typedef enum {
B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, // clear a watchpoint B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, // clear a watchpoint
B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, // set/get a thread's masks of signals B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, // set/get a thread's masks of signals
B_DEBUG_MESSAGE_GET_SIGNAL_MASKS, // the debugger is interested in B_DEBUG_MESSAGE_GET_SIGNAL_MASKS, // the debugger is interested in
B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER, // set/get a thread's signal handler for B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER, // set/get the team's signal handler for
B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER, // a signal B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER, // a signal
B_DEBUG_MESSAGE_PREPARE_HANDOVER, // prepares the debugged team for being B_DEBUG_MESSAGE_PREPARE_HANDOVER, // prepares the debugged team for being
@@ -356,7 +356,6 @@ typedef struct {
// B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER // B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER
typedef struct { typedef struct {
thread_id thread; // the thread
int signal; // the signal int signal; // the signal
struct sigaction handler; // the new signal handler struct sigaction handler; // the new signal handler
} debug_nub_set_signal_handler; } debug_nub_set_signal_handler;
@@ -365,7 +364,6 @@ typedef struct {
typedef struct { typedef struct {
port_id reply_port; // port to send the reply to port_id reply_port; // port to send the reply to
thread_id thread; // the thread
int signal; // the signal int signal; // the signal
} debug_nub_get_signal_handler; } debug_nub_get_signal_handler;
+3 -1
View File
@@ -141,7 +141,9 @@ struct vregs {
unsigned long ebp; unsigned long ebp;
unsigned long _reserved_1; unsigned long _reserved_1;
extended_regs xregs; extended_regs xregs;
unsigned long _reserved_2[3]; unsigned long edi;
unsigned long esi;
unsigned long ebx;
}; };
#endif /* __INTEL__ */ #endif /* __INTEL__ */
+6
View File
@@ -71,6 +71,12 @@
#define _POSIX_STREAM_MAX (8) #define _POSIX_STREAM_MAX (8)
#define _POSIX_TTY_NAME_MAX (256) #define _POSIX_TTY_NAME_MAX (256)
#define _POSIX_TZNAME_MAX (3) #define _POSIX_TZNAME_MAX (3)
#define _POSIX_SEM_VALUE_MAX INT_MAX
#define _POSIX_SIGQUEUE_MAX 32
#define _POSIX_RTSIG_MAX 8
#define _POSIX_CLOCKRES_MIN 20000000
#define _POSIX_TIMER_MAX 32
#define _POSIX_DELAYTIMER_MAX 32
#define _POSIX2_LINE_MAX (2048) #define _POSIX2_LINE_MAX (2048)
+2 -59
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2010 Haiku Inc. All Rights Reserved. * Copyright 2001-2011 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the Haiku License. * Distributed under the terms of the Haiku License.
*/ */
#ifndef _PTHREAD_H_ #ifndef _PTHREAD_H_
@@ -8,66 +8,10 @@
#include <sched.h> #include <sched.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
#include <time.h> #include <time.h>
typedef struct _pthread_thread *pthread_t;
typedef struct _pthread_attr *pthread_attr_t;
typedef struct _pthread_mutex pthread_mutex_t;
typedef struct _pthread_mutexattr *pthread_mutexattr_t;
typedef struct _pthread_cond pthread_cond_t;
typedef struct _pthread_condattr *pthread_condattr_t;
typedef int pthread_key_t;
typedef struct _pthread_once pthread_once_t;
typedef struct _pthread_rwlock pthread_rwlock_t;
typedef struct _pthread_rwlockattr *pthread_rwlockattr_t;
typedef struct _pthread_spinlock pthread_spinlock_t;
/*
typedef struct _pthread_barrier *pthread_barrier_t;
typedef struct _pthread_barrierattr *pthread_barrierattr_t;
*/
struct _pthread_mutex {
uint32_t flags;
int32_t lock;
int32_t unused;
int32_t owner;
int32_t owner_count;
};
struct _pthread_cond {
uint32_t flags;
int32_t unused;
pthread_mutex_t *mutex;
int32_t waiter_count;
int32_t lock;
};
struct _pthread_once {
int32_t state;
};
struct _pthread_rwlock {
uint32_t flags;
int32_t owner;
union {
struct {
int32_t sem;
} shared;
struct {
int32_t lock_sem;
int32_t lock_count;
int32_t reader_count;
int32_t writer_count;
void* waiters[2];
} local;
};
};
struct _pthread_spinlock {
int32_t lock;
};
#define PTHREAD_MUTEX_DEFAULT 0 #define PTHREAD_MUTEX_DEFAULT 0
#define PTHREAD_MUTEX_NORMAL 1 #define PTHREAD_MUTEX_NORMAL 1
#define PTHREAD_MUTEX_ERRORCHECK 2 #define PTHREAD_MUTEX_ERRORCHECK 2
@@ -278,7 +222,6 @@ extern int pthread_equal(pthread_t t1, pthread_t t2);
extern void pthread_exit(void *value_ptr); extern void pthread_exit(void *value_ptr);
extern int pthread_join(pthread_t thread, void **_value); extern int pthread_join(pthread_t thread, void **_value);
extern pthread_t pthread_self(void); extern pthread_t pthread_self(void);
extern int pthread_kill(pthread_t thread, int sig);
extern int pthread_getconcurrency(void); extern int pthread_getconcurrency(void);
extern int pthread_setconcurrency(int newLevel); extern int pthread_setconcurrency(int newLevel);
+1 -2
View File
@@ -15,8 +15,7 @@
typedef struct __jmp_buf_tag { typedef struct __jmp_buf_tag {
__jmp_buf regs; /* saved registers, stack & program pointer */ __jmp_buf regs; /* saved registers, stack & program pointer */
int mask_was_saved; sigset_t inverted_signal_mask;
sigset_t saved_mask;
} jmp_buf[1]; } jmp_buf[1];
typedef jmp_buf sigjmp_buf; typedef jmp_buf sigjmp_buf;
+192 -83
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2010 Haiku Inc. All Rights Reserved. * Copyright 2002-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SIGNAL_H_ #ifndef _SIGNAL_H_
@@ -10,48 +10,73 @@
typedef int sig_atomic_t; typedef int sig_atomic_t;
typedef __haiku_int32 sigset_t; typedef __haiku_uint64 sigset_t;
typedef void (*sighandler_t)(int);
/* GNU-like signal handler typedef */
typedef void (*__signal_func_ptr)(int);
/* deprecated, for compatibility with BeOS only */
/* macros defining the standard signal handling behavior */ /* macros defining the standard signal handling behavior */
#define SIG_DFL ((sighandler_t)0) /* "default" signal behaviour */ #define SIG_DFL ((__sighandler_t)0) /* "default" signal behaviour */
#define SIG_IGN ((sighandler_t)1) /* ignore signal */ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR ((sighandler_t)-1) /* an error occurred during signal processing */ #define SIG_ERR ((__sighandler_t)-1) /* an error occurred during signal
#define SIG_HOLD ((sighandler_t)3) /* the signal was hold */ processing */
#define SIG_HOLD ((__sighandler_t)3) /* the signal was hold */
/* TODO: Support this structure, or more precisely the SA_SIGINFO flag. To do /* macros specifying the event notification type (sigevent::sigev_notify) */
* this properly we need real-time signal support. Both are commented out for #define SIGEV_NONE 0 /* no notification */
* the time being to not make "configure" scripts think we do support them. */ #define SIGEV_SIGNAL 1 /* notify via queued signal */
#if 0 #define SIGEV_THREAD 2 /* notify via function called in new thread */
typedef struct {
union sigval {
int sival_int;
void* sival_ptr;
};
struct sigevent {
int sigev_notify; /* notification type */
int sigev_signo; /* signal number */
union sigval sigev_value; /* user-defined signal value */
void (*sigev_notify_function)(union sigval);
/* notification function in case of
SIGEV_THREAD */
pthread_attr_t* sigev_notify_attributes;
/* pthread creation attributes in case of
SIGEV_THREAD */
};
typedef struct __siginfo_t {
int si_signo; /* signal number */ int si_signo; /* signal number */
int si_code; /* signal code */ int si_code; /* signal code */
int si_errno; /* if non zero, an error number associated with this signal */ int si_errno; /* if non zero, an error number associated with
this signal */
pid_t si_pid; /* sending process ID */ pid_t si_pid; /* sending process ID */
uid_t si_uid; /* real user ID of sending process */ uid_t si_uid; /* real user ID of sending process */
void *si_addr; /* address of faulting instruction */ void* si_addr; /* address of faulting instruction */
int si_status; /* exit value or signal */ int si_status; /* exit value or signal */
long si_band; /* band event for SIGPOLL */ long si_band; /* band event for SIGPOLL */
union sigval si_value; /* signal value */
} siginfo_t; } siginfo_t;
#endif /* 0 */
/*
* structure used by sigaction() /* signal handler function types */
* typedef void (*__sighandler_t)(int);
* Note: the 'sa_userdata' field is a non-POSIX extension. typedef void (*__siginfo_handler_t)(int, siginfo_t*, void*);
* See the documentation for more info on this.
*/ #ifdef __USE_GNU
typedef __sighandler_t sighandler_t;
/* GNU-like signal handler typedef */
#endif
/* structure used by sigaction() */
struct sigaction { struct sigaction {
sighandler_t sa_handler; union {
__sighandler_t sa_handler;
__siginfo_handler_t sa_sigaction;
};
sigset_t sa_mask; sigset_t sa_mask;
int sa_flags; int sa_flags;
void *sa_userdata; /* will be passed to the signal handler */ void* sa_userdata; /* will be passed to the signal
handler, BeOS extension */
}; };
/* values for sa_flags */ /* values for sa_flags */
@@ -61,7 +86,7 @@ struct sigaction {
#define SA_NODEFER 0x08 #define SA_NODEFER 0x08
#define SA_RESTART 0x10 #define SA_RESTART 0x10
#define SA_ONSTACK 0x20 #define SA_ONSTACK 0x20
/* #define SA_SIGINFO 0x40 */ #define SA_SIGINFO 0x40
#define SA_NOMASK SA_NODEFER #define SA_NOMASK SA_NODEFER
#define SA_STACK SA_ONSTACK #define SA_STACK SA_ONSTACK
#define SA_ONESHOT SA_RESETHAND #define SA_ONESHOT SA_RESETHAND
@@ -73,20 +98,13 @@ struct sigaction {
#define MINSIGSTKSZ 4096 #define MINSIGSTKSZ 4096
#define SIGSTKSZ 16384 #define SIGSTKSZ 16384
/* /* for signals using an alternate stack */
* for signals using an alternate stack
*/
typedef struct stack_t { typedef struct stack_t {
void *ss_sp; void* ss_sp;
size_t ss_size; size_t ss_size;
int ss_flags; int ss_flags;
} stack_t; } stack_t;
typedef struct sigstack {
int ss_onstack;
void *ss_sp;
} sigstack;
/* for the 'how' arg of sigprocmask() */ /* for the 'how' arg of sigprocmask() */
#define SIG_BLOCK 1 #define SIG_BLOCK 1
#define SIG_UNBLOCK 2 #define SIG_UNBLOCK 2
@@ -128,62 +146,137 @@ typedef struct sigstack {
#define SIGVTALRM 27 /* Virtual timer expired */ #define SIGVTALRM 27 /* Virtual timer expired */
#define SIGXCPU 28 /* CPU time limit exceeded */ #define SIGXCPU 28 /* CPU time limit exceeded */
#define SIGXFSZ 29 /* File size limit exceeded */ #define SIGXFSZ 29 /* File size limit exceeded */
#define SIGBUS 30 /* access to undefined portion of a memory object */
#define SIGRESERVED1 31 /* reserved for future use */
#define SIGRESERVED2 32 /* reserved for future use */
#define SIGBUS SIGSEGV /* for old style code */ #define SIGRTMIN (__signal_get_sigrtmin())
/* lowest realtime signal number */
#define SIGRTMAX (__signal_get_sigrtmax())
/* greatest realtime signal number */
/* #define __MAX_SIGNO 64 /* greatest possible signal number, can be used (+1)
* Signal numbers 30-32 are currently free but may be used in future as size of static arrays */
* releases. Use them at your own peril (if you do use them, at least #define NSIG (__MAX_SIGNO + 1)
* be smart and use them backwards from signal 32). /* BSD extension, size of the sys_siglist table,
*/ obsolete */
#define MAX_SIGNO 32 /* the most signals that a single thread can reference */
#define __signal_max 29 /* the largest signal number that is actually defined */
#define NSIG (__signal_max+1) /* Signal code values appropriate for siginfo_t::si_code: */
/* the number of defined signals */ /* any signal */
#define SI_USER 0 /* signal sent by user */
#define SI_QUEUE 1 /* signal sent by sigqueue() */
#define SI_TIMER 2 /* signal sent on timer_settime() timeout */
#define SI_ASYNCIO 3 /* signal sent on asynchronous I/O completion */
#define SI_MESGQ 4 /* signal sent on arrival of message on empty
message queue */
/* SIGILL */
#define ILL_ILLOPC 10 /* illegal opcode */
#define ILL_ILLOPN 11 /* illegal operand */
#define ILL_ILLADR 12 /* illegal addressing mode */
#define ILL_ILLTRP 13 /* illegal trap */
#define ILL_PRVOPC 14 /* privileged opcode */
#define ILL_PRVREG 15 /* privileged register */
#define ILL_COPROC 16 /* coprocessor error */
#define ILL_BADSTK 17 /* internal stack error */
/* SIGFPE */
#define FPE_INTDIV 20 /* integer division by zero */
#define FPE_INTOVF 21 /* integer overflow */
#define FPE_FLTDIV 22 /* floating-point division by zero */
#define FPE_FLTOVF 23 /* floating-point overflow */
#define FPE_FLTUND 24 /* floating-point underflow */
#define FPE_FLTRES 25 /* floating-point inexact result */
#define FPE_FLTINV 26 /* invalid floating-point operation */
#define FPE_FLTSUB 27 /* subscript out of range */
/* SIGSEGV */
#define SEGV_MAPERR 30 /* address not mapped to object */
#define SEGV_ACCERR 31 /* invalid permissions for mapped object */
/* SIGBUS */
#define BUS_ADRALN 40 /* invalid address alignment */
#define BUS_ADRERR 41 /* nonexistent physical address */
#define BUS_OBJERR 42 /* object-specific hardware error */
/* SIGTRAP */
#define TRAP_BRKPT 50 /* process breakpoint */
#define TRAP_TRACE 51 /* process trace trap. */
/* SIGCHLD */
#define CLD_EXITED 60 /* child exited */
#define CLD_KILLED 61 /* child terminated abnormally without core dump */
#define CLD_DUMPED 62 /* child terminated abnormally with core dump */
#define CLD_TRAPPED 63 /* traced child trapped */
#define CLD_STOPPED 64 /* child stopped */
#define CLD_CONTINUED 65 /* stopped child continued */
/* SIGPOLL */
#define POLL_IN 70 /* input available */
#define POLL_OUT 71 /* output available */
#define POLL_MSG 72 /* input message available */
#define POLL_ERR 73 /* I/O error */
#define POLL_PRI 74 /* high priority input available */
#define POLL_HUP 75 /* device disconnected */
/* the global table of text strings containing descriptions for each signal */ /* the global table of text strings containing descriptions for each signal */
extern const char * const sys_siglist[NSIG]; extern const char* const sys_siglist[NSIG];
/* BSD extension, obsolete, use strsignal() instead */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
sighandler_t signal(int sig, sighandler_t signalHandler);
sighandler_t sigset(int sig, sighandler_t signalHandler);
int raise(int sig);
int kill(pid_t pid, int sig);
int send_signal(pid_t tid, unsigned int sig);
int killpg(pid_t processGroupID, int sig);
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); /* signal management (actions and block masks) */
int siginterrupt(int sig, int flag); __sighandler_t signal(int signal, __sighandler_t signalHandler);
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); int sigaction(int signal, const struct sigaction* action,
int sigpending(sigset_t *set); struct sigaction* oldAction);
int sigsuspend(const sigset_t *mask); __sighandler_t sigset(int signal, __sighandler_t signalHandler);
int sigwait(const sigset_t *set, int *sig); int sigignore(int signal);
int siginterrupt(int signal, int flag);
int sigemptyset(sigset_t *set); int sigprocmask(int how, const sigset_t* set, sigset_t* oldSet);
int sigfillset(sigset_t *set); int pthread_sigmask(int how, const sigset_t* set, sigset_t* oldSet);
int sigaddset(sigset_t *set, int signo); int sighold(int signal);
int sigdelset(sigset_t *set, int signo); int sigrelse(int signal);
int sigismember(const sigset_t *set, int signo);
int sigignore(int signo);
int sighold(int signo);
int sigrelse(int signo);
int sigpause(int signo);
void set_signal_stack(void *ptr, size_t size); /* sending signals */
int sigaltstack(const stack_t *ss, stack_t *oss); int raise(int signal);
int kill(pid_t pid, int signal);
int killpg(pid_t processGroupID, int signal);
int sigqueue(pid_t pid, int signal, const union sigval userValue);
int pthread_kill(pthread_t thread, int signal);
/* querying and waiting for signals */
int sigpending(sigset_t* set);
int sigsuspend(const sigset_t* mask);
int sigpause(int signal);
int sigwait(const sigset_t* set, int* _signal);
int sigwaitinfo(const sigset_t* set, siginfo_t* info);
int sigtimedwait(const sigset_t* set, siginfo_t* info,
const struct timespec* timeout);
/* setting the per-thread signal stack */
int sigaltstack(const stack_t* stack, stack_t* oldStack);
/* signal set (sigset_t) manipulation */
int sigemptyset(sigset_t* set);
int sigfillset(sigset_t* set);
int sigaddset(sigset_t* set, int signal);
int sigdelset(sigset_t* set, int signal);
int sigismember(const sigset_t* set, int signal);
/* printing signal names */
void psiginfo(const siginfo_t* info, const char* message);
void psignal(int signal, const char* message);
/* implementation private */
int __signal_get_sigrtmin();
int __signal_get_sigrtmax();
/* pthread extension : equivalent of sigprocmask() */
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
/* TODO: move this into the documentation! /* TODO: move this into the documentation!
* ================================================== * ==================================================
* !!! SPECIAL NOTES CONCERNING NON-POSIX EXTENSIONS: * !!! SPECIAL NOTES CONCERNING NON-POSIX EXTENSIONS:
@@ -205,7 +298,7 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
* handling. It also allows an opportunity, via the 'sigaction' struct, to * handling. It also allows an opportunity, via the 'sigaction' struct, to
* enable additional data to be passed to the handler. For example: * enable additional data to be passed to the handler. For example:
* void * void
* my_signal_handler(int sig, char *userData, vregs regs) * my_signal_handler(int sig, char* userData, vregs* regs)
* { * {
* . . . * . . .
* } * }
@@ -213,7 +306,7 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
* struct sigaction sa; * struct sigaction sa;
* char data_buffer[32]; * char data_buffer[32];
* *
* sa.sa_handler = (sighandler_t)my_signal_handler; * sa.sa_handler = (__sighandler_t)my_signal_handler;
* sigemptyset(&sa.sa_mask); * sigemptyset(&sa.sa_mask);
* sa.sa_userdata = userData; * sa.sa_userdata = userData;
* *
@@ -223,8 +316,9 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
* The two additional arguments available to the signal handler are extensions * The two additional arguments available to the signal handler are extensions
* to the Posix standard. This feature was introduced by the BeOS and retained * to the Posix standard. This feature was introduced by the BeOS and retained
* by Haiku. However, to remain compatible with Posix and ANSI C, the type * by Haiku. However, to remain compatible with Posix and ANSI C, the type
* of the sa_handler field is defined as 'sighandler_t'. This requires the handler * of the sa_handler field is defined as '__sighandler_t'. This requires the
* to be cast when assigned to the sa_handler field, as in the example above. * handler to be cast when assigned to the sa_handler field, as in the example
* above.
* *
* The 3 arguments that Haiku provides to signal handlers are as follows: * The 3 arguments that Haiku provides to signal handlers are as follows:
* 1) The first argument is the (usual) signal number. * 1) The first argument is the (usual) signal number.
@@ -234,10 +328,14 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
* *
* 3) The third argument is a pointer to a vregs struct (defined below). * 3) The third argument is a pointer to a vregs struct (defined below).
* The vregs struct contains the contents of the volatile registers at * 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 * the time the signal was delivered to your thread. You can change the
* of the structure. After your signal handler completes, the OS uses this struct * fields of the structure. After your signal handler completes, the OS uses
* to reload the registers for your thread (privileged registers are not loaded * this struct to reload the registers for your thread (privileged registers
* of course). The vregs struct is of course terribly machine dependent. * are not loaded of course). The vregs struct is of course terribly machine
* dependent.
* Note that in BeOS the vregs argument was passed by value, not by pointer.
* While Haiku retains binary compability with code compiled for BeOS, code
* built under Haiku must use the pointer argument.
*/ */
/* /*
@@ -245,11 +343,22 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
* *
* signal handlers get this as the last argument * signal handlers get this as the last argument
*/ */
typedef struct vregs vregs; typedef struct vregs vregs;
/* BeOS extension */
/* include architecture specific definitions */ /* include architecture specific definitions */
#include __HAIKU_ARCH_HEADER(signal.h) #include __HAIKU_ARCH_HEADER(signal.h)
typedef struct vregs mcontext_t;
typedef struct __ucontext_t {
struct __ucontext_t* uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
} ucontext_t;
#endif /* _SIGNAL_H_ */ #endif /* _SIGNAL_H_ */
+64
View File
@@ -52,6 +52,70 @@ typedef char* caddr_t;
typedef __haiku_addr_t addr_t; typedef __haiku_addr_t addr_t;
typedef __haiku_int32 key_t; typedef __haiku_int32 key_t;
typedef __haiku_std_int32 clockid_t;
typedef struct __timer_t* timer_t;
/* pthread types */
typedef struct _pthread_thread *pthread_t;
typedef struct _pthread_attr *pthread_attr_t;
typedef struct _pthread_mutex pthread_mutex_t;
typedef struct _pthread_mutexattr *pthread_mutexattr_t;
typedef struct _pthread_cond pthread_cond_t;
typedef struct _pthread_condattr *pthread_condattr_t;
typedef int pthread_key_t;
typedef struct _pthread_once pthread_once_t;
typedef struct _pthread_rwlock pthread_rwlock_t;
typedef struct _pthread_rwlockattr *pthread_rwlockattr_t;
typedef struct _pthread_spinlock pthread_spinlock_t;
/*
typedef struct _pthread_barrier *pthread_barrier_t;
typedef struct _pthread_barrierattr *pthread_barrierattr_t;
*/
struct _pthread_mutex {
__haiku_std_uint32 flags;
__haiku_std_int32 lock;
__haiku_std_int32 unused;
__haiku_std_int32 owner;
__haiku_std_int32 owner_count;
};
struct _pthread_cond {
__haiku_std_uint32 flags;
__haiku_std_int32 unused;
pthread_mutex_t* mutex;
__haiku_std_int32 waiter_count;
__haiku_std_int32 lock;
};
struct _pthread_once {
__haiku_std_int32 state;
};
struct _pthread_rwlock {
__haiku_std_uint32 flags;
__haiku_std_int32 owner;
union {
struct {
__haiku_std_int32 sem;
} shared;
struct {
__haiku_std_int32 lock_sem;
__haiku_std_int32 lock_count;
__haiku_std_int32 reader_count;
__haiku_std_int32 writer_count;
void* waiters[2];
} local;
};
};
struct _pthread_spinlock {
__haiku_std_int32 lock;
};
#include <null.h> #include <null.h>
#include <size_t.h> #include <size_t.h>
#include <time.h> #include <time.h>
+2 -6
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2010 Haiku Inc. All Rights Reserved. * Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SYS_WAIT_H #ifndef _SYS_WAIT_H
@@ -28,16 +28,12 @@
#define WIFCORED(value) ((value) & 0x10000) #define WIFCORED(value) ((value) & 0x10000)
#define WIFCONTINUED(value) ((value) & 0x20000) #define WIFCONTINUED(value) ((value) & 0x20000)
/* TODO: waitid() is part of the real-time signal extension. Uncomment when
* implemented! */
#if 0
/* ID types for waitid() */ /* ID types for waitid() */
typedef enum { typedef enum {
P_ALL, /* wait for any children, ignore ID */ P_ALL, /* wait for any children, ignore ID */
P_PID, /* wait for the child whose process ID matches */ P_PID, /* wait for the child whose process ID matches */
P_PGID /* wait for any child whose process group ID matches */ P_PGID /* wait for any child whose process group ID matches */
} idtype_t; } idtype_t;
#endif /* 0 */
#ifdef __cplusplus #ifdef __cplusplus
@@ -46,7 +42,7 @@ extern "C" {
extern pid_t wait(int *_status); extern pid_t wait(int *_status);
extern pid_t waitpid(pid_t pid, int *_status, int options); extern pid_t waitpid(pid_t pid, int *_status, int options);
/* extern int waitid(idtype_t idType, id_t id, siginfo_t *info, int options); */ extern int waitid(idtype_t idType, id_t id, siginfo_t *info, int options);
#ifdef __cplusplus #ifdef __cplusplus
} }
+35 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2005-2010 Haiku Inc. All Rights Reserved. * Copyright 2005-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _TIME_H_ #ifndef _TIME_H_
@@ -9,17 +9,33 @@
#include <sys/types.h> #include <sys/types.h>
struct sigevent; /* defined in <signal.h> */
typedef __haiku_int32 clock_t; typedef __haiku_int32 clock_t;
typedef __haiku_int32 time_t; typedef __haiku_int32 time_t;
typedef __haiku_int32 suseconds_t; typedef __haiku_int32 suseconds_t;
typedef __haiku_uint32 useconds_t; typedef __haiku_uint32 useconds_t;
#define CLOCKS_PER_SEC 1000
#define CLOCKS_PER_SEC 1000000
#define CLK_TCK CLOCKS_PER_SEC #define CLK_TCK CLOCKS_PER_SEC
#define MAX_TIMESTR 70 #define MAX_TIMESTR 70
/* maximum length of a string returned by asctime(), and ctime() */ /* maximum length of a string returned by asctime(), and ctime() */
#define CLOCK_MONOTONIC ((clockid_t)0)
/* system-wide monotonic clock (aka system time) */
#define CLOCK_REALTIME ((clockid_t)-1)
/* system-wide real time clock */
#define CLOCK_PROCESS_CPUTIME_ID ((clockid_t)-2)
/* clock measuring the used CPU time of the current process */
#define CLOCK_THREAD_CPUTIME_ID ((clockid_t)-3)
/* clock measuring the used CPU time of the current thread */
#define TIMER_ABSTIME 1 /* absolute timer flag */
struct timespec { struct timespec {
time_t tv_sec; /* seconds */ time_t tv_sec; /* seconds */
long tv_nsec; /* and nanoseconds */ long tv_nsec; /* and nanoseconds */
@@ -72,6 +88,23 @@ extern size_t strftime(char *buffer, size_t maxSize, const char *format,
const struct tm *tm); const struct tm *tm);
extern char *strptime(const char *buf, const char *format, struct tm *tm); extern char *strptime(const char *buf, const char *format, struct tm *tm);
/* clock functions */
int clock_getres(clockid_t clockID, struct timespec* resolution);
int clock_gettime(clockid_t clockID, struct timespec* time);
int clock_settime(clockid_t clockID, const struct timespec* time);
int clock_nanosleep(clockid_t clockID, int flags,
const struct timespec* time, struct timespec* remainingTime);
int clock_getcpuclockid(pid_t pid, clockid_t* _clockID);
/* timer functions */
int timer_create(clockid_t clockID, struct sigevent* event,
timer_t* timerID);
int timer_delete(timer_t timerID);
int timer_gettime(timer_t timerID, struct itimerspec* value);
int timer_settime(timer_t timerID, int flags,
const struct itimerspec* value, struct itimerspec* oldValue);
int timer_getoverrun(timer_t timerID);
/* special timezone support */ /* special timezone support */
extern void tzset(void); extern void tzset(void);
+15 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2010 Haiku Inc. All Rights Reserved. * Copyright 2004-2011 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _UNISTD_H_ #ifndef _UNISTD_H_
@@ -45,9 +45,13 @@
#define _POSIX_THREAD_ATTR_STACKADDR (-1) /* currently unsupported */ #define _POSIX_THREAD_ATTR_STACKADDR (-1) /* currently unsupported */
#define _POSIX_THREAD_ATTR_STACKSIZE (200809L) #define _POSIX_THREAD_ATTR_STACKSIZE (200809L)
#define _POSIX_THREAD_PRIORITY_SCHEDULING (-1) /* currently unsupported */ #define _POSIX_THREAD_PRIORITY_SCHEDULING (-1) /* currently unsupported */
#define _POSIX_REALTIME_SIGNALS (-1) /* currently unsupported */ #define _POSIX_REALTIME_SIGNALS (200809L)
#define _POSIX_MEMORY_PROTECTION (200809L) #define _POSIX_MEMORY_PROTECTION (200809L)
#define _POSIX_SEM_VALUE_MAX INT_MAX #define _POSIX_MONOTONIC_CLOCK (200809L)
#define _POSIX_TIMERS (200809L)
#define _POSIX_CPUTIME (200809L)
#define _POSIX_THREAD_CPUTIME (200809L)
/* pathconf() constants */ /* pathconf() constants */
/* BeOS supported values, do not touch */ /* BeOS supported values, do not touch */
@@ -119,6 +123,14 @@
#define _SC_THREAD_PRIORITY_SCHEDULING 50 #define _SC_THREAD_PRIORITY_SCHEDULING 50
#define _SC_REALTIME_SIGNALS 51 #define _SC_REALTIME_SIGNALS 51
#define _SC_MEMORY_PROTECTION 52 #define _SC_MEMORY_PROTECTION 52
#define _SC_SIGQUEUE_MAX 53
#define _SC_RTSIG_MAX 54
#define _SC_MONOTONIC_CLOCK 55
#define _SC_DELAYTIMER_MAX 56
#define _SC_TIMER_MAX 57
#define _SC_TIMERS 58
#define _SC_CPUTIME 59
#define _SC_THREAD_CPUTIME 60
/* confstr() constants */ /* confstr() constants */
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_DPC_H
#define _KERNEL_DPC_H
#include <sys/cdefs.h>
#include <KernelExport.h>
#include <util/DoublyLinkedList.h>
#include <condition_variable.h>
namespace BKernel {
class DPCQueue;
class DPCCallback : public DoublyLinkedListLinkImpl<DPCCallback> {
public:
DPCCallback();
virtual ~DPCCallback();
virtual void DoDPC(DPCQueue* queue) = 0;
private:
friend class DPCQueue;
private:
DPCQueue* fInQueue;
};
class FunctionDPCCallback : public DPCCallback {
public:
FunctionDPCCallback(DPCQueue* owner);
void SetTo(void (*function)(void*), void* argument);
virtual void DoDPC(DPCQueue* queue);
private:
DPCQueue* fOwner;
void (*fFunction)(void*);
void* fArgument;
};
class DPCQueue {
public:
DPCQueue();
~DPCQueue();
static DPCQueue* DefaultQueue(int priority);
status_t Init(const char* name, int32 priority,
uint32 reservedSlots);
void Close(bool cancelPending);
status_t Add(DPCCallback* callback,
bool schedulerLocked);
status_t Add(void (*function)(void*), void* argument,
bool schedulerLocked);
bool Cancel(DPCCallback* callback);
thread_id Thread() const
{ return fThreadID; }
public:
// conceptually package private
void Recycle(FunctionDPCCallback* callback);
private:
typedef DoublyLinkedList<DPCCallback> CallbackList;
private:
static status_t _ThreadEntry(void* data);
status_t _Thread();
bool _IsClosed() const
{ return fThreadID < 0; }
private:
spinlock fLock;
thread_id fThreadID;
CallbackList fCallbacks;
CallbackList fUnusedFunctionCallbacks;
ConditionVariable fPendingCallbacksCondition;
DPCCallback* fCallbackInProgress;
ConditionVariable* fCallbackDoneCondition;
};
} // namespace BKernel
using BKernel::DPCCallback;
using BKernel::DPCQueue;
using BKernel::FunctionDPCCallback;
__BEGIN_DECLS
void dpc_init();
__END_DECLS
#endif // _KERNEL_DPC_H
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_USER_EVENT_H
#define _KERNEL_USER_EVENT_H
#include <signal.h>
#include <SupportDefs.h>
#include <DPC.h>
#include <thread.h>
namespace BKernel {
struct Team;
struct Thread;
struct UserEvent {
virtual ~UserEvent();
virtual status_t Fire() = 0;
};
struct SignalEvent : UserEvent {
virtual ~SignalEvent();
void SetUserValue(union sigval userValue);
protected:
struct EventSignal;
protected:
SignalEvent(EventSignal* signal);
protected:
EventSignal* fSignal;
};
struct TeamSignalEvent : SignalEvent {
static TeamSignalEvent* Create(Team* team, uint32 signalNumber,
int32 signalCode, int32 errorCode);
virtual status_t Fire();
private:
TeamSignalEvent(Team* team,
EventSignal* signal);
private:
Team* fTeam;
};
struct ThreadSignalEvent : SignalEvent {
static ThreadSignalEvent* Create(Thread* thread, uint32 signalNumber,
int32 signalCode, int32 errorCode,
pid_t sendingTeam);
virtual status_t Fire();
private:
ThreadSignalEvent(Thread* thread,
EventSignal* signal);
private:
Thread* fThread;
};
struct CreateThreadEvent : UserEvent, private DPCCallback {
~CreateThreadEvent();
static CreateThreadEvent* Create(
const ThreadCreationAttributes& attributes);
virtual status_t Fire();
private:
CreateThreadEvent(
const ThreadCreationAttributes& attributes);
virtual void DoDPC(DPCQueue* queue);
private:
ThreadCreationAttributes fCreationAttributes;
char fThreadName[B_OS_NAME_LENGTH];
bool fPendingDPC;
};
} // namespace BKernel
using BKernel::CreateThreadEvent;
using BKernel::SignalEvent;
using BKernel::TeamSignalEvent;
using BKernel::ThreadSignalEvent;
using BKernel::UserEvent;
#endif // _KERNEL_USER_EVENT_H
+273
View File
@@ -0,0 +1,273 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_USER_TIMER_H
#define _KERNEL_USER_TIMER_H
#include <sys/cdefs.h>
#include <time.h>
#include <util/DoublyLinkedList.h>
#include <ksignal.h>
#include <timer.h>
#include <user_timer_defs.h>
struct thread_creation_attributes;
namespace BKernel {
struct UserEvent;
struct Team;
struct UserTimer : DoublyLinkedListLinkImpl<UserTimer> {
UserTimer();
virtual ~UserTimer();
int32 ID() const
{ return fID; }
void SetID(int32 id)
{ fID = id; }
void SetEvent(UserEvent* event)
{ fEvent = event; }
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval) = 0;
void Cancel();
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount) = 0;
protected:
static int32 HandleTimerHook(struct timer* timer);
virtual void HandleTimer();
inline void UpdatePeriodicStartTime();
inline void CheckPeriodicOverrun(bigtime_t now);
protected:
int32 fID;
timer fTimer;
UserEvent* fEvent;
bigtime_t fNextTime;
bigtime_t fInterval;
uint32 fOverrunCount;
bool fScheduled; // fTimer scheduled
};
struct SystemTimeUserTimer : public UserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
protected:
virtual void HandleTimer();
void ScheduleKernelTimer(bigtime_t now,
bool checkPeriodicOverrun);
};
struct RealTimeUserTimer : public SystemTimeUserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
void TimeWarped();
private:
bigtime_t fRealTimeOffset;
bool fAbsolute;
protected:
virtual void HandleTimer();
public:
// conceptually package private
DoublyLinkedListLink<RealTimeUserTimer> fGlobalListLink;
};
struct TeamTimeUserTimer : public UserTimer {
TeamTimeUserTimer(team_id teamID);
~TeamTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Update(Thread* unscheduledThread);
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
void _Update(bool unscheduling);
private:
team_id fTeamID;
Team* fTeam;
int32 fRunningThreads;
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<TeamTimeUserTimer> fCPUTimeListLink;
};
struct TeamUserTimeUserTimer : public UserTimer {
TeamUserTimeUserTimer(team_id teamID);
~TeamUserTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Check();
private:
team_id fTeamID;
Team* fTeam;
public:
// conceptually package private
DoublyLinkedListLink<TeamUserTimeUserTimer> fCPUTimeListLink;
};
struct ThreadTimeUserTimer : public UserTimer {
ThreadTimeUserTimer(thread_id threadID);
~ThreadTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Start();
void Stop();
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
thread_id fThreadID;
Thread* fThread; // != NULL only when active
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<ThreadTimeUserTimer> fCPUTimeListLink;
};
struct UserTimerList {
UserTimerList();
~UserTimerList();
UserTimer* TimerFor(int32 id) const;
void AddTimer(UserTimer* timer);
void RemoveTimer(UserTimer* timer)
{ fTimers.Remove(timer); }
int32 DeleteTimers(bool userDefinedOnly);
private:
typedef DoublyLinkedList<UserTimer> TimerList;
private:
TimerList fTimers;
};
typedef DoublyLinkedList<RealTimeUserTimer,
DoublyLinkedListMemberGetLink<RealTimeUserTimer,
&RealTimeUserTimer::fGlobalListLink> > RealTimeUserTimerList;
typedef DoublyLinkedList<TeamTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamTimeUserTimer,
&TeamTimeUserTimer::fCPUTimeListLink> > TeamTimeUserTimerList;
typedef DoublyLinkedList<TeamUserTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamUserTimeUserTimer,
&TeamUserTimeUserTimer::fCPUTimeListLink> > TeamUserTimeUserTimerList;
typedef DoublyLinkedList<ThreadTimeUserTimer,
DoublyLinkedListMemberGetLink<ThreadTimeUserTimer,
&ThreadTimeUserTimer::fCPUTimeListLink> > ThreadTimeUserTimerList;
} // namespace BKernel
using BKernel::RealTimeUserTimer;
using BKernel::RealTimeUserTimerList;
using BKernel::SystemTimeUserTimer;
using BKernel::TeamUserTimeUserTimer;
using BKernel::TeamUserTimeUserTimerList;
using BKernel::TeamTimeUserTimer;
using BKernel::TeamTimeUserTimerList;
using BKernel::ThreadTimeUserTimer;
using BKernel::ThreadTimeUserTimerList;
using BKernel::UserTimer;
using BKernel::UserTimerList;
__BEGIN_DECLS
status_t user_timer_create_thread_timers(Team* team, Thread* thread);
status_t user_timer_create_team_timers(Team* team);
status_t user_timer_get_clock(clockid_t clockID, bigtime_t& _time);
void user_timer_real_time_clock_changed();
void user_timer_stop_cpu_timers(Thread* thread, Thread* nextThread);
void user_timer_continue_cpu_timers(Thread* thread,
Thread* previousThread);
void user_timer_check_team_user_timers(Team* team);
status_t _user_get_clock(clockid_t clockID, bigtime_t* _time);
status_t _user_set_clock(clockid_t clockID, bigtime_t time);
int32 _user_create_timer(clockid_t clockID, thread_id threadID,
uint32 flags, const struct sigevent* event,
const thread_creation_attributes* threadAttributes);
status_t _user_delete_timer(int32 timerID, thread_id threadID);
status_t _user_get_timer(int32 timerID, thread_id threadID,
struct user_timer_info* info);
status_t _user_set_timer(int32 timerID, thread_id threadID,
bigtime_t startTime, bigtime_t interval, uint32 flags,
struct user_timer_info* oldInfo);
__END_DECLS
#endif // _KERNEL_USER_TIMER_H
+5 -5
View File
@@ -21,16 +21,16 @@ status_t arch_team_init_team_struct(Team *t, bool kernel);
status_t arch_thread_init_thread_struct(Thread *t); status_t arch_thread_init_thread_struct(Thread *t);
status_t arch_thread_init_tls(Thread *thread); status_t arch_thread_init_tls(Thread *thread);
void arch_thread_context_switch(Thread *t_from, Thread *t_to); void arch_thread_context_switch(Thread *t_from, Thread *t_to);
status_t arch_thread_init_kthread_stack(Thread *t, void arch_thread_init_kthread_stack(Thread *thread, void *stack,
int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)); void *stackTop, void (*function)(void*), const void *data);
void arch_thread_dump_info(void *info); void arch_thread_dump_info(void *info);
status_t arch_thread_enter_userspace(Thread *t, addr_t entry, status_t arch_thread_enter_userspace(Thread *t, addr_t entry,
void *args1, void *args2); void *args1, void *args2);
bool arch_on_signal_stack(Thread *thread); bool arch_on_signal_stack(Thread *thread);
status_t arch_setup_signal_frame(Thread *t, struct sigaction *sa, status_t arch_setup_signal_frame(Thread *thread, struct sigaction *action,
int signal, int signalMask); struct signal_frame_data *signalFrameData);
int64 arch_restore_signal_frame(void); int64 arch_restore_signal_frame(struct signal_frame_data* signalFrameData);
void arch_store_fork_frame(struct arch_fork_arg *arg); void arch_store_fork_frame(struct arch_fork_arg *arg);
void arch_restore_fork_frame(struct arch_fork_arg *arg); void arch_restore_fork_frame(struct arch_fork_arg *arg);
+26 -1
View File
@@ -95,6 +95,32 @@
#define IA32_MTR_WRITE_BACK 6 #define IA32_MTR_WRITE_BACK 6
// EFLAGS register
#define X86_EFLAGS_CARRY 0x00000001
#define X86_EFLAGS_RESERVED1 0x00000002
#define X86_EFLAGS_PARITY 0x00000004
#define X86_EFLAGS_AUXILIARY_CARRY 0x00000010
#define X86_EFLAGS_ZERO 0x00000040
#define X86_EFLAGS_SIGN 0x00000080
#define X86_EFLAGS_TRAP 0x00000100
#define X86_EFLAGS_INTERRUPT 0x00000200
#define X86_EFLAGS_DIRECTION 0x00000400
#define X86_EFLAGS_OVERFLOW 0x00000800
#define X86_EFLAGS_IO_PRIVILEG_LEVEL 0x00003000
#define X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT 12
#define X86_EFLAGS_NESTED_TASK 0x00004000
#define X86_EFLAGS_RESUME 0x00010000
#define X86_EFLAGS_V86_MODE 0x00020000
#define X86_EFLAGS_ALIGNMENT_CHECK 0x00040000
#define X86_EFLAGS_VIRTUAL_INTERRUPT 0x00080000
#define X86_EFLAGS_VIRTUAL_INTERRUPT_PENDING 0x00100000
#define X86_EFLAGS_ID 0x00200000
#define X86_EFLAGS_USER_FLAGS (X86_EFLAGS_CARRY | X86_EFLAGS_PARITY \
| X86_EFLAGS_AUXILIARY_CARRY | X86_EFLAGS_ZERO | X86_EFLAGS_SIGN \
| X86_EFLAGS_DIRECTION | X86_EFLAGS_OVERFLOW)
// iframe types // iframe types
#define IFRAME_TYPE_SYSCALL 0x1 #define IFRAME_TYPE_SYSCALL 0x1
#define IFRAME_TYPE_OTHER 0x2 #define IFRAME_TYPE_OTHER 0x2
@@ -276,7 +302,6 @@ void x86_context_switch(struct arch_thread* oldState,
struct arch_thread* newState); struct arch_thread* newState);
void x86_userspace_thread_exit(void); void x86_userspace_thread_exit(void);
void x86_end_userspace_thread_exit(void); void x86_end_userspace_thread_exit(void);
void x86_enter_userspace(addr_t entry, addr_t stackTop);
void x86_swap_pgdir(uint32 newPageDir); void x86_swap_pgdir(uint32 newPageDir);
void i386_set_tss_and_kstack(addr_t kstack); void i386_set_tss_and_kstack(addr_t kstack);
void i386_fnsave(void* fpuState); void i386_fnsave(void* fpuState);
@@ -24,9 +24,6 @@ uint32 x86_next_page_directory(Thread *from, Thread *to);
void x86_restart_syscall(struct iframe* frame); void x86_restart_syscall(struct iframe* frame);
void i386_return_from_signal();
void i386_end_return_from_signal();
// override empty macro // override empty macro
#undef arch_syscall_64_bit_return_value #undef arch_syscall_64_bit_return_value
void arch_syscall_64_bit_return_value(void); void arch_syscall_64_bit_return_value(void);
+10 -10
View File
@@ -56,18 +56,18 @@ public:
void Publish(const void* object, void Publish(const void* object,
const char* objectType); const char* objectType);
void Unpublish(bool threadsLocked = false); void Unpublish(bool schedulerLocked = false);
inline void NotifyOne(bool threadsLocked = false, inline void NotifyOne(bool schedulerLocked = false,
status_t result = B_OK); status_t result = B_OK);
inline void NotifyAll(bool threadsLocked = false, inline void NotifyAll(bool schedulerLocked = false,
status_t result = B_OK); status_t result = B_OK);
static void NotifyOne(const void* object, static void NotifyOne(const void* object,
bool threadsLocked = false, bool schedulerLocked = false,
status_t result = B_OK); status_t result = B_OK);
static void NotifyAll(const void* object, static void NotifyAll(const void* object,
bool threadsLocked = false, bool schedulerLocked = false,
status_t result = B_OK); status_t result = B_OK);
// (both methods) caller must ensure that // (both methods) caller must ensure that
// the variable is not unpublished // the variable is not unpublished
@@ -86,7 +86,7 @@ public:
void Dump() const; void Dump() const;
private: private:
void _Notify(bool all, bool threadsLocked, void _Notify(bool all, bool schedulerLocked,
status_t result); status_t result);
void _NotifyLocked(bool all, status_t result); void _NotifyLocked(bool all, status_t result);
@@ -124,16 +124,16 @@ ConditionVariableEntry::~ConditionVariableEntry()
inline void inline void
ConditionVariable::NotifyOne(bool threadsLocked, status_t result) ConditionVariable::NotifyOne(bool schedulerLocked, status_t result)
{ {
_Notify(false, threadsLocked, result); _Notify(false, schedulerLocked, result);
} }
inline void inline void
ConditionVariable::NotifyAll(bool threadsLocked, status_t result) ConditionVariable::NotifyAll(bool schedulerLocked, status_t result)
{ {
_Notify(true, threadsLocked, result); _Notify(true, schedulerLocked, result);
} }
+1
View File
@@ -51,6 +51,7 @@ typedef struct cpu_ent {
jmp_buf fault_jump_buffer; jmp_buf fault_jump_buffer;
Thread* running_thread; Thread* running_thread;
Thread* previous_thread;
bool invoke_scheduler; bool invoke_scheduler;
bool invoke_scheduler_if_idle; bool invoke_scheduler_if_idle;
bool disabled; bool disabled;
+7
View File
@@ -16,6 +16,12 @@
struct kernel_args; struct kernel_args;
struct elf_symbol_info {
addr_t address;
size_t size;
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -34,6 +40,7 @@ status_t elf_debug_lookup_user_symbol_address(Team* team, addr_t address,
addr_t *_baseAddress, const char **_symbolName, addr_t *_baseAddress, const char **_symbolName,
const char **_imageName, bool *_exactMatch); const char **_imageName, bool *_exactMatch);
addr_t elf_debug_lookup_symbol(const char* searchName); addr_t elf_debug_lookup_symbol(const char* searchName);
status_t elf_lookup_kernel_symbol(const char* name, elf_symbol_info* info);
struct elf_image_info* elf_get_kernel_image(); struct elf_image_info* elf_get_kernel_image();
status_t elf_get_image_info_for_address(addr_t address, image_info* info); status_t elf_get_image_info_for_address(addr_t address, image_info* info);
image_id elf_create_memory_image(const char* imageName, addr_t text, image_id elf_create_memory_image(const char* imageName, addr_t text,
+50 -16
View File
@@ -18,27 +18,59 @@ struct SchedulerListener;
struct scheduler_ops { struct scheduler_ops {
/*! Enqueues the thread in the ready-to-run queue.
The caller must hold the scheduler lock (with disabled interrupts).
*/
void (*enqueue_in_run_queue)(Thread* thread); void (*enqueue_in_run_queue)(Thread* thread);
/*! Selects a thread from the ready-to-run queue and, if that's not the
calling thread, switches the current CPU's context to run the selected
thread.
If it's the same thread, the thread will just continue to run.
In either case, unless the thread is dead or is sleeping/waiting
indefinitely, the function will eventually return.
The caller must hold the scheduler lock (with disabled interrupts).
*/
void (*reschedule)(void); void (*reschedule)(void);
/*! Sets the given thread's priority.
The thread may be running or may be in the ready-to-run queue.
The caller must hold the scheduler lock (with disabled interrupts).
*/
void (*set_thread_priority)(Thread* thread, int32 priority); void (*set_thread_priority)(Thread* thread, int32 priority);
bigtime_t (*estimate_max_scheduling_latency)(Thread* thread); bigtime_t (*estimate_max_scheduling_latency)(Thread* thread);
void (*on_thread_create)(Thread* thread); /*! Called when the Thread structure is first created.
// called when the thread structure is first created - Per-thread housekeeping resources can be allocated.
// initialization of per-thread housekeeping data structures should Interrupts must be enabled.
// be done here */
void (*on_thread_init)(Thread* thread); status_t (*on_thread_create)(Thread* thread, bool idleThread);
// called when a thread structure is initialized and made ready for
// use - should be used to reset the housekeeping data structures
// if needed
void (*on_thread_destroy)(Thread* thread);
// called when a thread structure is freed - freeing up any allocated
// mem on the scheduler's part should be done here
/*! Called when a Thread structure is initialized and made ready for
use.
The per-thread housekeeping data structures are reset, if needed.
The caller must hold the scheduler lock (with disabled interrupts).
*/
void (*on_thread_init)(Thread* thread);
/*! Called when a Thread structure is freed.
Frees up any per-thread resources allocated on the scheduler's part. The
function may be called even if on_thread_create() failed.
Interrupts must be enabled.
*/
void (*on_thread_destroy)(Thread* thread);
/*! Called in the early boot process to start thread scheduling on the
current CPU.
The function is called once for each CPU.
Interrupts must be disabled, but the caller must not hold the scheduler
lock.
*/
void (*start)(void); void (*start)(void);
}; };
extern struct scheduler_ops* gScheduler; extern struct scheduler_ops* gScheduler;
extern spinlock gSchedulerLock;
#define scheduler_enqueue_in_run_queue(thread) \ #define scheduler_enqueue_in_run_queue(thread) \
gScheduler->enqueue_in_run_queue(thread) gScheduler->enqueue_in_run_queue(thread)
@@ -46,8 +78,8 @@ extern struct scheduler_ops* gScheduler;
gScheduler->set_thread_priority(thread, priority) gScheduler->set_thread_priority(thread, priority)
#define scheduler_reschedule() gScheduler->reschedule() #define scheduler_reschedule() gScheduler->reschedule()
#define scheduler_start() gScheduler->start() #define scheduler_start() gScheduler->start()
#define scheduler_on_thread_create(thread) \ #define scheduler_on_thread_create(thread, idleThread) \
gScheduler->on_thread_create(thread) gScheduler->on_thread_create(thread, idleThread)
#define scheduler_on_thread_init(thread) \ #define scheduler_on_thread_init(thread) \
gScheduler->on_thread_init(thread) gScheduler->on_thread_init(thread)
#define scheduler_on_thread_destroy(thread) \ #define scheduler_on_thread_destroy(thread) \
@@ -73,7 +105,7 @@ status_t _user_analyze_scheduling(bigtime_t from, bigtime_t until, void* buffer,
/*! Reschedules, if necessary. /*! Reschedules, if necessary.
The thread spinlock must be held. The caller must hold the scheduler lock (with disabled interrupts).
*/ */
static inline void static inline void
scheduler_reschedule_if_necessary_locked() scheduler_reschedule_if_necessary_locked()
@@ -91,9 +123,11 @@ scheduler_reschedule_if_necessary()
{ {
if (are_interrupts_enabled()) { if (are_interrupts_enabled()) {
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
GRAB_THREAD_LOCK(); acquire_spinlock(&gSchedulerLock);
scheduler_reschedule_if_necessary_locked(); scheduler_reschedule_if_necessary_locked();
RELEASE_THREAD_LOCK();
release_spinlock(&gSchedulerLock);
restore_interrupts(state); restore_interrupts(state);
} }
} }
+207 -24
View File
@@ -1,57 +1,240 @@
/* /*
* Copyright 2003-2008, Axel Dörfler, [email protected]. All rights reserved. * Copyright 2011, Ingo Weinhold, [email protected].
* Copyright 2003-2008, Axel Dörfler, [email protected].
* All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _KERNEL_SIGNAL_H #ifndef _KERNEL_SIGNAL_H
#define _KERNEL_SIGNAL_H #define _KERNEL_SIGNAL_H
#include <KernelExport.h>
#include <signal.h> #include <signal.h>
#include <KernelExport.h>
#include <signal_defs.h>
#include <heap.h>
#include <util/DoublyLinkedList.h>
#include <util/KernelReferenceable.h>
namespace BKernel { namespace BKernel {
struct ProcessGroup;
struct Team;
struct Thread; struct Thread;
} }
using BKernel::ProcessGroup;
using BKernel::Team;
using BKernel::Thread; using BKernel::Thread;
#define KILL_SIGNALS ((1L << (SIGKILL - 1)) | (1L << (SIGKILLTHR - 1))) #define KILL_SIGNALS \
(((sigset_t)1 << (SIGKILL - 1)) | ((sigset_t)1 << (SIGKILLTHR - 1)))
#define SIGNAL_TO_MASK(signal) (1LL << (signal - 1)) #define SYSCALL_RESTART_PARAMETER_SIZE 32
// additional send_signal_etc() flag // kernel-internal signals
#define SIGNAL_FLAG_TEAMS_LOCKED (0x10000) #define SIGNAL_CANCEL_THREAD 63
// interrupts are disabled and team lock is held // Cancel a thread. Non-blockable.
#define SIGNAL_FLAG_DONT_RESTART_SYSCALL (0x20000) #define SIGNAL_CONTINUE_THREAD 64
// Continue a thread. Used by resume_thread(). Non-blockable, prevents
// syscall restart.
struct signal_frame_data {
siginfo_t info;
ucontext_t context;
void* user_data;
void* handler;
bool siginfo_handler;
int32 thread_flags;
uint64 syscall_restart_return_value;
uint8 syscall_restart_parameters[SYSCALL_RESTART_PARAMETER_SIZE];
};
namespace BKernel {
struct QueuedSignalsCounter : BReferenceable {
QueuedSignalsCounter(int32 limit);
bool Increment();
void Decrement() { ReleaseReference(); }
private:
int32 fLimit;
};
struct Signal : KernelReferenceable, DoublyLinkedListLinkImpl<Signal> {
public:
Signal();
// cheap no-init constructor
Signal(const Signal& other);
Signal(uint32 number, int32 signalCode,
int32 errorCode, pid_t sendingProcess);
virtual ~Signal();
static status_t CreateQueuable(const Signal& signal,
bool queuingRequired,
Signal*& _signalToQueue);
void SetTo(uint32 number);
uint32 Number() const { return fNumber; }
void SetNumber(uint32 number)
{ fNumber = number; }
int32 Priority() const;
int32 SignalCode() const
{ return fSignalCode; }
int32 ErrorCode() const
{ return fErrorCode; }
pid_t SendingProcess() const
{ return fSendingProcess; }
uid_t SendingUser() const
{ return fSendingUser; }
void SetSendingUser(uid_t user)
{ fSendingUser = user; }
int32 Status() const
{ return fStatus; }
void SetStatus(int32 status)
{ fStatus = status; }
int32 PollBand() const
{ return fPollBand; }
void SetPollBand(int32 pollBand)
{ fPollBand = pollBand; }
void* Address() const
{ return fAddress; }
void SetAddress(void* address)
{ fAddress = address; }
union sigval UserValue() const
{ return fUserValue; }
void SetUserValue(union sigval userValue)
{ fUserValue = userValue; }
bool IsPending() const
{ return fPending; }
void SetPending(bool pending)
{ fPending = pending; }
virtual void Handled();
protected:
virtual void LastReferenceReleased();
private:
QueuedSignalsCounter* fCounter;
uint32 fNumber;
int32 fSignalCode;
int32 fErrorCode; // error code associated with the
// signal
pid_t fSendingProcess;
uid_t fSendingUser;
int32 fStatus; // exit value
int32 fPollBand; // for SIGPOLL
void* fAddress;
union sigval fUserValue;
bool fPending;
};
struct PendingSignals {
PendingSignals();
~PendingSignals();
sigset_t AllSignals() const
{ return fQueuedSignalsMask
| fUnqueuedSignalsMask; }
int32 HighestSignalPriority(sigset_t nonBlocked)
const;
void Clear();
void AddSignal(int32 signal)
{ fUnqueuedSignalsMask
|= SIGNAL_TO_MASK(signal); }
void AddSignal(Signal* signal);
void RemoveSignal(int32 signal)
{ RemoveSignals(SIGNAL_TO_MASK(signal)); }
void RemoveSignal(Signal* signal);
void RemoveSignals(sigset_t mask);
Signal* DequeueSignal(sigset_t nonBlocked,
Signal& buffer);
private:
typedef DoublyLinkedList<Signal> SignalList;
private:
int32 _GetHighestPrioritySignal(sigset_t nonBlocked,
Signal*& _queuedSignal,
int32& _unqueuedSignal) const;
void _UpdateQueuedSignalMask();
private:
sigset_t fQueuedSignalsMask;
sigset_t fUnqueuedSignalsMask;
SignalList fQueuedSignals;
};
} // namespace BKernel
using BKernel::PendingSignals;
using BKernel::QueuedSignalsCounter;
using BKernel::Signal;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern bool handle_signals(Thread *thread); void handle_signals(Thread* thread);
extern bool is_kill_signal_pending(void); bool is_team_signal_blocked(Team* team, int signal);
extern int has_signals_pending(void *_thread); void signal_get_user_stack(addr_t address, stack_t* stack);
extern bool is_signal_blocked(int signal);
extern void update_current_thread_signals_flag(); status_t send_signal_to_thread_locked(Thread* thread, uint32 signalNumber,
Signal* signal, uint32 flags);
status_t send_signal_to_thread(Thread* thread, const Signal& signal,
uint32 flags);
status_t send_signal_to_thread_id(thread_id threadID, const Signal& signal,
uint32 flags);
extern int sigaction_etc(thread_id threadID, int signal, status_t send_signal_to_team_locked(Team* team, uint32 signalNumber,
const struct sigaction *newAction, struct sigaction *oldAction); Signal* signal, uint32 flags);
status_t send_signal_to_team(Team* team, const Signal& signal, uint32 flags);
status_t send_signal_to_team_id(team_id teamID, const Signal& signal,
uint32 flags);
extern status_t _user_send_signal(pid_t tid, uint sig); status_t send_signal_to_process_group_locked(ProcessGroup* group,
extern status_t _user_sigprocmask(int how, const sigset_t *set, const Signal& signal, uint32 flags);
sigset_t *oldSet); status_t send_signal_to_process_group(pid_t groupID, const Signal& signal,
extern status_t _user_sigaction(int sig, const struct sigaction *newAction, uint32 flags);
status_t _user_send_signal(int32 id, uint32 signal,
const union sigval* userValue, uint32 flags);
status_t _user_set_signal_mask(int how, const sigset_t *set, sigset_t *oldSet);
status_t _user_sigaction(int sig, const struct sigaction *newAction,
struct sigaction *oldAction); struct sigaction *oldAction);
extern bigtime_t _user_set_alarm(bigtime_t time, uint32 mode); bigtime_t _user_set_alarm(bigtime_t time, uint32 mode);
extern status_t _user_sigwait(const sigset_t *set, int *_signal); status_t _user_sigwait(const sigset_t *set, siginfo_t *info, uint32 flags,
extern status_t _user_sigsuspend(const sigset_t *mask); bigtime_t timeout);
extern status_t _user_sigpending(sigset_t *set); status_t _user_sigsuspend(const sigset_t *mask);
extern status_t _user_set_signal_stack(const stack_t *newUserStack, status_t _user_sigpending(sigset_t *set);
status_t _user_set_signal_stack(const stack_t *newUserStack,
stack_t *oldUserStack); stack_t *oldUserStack);
int64 _user_restore_signal_frame(struct signal_frame_data* signalFrameData);
#ifdef __cplusplus #ifdef __cplusplus
} }
+5 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2008-2010, Ingo Weinhold, [email protected]. * Copyright 2008-2011, Ingo Weinhold, [email protected].
* Copyright 2002-2009, Axel Dörfler, [email protected]. * Copyright 2002-2009, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
@@ -144,11 +144,11 @@ extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to);
extern status_t _rw_lock_read_lock(rw_lock* lock); extern status_t _rw_lock_read_lock(rw_lock* lock);
extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock, extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock,
uint32 timeoutFlags, bigtime_t timeout); uint32 timeoutFlags, bigtime_t timeout);
extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked); extern void _rw_lock_read_unlock(rw_lock* lock, bool schedulerLocked);
extern void _rw_lock_write_unlock(rw_lock* lock, bool threadsLocked); extern void _rw_lock_write_unlock(rw_lock* lock, bool schedulerLocked);
extern status_t _mutex_lock(mutex* lock, bool threadsLocked); extern status_t _mutex_lock(mutex* lock, bool schedulerLocked);
extern void _mutex_unlock(mutex* lock, bool threadsLocked); extern void _mutex_unlock(mutex* lock, bool schedulerLocked);
extern status_t _mutex_trylock(mutex* lock); extern status_t _mutex_trylock(mutex* lock);
extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
bigtime_t timeout); bigtime_t timeout);
+3 -1
View File
@@ -22,6 +22,8 @@ struct kernel_args;
extern "C" { extern "C" {
#endif #endif
void set_real_time_clock_usecs(bigtime_t currentTime);
status_t rtc_init(struct kernel_args *args); status_t rtc_init(struct kernel_args *args);
bigtime_t rtc_boot_time(void); bigtime_t rtc_boot_time(void);
// Returns the time at which the system was booted in microseconds since Jan 1, 1970 UTC. // Returns the time at which the system was booted in microseconds since Jan 1, 1970 UTC.
@@ -34,7 +36,7 @@ void rtc_secs_to_tm(uint32 seconds, struct tm *t);
uint32 get_timezone_offset(void); uint32 get_timezone_offset(void);
bigtime_t _user_system_time(void); bigtime_t _user_system_time(void);
status_t _user_set_real_time_clock(uint32 time); status_t _user_set_real_time_clock(bigtime_t time);
status_t _user_set_timezone(int32 timezoneOffset, const char *name, status_t _user_set_timezone(int32 timezoneOffset, const char *name,
size_t nameLength); size_t nameLength);
status_t _user_get_timezone(int32 *_timezoneOffset, char* name, status_t _user_get_timezone(int32 *_timezoneOffset, char* name,
+7 -13
View File
@@ -22,12 +22,11 @@ extern "C" {
status_t team_init(struct kernel_args *args); status_t team_init(struct kernel_args *args);
status_t wait_for_team(team_id id, status_t *returnCode); status_t wait_for_team(team_id id, status_t *returnCode);
void team_remove_team(Team *team);
port_id team_shutdown_team(Team *team, cpu_status& state); void team_remove_team(Team *team, pid_t& _signalGroup);
port_id team_shutdown_team(Team *team);
void team_delete_team(Team *team, port_id debuggerPort); void team_delete_team(Team *team, port_id debuggerPort);
struct process_group *team_get_process_group_locked(
struct process_session *session, pid_t id);
void team_delete_process_group(struct process_group *group);
Team *team_get_kernel_team(void); Team *team_get_kernel_team(void);
team_id team_get_kernel_team_id(void); team_id team_get_kernel_team_id(void);
team_id team_get_current_team_id(void); team_id team_get_current_team_id(void);
@@ -42,15 +41,11 @@ Team *team_get_team_struct_locked(team_id id);
int32 team_max_teams(void); int32 team_max_teams(void);
int32 team_used_teams(void); int32 team_used_teams(void);
typedef bool (*team_iterator_callback)(Team* team, void* cookie);
Team* team_iterate_through_teams(team_iterator_callback callback,
void* cookie);
thread_id load_image_etc(int32 argCount, const char* const* args, thread_id load_image_etc(int32 argCount, const char* const* args,
const char* const* env, int32 priority, team_id parentID, uint32 flags); const char* const* env, int32 priority, team_id parentID, uint32 flags);
void team_set_job_control_state(Team* team, job_control_state newState, void team_set_job_control_state(Team* team, job_control_state newState,
int signal, bool threadsLocked); Signal* signal, bool threadsLocked);
void team_set_controlling_tty(int32 index); void team_set_controlling_tty(int32 index);
int32 team_get_controlling_tty(); int32 team_get_controlling_tty();
status_t team_set_foreground_process_group(int32 ttyIndex, pid_t processGroup); status_t team_set_foreground_process_group(int32 ttyIndex, pid_t processGroup);
@@ -61,7 +56,7 @@ status_t stop_watching_team(team_id team, void (*hook)(team_id, void *),
void *data); void *data);
struct user_thread* team_allocate_user_thread(Team* team); struct user_thread* team_allocate_user_thread(Team* team);
void team_free_user_thread(Thread* thread); void team_free_user_thread(Team* team, struct user_thread* userThread);
bool team_associate_data(AssociatedData* data); bool team_associate_data(AssociatedData* data);
bool team_dissociate_data(AssociatedData* data); bool team_dissociate_data(AssociatedData* data);
@@ -73,8 +68,7 @@ thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize,
status_t _user_wait_for_team(team_id id, status_t *_returnCode); status_t _user_wait_for_team(team_id id, status_t *_returnCode);
void _user_exit_team(status_t returnValue); void _user_exit_team(status_t returnValue);
status_t _user_kill_team(thread_id thread); status_t _user_kill_team(thread_id thread);
thread_id _user_wait_for_child(thread_id child, uint32 flags, int32 *_reason, pid_t _user_wait_for_child(thread_id child, uint32 flags, siginfo_t* info);
status_t *_returnCode);
status_t _user_exec(const char *path, const char* const* flatArgs, status_t _user_exec(const char *path, const char* const* flatArgs,
size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask); size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask);
thread_id _user_fork(void); thread_id _user_fork(void);
+235 -23
View File
@@ -19,6 +19,7 @@
#include <ksignal.h> #include <ksignal.h>
struct arch_fork_arg;
struct kernel_args; struct kernel_args;
struct select_info; struct select_info;
struct thread_creation_attributes; struct thread_creation_attributes;
@@ -31,6 +32,43 @@ struct thread_creation_attributes;
#define THREAD_NAME_CHANGED 0x04 #define THREAD_NAME_CHANGED 0x04
namespace BKernel {
struct ThreadCreationAttributes : thread_creation_attributes {
// when calling from kernel only
team_id team;
Thread* thread;
sigset_t signal_mask;
size_t additional_stack_size; // additional space in the stack
// area after the TLS region, not
// used as thread stack
thread_func kernelEntry;
void* kernelArgument;
arch_fork_arg* forkArgs; // If non-NULL, the userland thread
// will be started with this
// register context.
public:
ThreadCreationAttributes() {}
// no-init constructor
ThreadCreationAttributes(
thread_func function, const char* name,
int32 priority, void* arg,
team_id team = -1, Thread* thread = NULL);
status_t InitFromUserAttributes(
const thread_creation_attributes*
userAttributes,
char* nameBuffer);
};
} // namespace BKernel
using BKernel::ThreadCreationAttributes;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -61,9 +99,6 @@ void thread_set_io_priority(int32 priority);
#define thread_get_current_thread arch_thread_get_current_thread #define thread_get_current_thread arch_thread_get_current_thread
Thread *thread_get_thread_struct(thread_id id);
Thread *thread_get_thread_struct_locked(thread_id id);
static thread_id thread_get_current_thread_id(void); static thread_id thread_get_current_thread_id(void);
static inline thread_id static inline thread_id
thread_get_current_thread_id(void) thread_get_current_thread_id(void)
@@ -75,18 +110,21 @@ thread_get_current_thread_id(void)
static inline bool static inline bool
thread_is_idle_thread(Thread *thread) thread_is_idle_thread(Thread *thread)
{ {
return thread->entry == NULL; return thread->priority == B_IDLE_PRIORITY;
} }
typedef bool (*thread_iterator_callback)(Thread* thread, void* cookie); thread_id allocate_thread_id();
Thread* thread_iterate_through_threads(thread_iterator_callback callback, thread_id peek_next_thread_id();
void* cookie);
thread_id allocate_thread_id(void); status_t thread_enter_userspace_new_team(Thread* thread, addr_t entryFunction,
thread_id peek_next_thread_id(void); void* argument1, void* argument2);
status_t thread_create_user_stack(Team* team, Thread* thread, void* stackBase,
size_t stackSize, size_t additionalSize);
thread_id thread_create_thread(const ThreadCreationAttributes& attributes,
bool kernel);
thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority, thread_id spawn_kernel_thread_etc(thread_func, const char *name, int32 priority,
void *args, team_id team, thread_id threadID); void *args, team_id team);
status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
status_t *_returnCode); status_t *_returnCode);
@@ -99,7 +137,6 @@ status_t thread_block();
status_t thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout); status_t thread_block_with_timeout(uint32 timeoutFlags, bigtime_t timeout);
status_t thread_block_with_timeout_locked(uint32 timeoutFlags, status_t thread_block_with_timeout_locked(uint32 timeoutFlags,
bigtime_t timeout); bigtime_t timeout);
void thread_unblock(status_t threadID, status_t status);
// used in syscalls.c // used in syscalls.c
status_t _user_set_thread_priority(thread_id thread, int32 newPriority); status_t _user_set_thread_priority(thread_id thread, int32 newPriority);
@@ -109,8 +146,10 @@ status_t _user_resume_thread(thread_id thread);
status_t _user_rename_thread(thread_id thread, const char *name); status_t _user_rename_thread(thread_id thread, const char *name);
thread_id _user_spawn_thread(struct thread_creation_attributes* attributes); thread_id _user_spawn_thread(struct thread_creation_attributes* attributes);
status_t _user_wait_for_thread(thread_id id, status_t *_returnCode); status_t _user_wait_for_thread(thread_id id, status_t *_returnCode);
status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags); status_t _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags,
bigtime_t* _remainingTime);
status_t _user_kill_thread(thread_id thread); status_t _user_kill_thread(thread_id thread);
status_t _user_cancel_thread(thread_id threadID, void (*cancelFunction)(int));
void _user_thread_yield(void); void _user_thread_yield(void);
void _user_exit_thread(status_t return_value); void _user_exit_thread(status_t return_value);
bool _user_has_data(thread_id thread); bool _user_has_data(thread_id thread);
@@ -135,20 +174,41 @@ int _user_setrlimit(int resource, const struct rlimit * rlp);
#endif #endif
/*! /*! Checks whether the current thread would immediately be interrupted when
\a thread must be the current thread. blocking it with the given wait/interrupt flags.
Thread lock can be, but doesn't need to be held.
The caller must hold the scheduler lock.
\param thread The current thread.
\param flags Wait/interrupt flags to be considered. Relevant are:
- \c B_CAN_INTERRUPT: The thread can be interrupted by any non-blocked
signal. Implies \c B_KILL_CAN_INTERRUPT (specified or not).
- \c B_KILL_CAN_INTERRUPT: The thread can be interrupted by a kill
signal.
\return \c true, if the thread would be interrupted, \c false otherwise.
*/ */
static inline bool static inline bool
thread_is_interrupted(Thread* thread, uint32 flags) thread_is_interrupted(Thread* thread, uint32 flags)
{ {
return ((flags & B_CAN_INTERRUPT) sigset_t pendingSignals = thread->AllPendingSignals();
&& (thread->sig_pending & ~thread->sig_block_mask) != 0) return ((flags & B_CAN_INTERRUPT) != 0
|| ((flags & B_KILL_CAN_INTERRUPT) && (pendingSignals & ~thread->sig_block_mask) != 0)
&& (thread->sig_pending & KILL_SIGNALS)); || ((flags & B_KILL_CAN_INTERRUPT) != 0
&& (pendingSignals & KILL_SIGNALS) != 0);
} }
/*! Checks wether the given thread is currently blocked (i.e. still waiting for
something).
If a stable answer is required, the caller must hold the scheduler lock.
Alternatively, if waiting is not interruptible and cannot time out, holding
the client lock held when calling thread_prepare_to_block() and the
unblocking functions works as well.
\param thread The thread in question.
\return \c true, if the thread is blocked, \c false otherwise.
*/
static inline bool static inline bool
thread_is_blocked(Thread* thread) thread_is_blocked(Thread* thread)
{ {
@@ -156,9 +216,109 @@ thread_is_blocked(Thread* thread)
} }
/*! /*! Prepares the current thread for waiting.
\a thread must be the current thread.
Thread lock can be, but doesn't need to be locked. This is the first of two steps necessary to block the current thread
(IOW, to let it wait for someone else to unblock it or optionally time out
after a specified delay). The process consists of two steps to avoid race
conditions in case a lock other than the scheduler lock is involved.
Usually the thread waits for some condition to change and this condition is
something reflected in the caller's data structures which should be
protected by a client lock the caller knows about. E.g. in the semaphore
code that lock is a per-semaphore spinlock that protects the semaphore data,
including the semaphore count and the queue of waiting threads. For certain
low-level locking primitives (e.g. mutexes) that client lock is the
scheduler lock itself, which simplifies things a bit.
If a client lock other than the scheduler lock is used, this function must
be called with that lock being held. Afterwards that lock should be dropped
and the function that actually blocks the thread shall be invoked
(thread_block[_locked]() or thread_block_with_timeout[_locked]()). In
between these two steps no functionality that uses the thread blocking API
for this thread shall be used.
When the caller determines that the condition for unblocking the thread
occurred, it calls thread_unblock_locked() to unblock the thread. At that
time one of locks that are held when calling thread_prepare_to_block() must
be held. Usually that would be the client lock. In two cases it generally
isn't, however, since the unblocking code doesn't know about the client
lock: 1. When thread_block_with_timeout[_locked]() had been used and the
timeout occurs. 2. When thread_prepare_to_block() had been called with one
or both of the \c B_CAN_INTERRUPT or \c B_KILL_CAN_INTERRUPT flags specified
and someone calls thread_interrupt() that is supposed to wake up the thread.
In either of these two cases only the scheduler lock is held by the
unblocking code. A timeout can only happen after
thread_block_with_timeout_locked() has been called, but an interruption is
possible at any time. The client code must deal with those situations.
Generally blocking and unblocking threads proceed in the following manner:
Blocking thread:
- Acquire client lock.
- Check client condition and decide whether blocking is necessary.
- Modify some client data structure to indicate that this thread is now
waiting.
- Release client lock (unless client lock is the scheduler lock).
- Block.
- Acquire client lock (unless client lock is the scheduler lock).
- Check client condition and compare with block result. E.g. if the wait was
interrupted or timed out, but the client condition indicates success, it
may be considered a success after all, since usually that happens when
another thread concurrently changed the client condition and also tried
to unblock the waiting thread. It is even necessary when that other
thread changed the client data structures in a way that associate some
resource with the unblocked thread, or otherwise the unblocked thread
would have to reverse that here.
- If still necessary -- i.e. not already taken care of by an unblocking
thread -- modify some client structure to indicate that the thread is no
longer waiting, so it isn't erroneously unblocked later.
Unblocking thread:
- Acquire client lock.
- Check client condition and decide whether a blocked thread can be woken
up.
- Check the client data structure that indicates whether one or more threads
are waiting and which thread(s) need(s) to be woken up.
- Unblock respective thread(s).
- Possibly change some client structure, so that an unblocked thread can
decide whether a concurrent timeout/interruption can be ignored, or
simply so that it doesn't have to do any more cleanup.
Note that in the blocking thread the steps after blocking are strictly
required only if timeouts or interruptions are possible. If they are not,
the blocking thread can only be woken up explicitly by an unblocking thread,
which could already take care of all the necessary client data structure
modifications, so that the blocking thread wouldn't have to do that.
Note that the client lock can but does not have to be a spinlock.
A mutex, a semaphore, or anything that doesn't try to use the thread
blocking API for the calling thread when releasing the lock is fine.
In particular that means in principle thread_prepare_to_block() can be
called with interrupts enabled.
Care must be taken when the wait can be interrupted or can time out,
especially with a client lock that uses the thread blocking API. After a
blocked thread has been interrupted or the the time out occurred it cannot
acquire the client lock (or any other lock using the thread blocking API)
without first making sure that the thread doesn't still appears to be
waiting to other client code. Otherwise another thread could try to unblock
it which could erroneously unblock the thread while already waiting on the
client lock. So usually when interruptions or timeouts are possible a
spinlock needs to be involved.
\param thread The current thread.
\param flags The blocking flags. Relevant are:
- \c B_CAN_INTERRUPT: The thread can be interrupted by any non-blocked
signal. Implies \c B_KILL_CAN_INTERRUPT (specified or not).
- \c B_KILL_CAN_INTERRUPT: The thread can be interrupted by a kill
signal.
\param type The type of object the thread will be blocked at. Informative/
for debugging purposes. Must be one of the \c THREAD_BLOCK_TYPE_*
constants. \c THREAD_BLOCK_TYPE_OTHER implies that \a object is a
string.
\param object The object the thread will be blocked at. Informative/for
debugging purposes.
*/ */
static inline void static inline void
thread_prepare_to_block(Thread* thread, uint32 flags, uint32 type, thread_prepare_to_block(Thread* thread, uint32 flags, uint32 type,
@@ -173,11 +333,27 @@ thread_prepare_to_block(Thread* thread, uint32 flags, uint32 type,
} }
/*! Blocks the current thread.
The thread is blocked until someone else unblock it. Must be called after a
call to thread_prepare_to_block(). If the thread has already been unblocked
after the previous call to thread_prepare_to_block(), this function will
return immediately. Cf. the documentation of thread_prepare_to_block() for
more details.
The caller must hold the scheduler lock.
\param thread The current thread.
\return The error code passed to the unblocking function. thread_interrupt()
uses \c B_INTERRUPTED. By convention \c B_OK means that the wait was
successful while another error code indicates a failure (what that means
depends on the client code).
*/
static inline status_t static inline status_t
thread_block_locked(Thread* thread) thread_block_locked(Thread* thread)
{ {
if (thread->wait.status == 1) { if (thread->wait.status == 1) {
// check for signals, if interruptable // check for signals, if interruptible
if (thread_is_interrupted(thread, thread->wait.flags)) { if (thread_is_interrupted(thread, thread->wait.flags)) {
thread->wait.status = B_INTERRUPTED; thread->wait.status = B_INTERRUPTED;
} else { } else {
@@ -190,6 +366,19 @@ thread_block_locked(Thread* thread)
} }
/*! Unblocks the specified blocked thread.
If the thread is no longer waiting (e.g. because thread_unblock_locked() has
already been called in the meantime), this function does not have any
effect.
The caller must hold the scheduler lock and the client lock (might be the
same).
\param thread The thread to be unblocked.
\param status The unblocking status. That's what the unblocked thread's
call to thread_block_locked() will return.
*/
static inline void static inline void
thread_unblock_locked(Thread* thread, status_t status) thread_unblock_locked(Thread* thread, status_t status)
{ {
@@ -202,6 +391,29 @@ thread_unblock_locked(Thread* thread, status_t status)
} }
/*! Interrupts the specified blocked thread, if possible.
The function checks whether the thread can be interrupted and, if so, calls
\code thread_unblock_locked(thread, B_INTERRUPTED) \endcode. Otherwise the
function is a no-op.
The caller must hold the scheduler lock. Normally thread_unblock_locked()
also requires the client lock to be held, but in this case the caller
usually doesn't know it. This implies that the client code needs to take
special care, if waits are interruptible. See thread_prepare_to_block() for
more information.
\param thread The thread to be interrupted.
\param kill If \c false, the blocked thread is only interrupted, when the
flag \c B_CAN_INTERRUPT was specified for the blocked thread. If
\c true, it is only interrupted, when at least one of the flags
\c B_CAN_INTERRUPT or \c B_KILL_CAN_INTERRUPT was specified for the
blocked thread.
\return \c B_OK, if the thread is interruptible and thread_unblock_locked()
was called, \c B_NOT_ALLOWED otherwise. \c B_OK doesn't imply that the
thread actually has been interrupted -- it could have been unblocked
before already.
*/
static inline status_t static inline status_t
thread_interrupt(Thread* thread, bool kill) thread_interrupt(Thread* thread, bool kill)
{ {
+504 -103
View File
@@ -10,30 +10,23 @@
#ifndef _ASSEMBLER #ifndef _ASSEMBLER
#include <Referenceable.h> #include <pthread.h>
#include <arch/thread_types.h> #include <arch/thread_types.h>
#include <condition_variable.h> #include <condition_variable.h>
#include <heap.h>
#include <ksignal.h>
#include <lock.h> #include <lock.h>
#include <signal.h>
#include <smp.h> #include <smp.h>
#include <thread_defs.h> #include <thread_defs.h>
#include <timer.h> #include <timer.h>
#include <UserTimer.h>
#include <user_debugger.h> #include <user_debugger.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/KernelReferenceable.h>
#include <util/list.h> #include <util/list.h>
extern spinlock gThreadSpinlock;
#define GRAB_THREAD_LOCK() acquire_spinlock(&gThreadSpinlock)
#define RELEASE_THREAD_LOCK() release_spinlock(&gThreadSpinlock)
extern spinlock gTeamSpinlock;
// NOTE: TEAM lock can be held over a THREAD lock acquisition,
// but not the other way (to avoid deadlock)
#define GRAB_TEAM_LOCK() acquire_spinlock(&gTeamSpinlock)
#define RELEASE_TEAM_LOCK() release_spinlock(&gTeamSpinlock)
enum additional_thread_state { enum additional_thread_state {
THREAD_STATE_FREE_ON_RESCHED = 7, // free the thread structure upon reschedule THREAD_STATE_FREE_ON_RESCHED = 7, // free the thread structure upon reschedule
// THREAD_STATE_BIRTH // thread is being created // THREAD_STATE_BIRTH // thread is being created
@@ -44,8 +37,10 @@ enum additional_thread_state {
enum team_state { enum team_state {
TEAM_STATE_NORMAL, // normal state TEAM_STATE_NORMAL, // normal state
TEAM_STATE_BIRTH, // being contructed TEAM_STATE_BIRTH, // being constructed
TEAM_STATE_DEATH // being killed TEAM_STATE_SHUTDOWN, // still lives, but is going down
TEAM_STATE_DEATH // only the Team object still exists, threads are
// gone
}; };
#define TEAM_FLAG_EXEC_DONE 0x01 #define TEAM_FLAG_EXEC_DONE 0x01
@@ -71,33 +66,14 @@ struct xsi_sem_context; // defined in xsi_semaphore.cpp
namespace BKernel { namespace BKernel {
struct Team; struct Team;
struct Thread; struct Thread;
struct ProcessGroup;
} }
struct death_entry { struct thread_death_entry {
struct list_link link; struct list_link link;
pid_t group_id;
thread_id thread; thread_id thread;
status_t status; status_t status;
uint16 reason;
uint16 signal;
};
struct process_session {
pid_t id;
int32 group_count;
int32 controlling_tty; // index of the controlling tty,
// -1 if none
pid_t foreground_group;
};
struct process_group {
struct process_group *next; // next in hash
struct process_session *session;
pid_t id;
int32 refs;
BKernel::Team *teams;
bool orphaned;
}; };
struct team_loading_info { struct team_loading_info {
@@ -122,7 +98,9 @@ struct team_watcher {
struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> { struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> {
job_control_state state; // current team job control state job_control_state state; // current team job control state
thread_id thread; // main thread ID == team ID thread_id thread; // main thread ID == team ID
uint16 signal; // signal causing the current state
bool has_group_ref; bool has_group_ref;
uid_t signaling_user;
// valid while state != JOB_CONTROL_STATE_DEAD // valid while state != JOB_CONTROL_STATE_DEAD
BKernel::Team* team; BKernel::Team* team;
@@ -130,8 +108,8 @@ struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> {
// valid when state == JOB_CONTROL_STATE_DEAD // valid when state == JOB_CONTROL_STATE_DEAD
pid_t group_id; pid_t group_id;
status_t status; status_t status;
uint16 reason; uint16 reason; // reason for the team's demise, one of the
uint16 signal; // CLD_* values defined in <signal.h>
job_control_entry(); job_control_entry();
~job_control_entry(); ~job_control_entry();
@@ -215,41 +193,67 @@ typedef bool (*page_fault_callback)(addr_t address, addr_t faultAddress,
namespace BKernel { namespace BKernel {
struct Team : AssociatedDataOwner {
Team *next; // next in hash template<typename IDType>
Team *siblings_next; struct TeamThreadIteratorEntry
Team *parent; : DoublyLinkedListLinkImpl<TeamThreadIteratorEntry<IDType> > {
Team *children; typedef IDType id_type;
Team *group_next; typedef TeamThreadIteratorEntry<id_type> iterator_type;
team_id id;
id_type id; // -1 for iterator entries, >= 0 for actual elements
bool visible; // the entry is publicly visible
};
struct Team : TeamThreadIteratorEntry<team_id>, KernelReferenceable,
AssociatedDataOwner {
DoublyLinkedListLink<Team> global_list_link;
Team *hash_next; // next in hash
Team *siblings_next; // next in parent's list; protected by
// parent's fLock
Team *parent; // write-protected by both parent (if any)
// and this team's fLock
Team *children; // protected by this team's fLock;
// adding/removing a child also requires the
// child's fLock
Team *group_next; // protected by the group's lock
int64 serial_number; // immutable after adding team to hash
// process group info -- write-protected by both the group's lock, the
// team's lock, and the team's parent's lock
pid_t group_id; pid_t group_id;
pid_t session_id; pid_t session_id;
struct process_group *group; ProcessGroup *group;
char name[B_OS_NAME_LENGTH];
char args[64]; // contents for the team_info::args field
int num_threads; // number of threads in this team int num_threads; // number of threads in this team
int state; // current team state, see above int state; // current team state, see above
int32 flags; int32 flags;
struct io_context *io_context; struct io_context *io_context;
struct realtime_sem_context *realtime_sem_context; struct realtime_sem_context *realtime_sem_context;
struct xsi_sem_context *xsi_sem_context; struct xsi_sem_context *xsi_sem_context;
struct team_death_entry *death_entry; struct team_death_entry *death_entry; // protected by fLock
struct list dead_threads; struct list dead_threads;
int dead_threads_count; int dead_threads_count;
// protected by the team's fLock
team_dead_children dead_children; team_dead_children dead_children;
team_job_control_children stopped_children; team_job_control_children stopped_children;
team_job_control_children continued_children; team_job_control_children continued_children;
// protected by the parent team's fLock
struct job_control_entry* job_control_entry; struct job_control_entry* job_control_entry;
VMAddressSpace *address_space; VMAddressSpace *address_space;
Thread *main_thread; Thread *main_thread; // protected by fLock and the scheduler
Thread *thread_list; // lock (and the thread's lock), immutable
struct team_loading_info *loading_info; // after first set
struct list image_list; Thread *thread_list; // protected by fLock and the scheduler lock
struct team_loading_info *loading_info; // protected by fLock
struct list image_list; // protected by sImageMutex
struct list watcher_list; struct list watcher_list;
struct list sem_list; struct list sem_list; // protected by sSemsSpinlock
struct list port_list; struct list port_list; // protected by sPortsLock
struct arch_team arch_info; struct arch_team arch_info;
addr_t user_data; addr_t user_data;
@@ -260,9 +264,13 @@ struct Team : AssociatedDataOwner {
struct team_debug_info debug_info; struct team_debug_info debug_info;
// protected by scheduler lock
bigtime_t dead_threads_kernel_time; bigtime_t dead_threads_kernel_time;
bigtime_t dead_threads_user_time; bigtime_t dead_threads_user_time;
bigtime_t cpu_clock_offset;
// user group information; protected by fLock, the *_uid/*_gid fields also
// by the scheduler lock
uid_t saved_set_uid; uid_t saved_set_uid;
uid_t real_uid; uid_t real_uid;
uid_t effective_uid; uid_t effective_uid;
@@ -271,44 +279,181 @@ struct Team : AssociatedDataOwner {
gid_t effective_gid; gid_t effective_gid;
gid_t* supplementary_groups; gid_t* supplementary_groups;
int supplementary_group_count; int supplementary_group_count;
// Exit status information. Set when the first terminal event occurs,
// immutable afterwards. Protected by fLock.
struct {
uint16 reason; // reason for the team's demise, one of the
// CLD_* values defined in <signal.h>
uint16 signal; // signal killing the team
uid_t signaling_user; // real UID of the signal sender
status_t status; // exit status, if normal team exit
bool initialized; // true when the state has been initialized
} exit;
public:
~Team();
static Team* Create(team_id id, const char* name,
bool kernel);
static Team* Get(team_id id);
static Team* GetAndLock(team_id id);
bool Lock()
{ mutex_lock(&fLock); return true; }
bool TryLock()
{ return mutex_trylock(&fLock) == B_OK; }
void Unlock()
{ mutex_unlock(&fLock); }
void UnlockAndReleaseReference()
{ Unlock(); ReleaseReference(); }
void LockTeamAndParent(bool dontLockParentIfKernel);
void UnlockTeamAndParent();
void LockTeamAndProcessGroup();
void UnlockTeamAndProcessGroup();
void LockTeamParentAndProcessGroup();
void UnlockTeamParentAndProcessGroup();
void LockProcessGroup()
{ LockTeamAndProcessGroup(); Unlock(); }
const char* Name() const { return fName; }
void SetName(const char* name);
const char* Args() const { return fArgs; }
void SetArgs(const char* args);
void SetArgs(const char* path,
const char* const* otherArgs,
int otherArgCount);
BKernel::QueuedSignalsCounter* QueuedSignalsCounter() const
{ return fQueuedSignalsCounter; }
sigset_t PendingSignals() const
{ return fPendingSignals.AllSignals(); }
void AddPendingSignal(int signal)
{ fPendingSignals.AddSignal(signal); }
void AddPendingSignal(Signal* signal)
{ fPendingSignals.AddSignal(signal); }
void RemovePendingSignal(int signal)
{ fPendingSignals.RemoveSignal(signal); }
void RemovePendingSignal(Signal* signal)
{ fPendingSignals.RemoveSignal(signal); }
void RemovePendingSignals(sigset_t mask)
{ fPendingSignals.RemoveSignals(mask); }
void ResetSignalsOnExec();
inline int32 HighestPendingSignalPriority(
sigset_t nonBlocked) const;
inline Signal* DequeuePendingSignal(sigset_t nonBlocked,
Signal& buffer);
struct sigaction& SignalActionFor(int32 signal)
{ return fSignalActions[signal - 1]; }
void InheritSignalActions(Team* parent);
// user timers -- protected by fLock
UserTimer* UserTimerFor(int32 id) const
{ return fUserTimers.TimerFor(id); }
status_t AddUserTimer(UserTimer* timer);
void RemoveUserTimer(UserTimer* timer);
void DeleteUserTimers(bool userDefinedOnly);
bool CheckAddUserDefinedTimer();
void UserDefinedTimersRemoved(int32 count);
void UserTimerActivated(TeamTimeUserTimer* timer)
{ fCPUTimeUserTimers.Add(timer); }
void UserTimerActivated(TeamUserTimeUserTimer* timer)
{ fUserTimeUserTimers.Add(timer); }
void UserTimerDeactivated(TeamTimeUserTimer* timer)
{ fCPUTimeUserTimers.Remove(timer); }
void UserTimerDeactivated(
TeamUserTimeUserTimer* timer)
{ fUserTimeUserTimers.Remove(timer); }
void DeactivateCPUTimeUserTimers();
// both total and user CPU timers
bool HasActiveCPUTimeUserTimers() const
{ return !fCPUTimeUserTimers.IsEmpty(); }
bool HasActiveUserTimeUserTimers() const
{ return !fUserTimeUserTimers.IsEmpty(); }
TeamTimeUserTimerList::ConstIterator
CPUTimeUserTimerIterator() const
{ return fCPUTimeUserTimers.GetIterator(); }
inline TeamUserTimeUserTimerList::ConstIterator
UserTimeUserTimerIterator() const;
bigtime_t CPUTime(bool ignoreCurrentRun) const;
bigtime_t UserCPUTime() const;
private:
Team(team_id id, bool kernel);
private:
mutex fLock;
char fName[B_OS_NAME_LENGTH];
char fArgs[64];
// contents for the team_info::args field
BKernel::QueuedSignalsCounter* fQueuedSignalsCounter;
BKernel::PendingSignals fPendingSignals;
// protected by scheduler lock
struct sigaction fSignalActions[MAX_SIGNAL_NUMBER];
// indexed signal - 1, protected by fLock
UserTimerList fUserTimers; // protected by fLock
TeamTimeUserTimerList fCPUTimeUserTimers;
// protected by scheduler lock
TeamUserTimeUserTimerList fUserTimeUserTimers;
vint32 fUserDefinedTimerCount; // accessed atomically
}; };
struct Thread { struct Thread : TeamThreadIteratorEntry<thread_id>, KernelReferenceable {
int32 flags; // summary of events relevant in interrupt int32 flags; // summary of events relevant in interrupt
// handlers (signals pending, user debugging // handlers (signals pending, user debugging
// enabled, etc.) // enabled, etc.)
Thread *all_next; int64 serial_number; // immutable after adding thread to hash
Thread *team_next; Thread *hash_next; // protected by thread hash lock
Thread *queue_next; /* i.e. run queue, release queue, etc. */ Thread *team_next; // protected by team lock and fLock
timer alarm; Thread *queue_next; // protected by scheduler lock
thread_id id; timer alarm; // protected by scheduler lock
char name[B_OS_NAME_LENGTH]; char name[B_OS_NAME_LENGTH]; // protected by fLock
int32 priority; int32 priority; // protected by scheduler lock
int32 next_priority; int32 next_priority; // protected by scheduler lock
int32 io_priority; int32 io_priority; // protected by fLock
int32 state; int32 state; // protected by scheduler lock
int32 next_state; int32 next_state; // protected by scheduler lock
struct cpu_ent *cpu; struct cpu_ent *cpu; // protected by scheduler lock
struct cpu_ent *previous_cpu; struct cpu_ent *previous_cpu; // protected by scheduler lock
int32 pinned_to_cpu; int32 pinned_to_cpu; // only accessed by this thread or in the
// scheduler, when thread is not running
sigset_t sig_pending; sigset_t sig_block_mask; // protected by scheduler lock,
sigset_t sig_block_mask; // only modified by the thread itself
sigset_t sig_temp_enabled; sigset_t sigsuspend_original_unblocked_mask;
struct sigaction sig_action[32]; // non-0 after a return from _user_sigsuspend(), containing the inverted
addr_t signal_stack_base; // original signal mask, reset in handle_signals(); only accessed by
size_t signal_stack_size; // this thread
bool signal_stack_enabled; ucontext_t* user_signal_context; // only accessed by this thread
addr_t signal_stack_base; // only accessed by this thread
size_t signal_stack_size; // only accessed by this thread
bool signal_stack_enabled; // only accessed by this thread
bool in_kernel; bool in_kernel; // protected by time_lock, only written by
bool was_yielded; // this thread
struct scheduler_thread_data* scheduler_data; bool was_yielded; // protected by scheduler lock
struct scheduler_thread_data* scheduler_data; // protected by scheduler lock
struct user_thread* user_thread; struct user_thread* user_thread; // write-protected by fLock, only
// modified by the thread itself and
// thus freely readable by it
void (*cancel_function)(int);
struct { struct {
uint8 parameters[32]; uint8 parameters[SYSCALL_RESTART_PARAMETER_SIZE];
} syscall_restart; } syscall_restart;
struct { struct {
@@ -322,13 +467,15 @@ struct Thread {
struct PrivateConditionVariableEntry *condition_variable_entry; struct PrivateConditionVariableEntry *condition_variable_entry;
struct { struct {
sem_id write_sem; sem_id write_sem; // acquired by writers before writing
sem_id read_sem; sem_id read_sem; // release by writers after writing, acquired
// by this thread when reading
thread_id sender; thread_id sender;
int32 code; int32 code;
size_t size; size_t size;
void* buffer; void* buffer;
} msg; } msg; // write_sem/read_sem are protected by fLock when accessed by
// others, the other fields are protected by write_sem/read_sem
union { union {
addr_t fault_handler; addr_t fault_handler;
@@ -340,50 +487,304 @@ struct Thread {
int32 page_faults_allowed; int32 page_faults_allowed;
/* this field may only stay in debug builds in the future */ /* this field may only stay in debug builds in the future */
thread_entry_func entry; BKernel::Team *team; // protected by team lock, thread lock, scheduler
void *args1, *args2; // lock
BKernel::Team *team;
struct { struct {
sem_id sem; sem_id sem; // immutable after thread creation
status_t status; status_t status; // accessed only by this thread
uint16 reason; struct list waiters; // protected by fLock
uint16 signal;
struct list waiters;
} exit; } exit;
struct select_info *select_infos; struct select_info *select_infos; // protected by fLock
struct thread_debug_info debug_info; struct thread_debug_info debug_info;
// stack // stack
area_id kernel_stack_area; area_id kernel_stack_area; // immutable after thread creation
addr_t kernel_stack_base; addr_t kernel_stack_base; // immutable after thread creation
addr_t kernel_stack_top; addr_t kernel_stack_top; // immutable after thread creation
area_id user_stack_area; area_id user_stack_area; // protected by thread lock
addr_t user_stack_base; addr_t user_stack_base; // protected by thread lock
size_t user_stack_size; size_t user_stack_size; // protected by thread lock
addr_t user_local_storage; addr_t user_local_storage;
// usually allocated at the safe side of the stack // usually allocated at the safe side of the stack
int kernel_errno; int kernel_errno;
// kernel "errno" differs from its userspace alter ego // kernel "errno" differs from its userspace alter ego
bigtime_t user_time; // user_time, kernel_time, and last_time are only written by the thread
bigtime_t kernel_time; // itself, so they can be read by the thread without lock. Holding the
bigtime_t last_time; // scheduler lock and checking that the thread does not run also guarantees
// that the times will not change.
spinlock time_lock;
bigtime_t user_time; // protected by time_lock
bigtime_t kernel_time; // protected by time_lock
bigtime_t last_time; // protected by time_lock
bigtime_t cpu_clock_offset; // protected by scheduler lock
void (*post_interrupt_callback)(void*); void (*post_interrupt_callback)(void*);
void* post_interrupt_data; void* post_interrupt_data;
// architecture dependant section // architecture dependent section
struct arch_thread arch_info; struct arch_thread arch_info;
public:
Thread() {}
// dummy for the idle threads
Thread(const char *name, thread_id threadID,
struct cpu_ent *cpu);
~Thread();
static status_t Create(const char* name, Thread*& _thread);
static Thread* Get(thread_id id);
static Thread* GetAndLock(thread_id id);
static Thread* GetDebug(thread_id id);
// in kernel debugger only
static bool IsAlive(thread_id id);
void* operator new(size_t size);
void* operator new(size_t, void* pointer);
void operator delete(void* pointer, size_t size);
status_t Init(bool idleThread);
bool Lock()
{ mutex_lock(&fLock); return true; }
bool TryLock()
{ return mutex_trylock(&fLock) == B_OK; }
void Unlock()
{ mutex_unlock(&fLock); }
void UnlockAndReleaseReference()
{ Unlock(); ReleaseReference(); }
bool IsAlive() const;
bool IsRunning() const
{ return cpu != NULL; }
// scheduler lock must be held
sigset_t ThreadPendingSignals() const
{ return fPendingSignals.AllSignals(); }
inline sigset_t AllPendingSignals() const;
void AddPendingSignal(int signal)
{ fPendingSignals.AddSignal(signal); }
void AddPendingSignal(Signal* signal)
{ fPendingSignals.AddSignal(signal); }
void RemovePendingSignal(int signal)
{ fPendingSignals.RemoveSignal(signal); }
void RemovePendingSignal(Signal* signal)
{ fPendingSignals.RemoveSignal(signal); }
void RemovePendingSignals(sigset_t mask)
{ fPendingSignals.RemoveSignals(mask); }
void ResetSignalsOnExec();
inline int32 HighestPendingSignalPriority(
sigset_t nonBlocked) const;
inline Signal* DequeuePendingSignal(sigset_t nonBlocked,
Signal& buffer);
// user timers -- protected by fLock
UserTimer* UserTimerFor(int32 id) const
{ return fUserTimers.TimerFor(id); }
status_t AddUserTimer(UserTimer* timer);
void RemoveUserTimer(UserTimer* timer);
void DeleteUserTimers(bool userDefinedOnly);
void UserTimerActivated(ThreadTimeUserTimer* timer)
{ fCPUTimeUserTimers.Add(timer); }
void UserTimerDeactivated(ThreadTimeUserTimer* timer)
{ fCPUTimeUserTimers.Remove(timer); }
void DeactivateCPUTimeUserTimers();
bool HasActiveCPUTimeUserTimers() const
{ return !fCPUTimeUserTimers.IsEmpty(); }
ThreadTimeUserTimerList::ConstIterator
CPUTimeUserTimerIterator() const
{ return fCPUTimeUserTimers.GetIterator(); }
inline bigtime_t CPUTime(bool ignoreCurrentRun) const;
private:
mutex fLock;
BKernel::PendingSignals fPendingSignals;
// protected by scheduler lock
UserTimerList fUserTimers; // protected by fLock
ThreadTimeUserTimerList fCPUTimeUserTimers;
// protected by scheduler lock
}; };
struct ProcessSession : BReferenceable {
pid_t id;
int32 controlling_tty; // index of the controlling tty,
// -1 if none
pid_t foreground_group;
public:
ProcessSession(pid_t id);
~ProcessSession();
bool Lock()
{ mutex_lock(&fLock); return true; }
bool TryLock()
{ return mutex_trylock(&fLock) == B_OK; }
void Unlock()
{ mutex_unlock(&fLock); }
private:
mutex fLock;
};
struct ProcessGroup : KernelReferenceable {
struct ProcessGroup *next; // next in hash
pid_t id;
BKernel::Team *teams;
public:
ProcessGroup(pid_t id);
~ProcessGroup();
static ProcessGroup* Get(pid_t id);
bool Lock()
{ mutex_lock(&fLock); return true; }
bool TryLock()
{ return mutex_trylock(&fLock) == B_OK; }
void Unlock()
{ mutex_unlock(&fLock); }
ProcessSession* Session() const
{ return fSession; }
void Publish(ProcessSession* session);
void PublishLocked(ProcessSession* session);
bool IsOrphaned() const;
void ScheduleOrphanedCheck();
void UnsetOrphanedCheck();
public:
SinglyLinkedListLink<ProcessGroup> fOrphanedCheckListLink;
private:
mutex fLock;
ProcessSession* fSession;
bool fInOrphanedCheckList; // protected by
// sOrphanedCheckLock
};
typedef SinglyLinkedList<ProcessGroup,
SinglyLinkedListMemberGetLink<ProcessGroup,
&ProcessGroup::fOrphanedCheckListLink> > ProcessGroupList;
/*! \brief Allows to iterate through all teams.
*/
struct TeamListIterator {
TeamListIterator();
~TeamListIterator();
Team* Next();
private:
TeamThreadIteratorEntry<team_id> fEntry;
};
/*! \brief Allows to iterate through all threads.
*/
struct ThreadListIterator {
ThreadListIterator();
~ThreadListIterator();
Thread* Next();
private:
TeamThreadIteratorEntry<thread_id> fEntry;
};
inline int32
Team::HighestPendingSignalPriority(sigset_t nonBlocked) const
{
return fPendingSignals.HighestSignalPriority(nonBlocked);
}
inline Signal*
Team::DequeuePendingSignal(sigset_t nonBlocked, Signal& buffer)
{
return fPendingSignals.DequeueSignal(nonBlocked, buffer);
}
inline TeamUserTimeUserTimerList::ConstIterator
Team::UserTimeUserTimerIterator() const
{
return fUserTimeUserTimers.GetIterator();
}
inline sigset_t
Thread::AllPendingSignals() const
{
return fPendingSignals.AllSignals() | team->PendingSignals();
}
inline int32
Thread::HighestPendingSignalPriority(sigset_t nonBlocked) const
{
return fPendingSignals.HighestSignalPriority(nonBlocked);
}
inline Signal*
Thread::DequeuePendingSignal(sigset_t nonBlocked, Signal& buffer)
{
return fPendingSignals.DequeueSignal(nonBlocked, buffer);
}
/*! Returns the thread's current total CPU time (kernel + user + offset).
The caller must hold the scheduler lock.
\param ignoreCurrentRun If \c true and the thread is currently running,
don't add the time since the last time \c last_time was updated. Should
be used in "thread unscheduled" scheduler callbacks, since although the
thread is still running at that time, its time has already been stopped.
\return The thread's current total CPU time.
*/
inline bigtime_t
Thread::CPUTime(bool ignoreCurrentRun) const
{
bigtime_t time = user_time + kernel_time + cpu_clock_offset;
// If currently running, also add the time since the last check, unless
// requested otherwise.
if (!ignoreCurrentRun && cpu != NULL)
time += system_time() - last_time;
return time;
}
} // namespace BKernel } // namespace BKernel
using BKernel::Team; using BKernel::Team;
using BKernel::TeamListIterator;
using BKernel::Thread; using BKernel::Thread;
using BKernel::ThreadListIterator;
using BKernel::ProcessSession;
using BKernel::ProcessGroup;
using BKernel::ProcessGroupList;
struct thread_queue { struct thread_queue {
+17 -2
View File
@@ -15,8 +15,21 @@ extern "C" {
struct kernel_args; struct kernel_args;
#define B_TIMER_ACQUIRE_THREAD_LOCK 0x8000 #define B_TIMER_REAL_TIME_BASE 0x2000
#define B_TIMER_FLAGS B_TIMER_ACQUIRE_THREAD_LOCK // For an absolute timer the given time is interpreted as a real-time, not
// as a system time. Note that setting the real-time clock will cause the
// timer to be updated -- it will expire according to the new clock.
// Relative timers are unaffected by this flag.
#define B_TIMER_USE_TIMER_STRUCT_TIMES 0x4000
// For add_timer(): Use the timer::schedule_time (absolute time) and
// timer::period values instead of the period parameter.
#define B_TIMER_ACQUIRE_SCHEDULER_LOCK 0x8000
// The timer hook is invoked with the scheduler lock held. When invoking
// cancel_timer() with the scheduler lock held, too, this helps to avoid
// race conditions.
#define B_TIMER_FLAGS \
(B_TIMER_USE_TIMER_STRUCT_TIMES | B_TIMER_ACQUIRE_SCHEDULER_LOCK \
| B_TIMER_REAL_TIME_BASE)
/* Timer info structure */ /* Timer info structure */
struct timer_info { struct timer_info {
@@ -32,6 +45,8 @@ typedef struct timer_info timer_info;
/* kernel functions */ /* kernel functions */
status_t timer_init(struct kernel_args *); status_t timer_init(struct kernel_args *);
void timer_init_post_rtc(void);
void timer_real_time_clock_changed();
int32 timer_interrupt(void); int32 timer_interrupt(void);
#ifdef __cplusplus #ifdef __cplusplus
+41 -19
View File
@@ -36,25 +36,26 @@ using BKernel::Thread;
// //
// Locking policy: // Locking policy:
// 1) When accessing the structure it must be made sure, that the structure, // 1) When accessing the structure it must be made sure, that the structure,
// (i.e. the struct team it lives in) isn't deleted. Thus one either needs to // (i.e. the struct Team it lives in) isn't deleted. Thus one either needs to
// acquire the global team lock, or one accesses the structure from a thread // get a team reference, lock the team, or one accesses the structure from a
// of that team. // thread of that team.
// 2) Access to the `flags' field is atomic. Reading via atomic_get() // 2) Access to the `flags' field is atomic. Reading via atomic_get()
// requires no further locks (in addition to 1) that is). Writing requires // requires no further locks (in addition to 1) that is). Writing requires
// `lock' being held and must be done atomically, too // `lock' to be held and must be done atomically, too
// (atomic_{set,and,or}()). Reading with `lock' being held doesn't need to // (atomic_{set,and,or}()). Reading with `lock' being held doesn't need to
// be done atomically. // be done atomically.
// 3) Access to all other fields (read or write) requires `lock' being held. // 3) Access to all other fields (read or write) requires `lock' to be held.
// 4) Locking order is scheduler lock -> Team -> Thread -> team_debug_info::lock
// -> thread_debug_info::lock.
// //
struct team_debug_info { struct team_debug_info {
spinlock lock; spinlock lock;
// Guards the remaining fields. Should always be the innermost lock // Guards the remaining fields. Should always be the innermost lock
// to be acquired/released. // to be acquired/released, save for thread_debug_info::lock.
int32 flags; int32 flags;
// Set atomically. So reading atomically is OK, even when the team // Set atomically. So reading atomically is OK, even when the lock is
// lock is not held (at least if it is certain, that the team struct // not held (at least if it is certain, that the team struct won't go).
// won't go).
team_id debugger_team; team_id debugger_team;
port_id debugger_port; port_id debugger_port;
@@ -71,12 +72,13 @@ struct team_debug_info {
// counter incremented whenever an image is created/deleted // counter incremented whenever an image is created/deleted
struct ConditionVariable* debugger_changed_condition; struct ConditionVariable* debugger_changed_condition;
// Set whenever someone is going (or planning) to change the debugger. // Set to a condition variable when going to change the debugger. Anyone
// If one wants to do the same, one has to wait for this condition. // who wants to change the debugger as well, needs to wait until the
// Both threads lock (outer) and team debug info lock (inner) have to // condition variable is unset again (waiting for the condition and
// be held when accessing this field. After setting to a condition // rechecking again). The field and the condition variable is protected
// variable the thread won't be deleted (until unsetting it) -- it might // by 'lock'. After setting the a condition variable the team is
// be removed from the team hash table, though. // guaranteed not to be deleted (until it is unset) it might be removed
// from the team hash table, though.
struct BreakpointManager* breakpoint_manager; struct BreakpointManager* breakpoint_manager;
// manages hard- and software breakpoints // manages hard- and software breakpoints
@@ -84,11 +86,31 @@ struct team_debug_info {
struct arch_team_debug_info arch_info; struct arch_team_debug_info arch_info;
}; };
// Thread related debugging data.
//
// Locking policy:
// 1) When accessing the structure it must be made sure, that the structure,
// (i.e. the struct Thread it lives in) isn't deleted. Thus one either needs
// to get a thread reference, lock the thread, or one accesses the structure
// of the current thread.
// 2) Access to the `flags' field is atomic. Reading via atomic_get()
// requires no further locks (in addition to 1) that is). Writing requires
// `lock' to be held and must be done atomically, too
// (atomic_{set,and,or}()). Reading with `lock' being held doesn't need to
// be done atomically.
// 3) Access to all other fields (read or write) requires `lock' to be held.
// 4) Locking order is scheduler lock -> Team -> Thread -> team_debug_info::lock
// -> thread_debug_info::lock.
//
struct thread_debug_info { struct thread_debug_info {
spinlock lock;
// Guards the remaining fields. Should always be the innermost lock
// to be acquired/released.
int32 flags; int32 flags;
// Set atomically. So reading atomically is OK, even when the thread // Set atomically. So reading atomically is OK, even when the lock is
// lock is not held (at least if it is certain, that the thread struct // not held (at least if it is certain, that the thread struct won't
// won't go). // go).
port_id debug_port; port_id debug_port;
// the port the thread is waiting on for commands from the nub thread // the port the thread is waiting on for commands from the nub thread
@@ -238,7 +260,7 @@ void user_debug_stop_thread();
void user_debug_team_created(team_id teamID); void user_debug_team_created(team_id teamID);
void user_debug_team_deleted(team_id teamID, port_id debuggerPort); void user_debug_team_deleted(team_id teamID, port_id debuggerPort);
void user_debug_team_exec(); void user_debug_team_exec();
void user_debug_update_new_thread_flags(thread_id threadID); void user_debug_update_new_thread_flags(Thread* thread);
void user_debug_thread_created(thread_id threadID); void user_debug_thread_created(thread_id threadID);
void user_debug_thread_deleted(team_id teamID, thread_id threadID); void user_debug_thread_deleted(team_id teamID, thread_id threadID);
void user_debug_thread_exiting(Thread* thread); void user_debug_thread_exiting(Thread* thread);
-1
View File
@@ -25,7 +25,6 @@ extern "C" {
// kernel private functions // kernel private functions
void inherit_parent_user_and_group(Team* team, Team* parent); void inherit_parent_user_and_group(Team* team, Team* parent);
void inherit_parent_user_and_group_locked(Team* team, Team* parent);
status_t update_set_id_user_and_group(Team* team, const char* file); status_t update_set_id_user_and_group(Team* team, const char* file);
// syscalls // syscalls
+7
View File
@@ -177,6 +177,10 @@ public:
typedef AutoLocker<Thread, ThreadCPUPinLocking> ThreadCPUPinner; typedef AutoLocker<Thread, ThreadCPUPinLocking> ThreadCPUPinner;
typedef AutoLocker<Team> TeamLocker;
typedef AutoLocker<Thread> ThreadLocker;
} // namespace BPrivate } // namespace BPrivate
using BPrivate::AutoLocker; using BPrivate::AutoLocker;
@@ -188,5 +192,8 @@ using BPrivate::InterruptsLocker;
using BPrivate::SpinLocker; using BPrivate::SpinLocker;
using BPrivate::InterruptsSpinLocker; using BPrivate::InterruptsSpinLocker;
using BPrivate::ThreadCPUPinner; using BPrivate::ThreadCPUPinner;
using BPrivate::TeamLocker;
using BPrivate::ThreadLocker;
#endif // KERNEL_UTIL_AUTO_LOCKER_H #endif // KERNEL_UTIL_AUTO_LOCKER_H
@@ -0,0 +1,29 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_UTIL_KERNEL_REFERENCEABLE_H
#define _KERNEL_UTIL_KERNEL_REFERENCEABLE_H
#include <Referenceable.h>
#include <heap.h>
namespace BKernel {
struct KernelReferenceable : BReferenceable, DeferredDeletable {
protected:
virtual void LastReferenceReleased();
};
} // namespace BKernel
using BKernel::KernelReferenceable;
#endif /* _KERNEL_UTIL_KERNEL_REFERENCEABLE_H */
+1 -2
View File
@@ -37,12 +37,11 @@ void __init_heap_post_env(void);
void __init_time(void); void __init_time(void);
void __arch_init_time(struct real_time_data *data, bool setDefaults); void __arch_init_time(struct real_time_data *data, bool setDefaults);
bigtime_t __arch_get_system_time_offset(struct real_time_data *data); bigtime_t __arch_get_system_time_offset(struct real_time_data *data);
bigtime_t __get_system_time_offset();
void __init_pwd_backend(void); void __init_pwd_backend(void);
void __reinit_pwd_backend_after_fork(void); void __reinit_pwd_backend_after_fork(void);
void* __arch_get_caller(void); void* __arch_get_caller(void);
void __init_pthread(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
+18 -4
View File
@@ -11,6 +11,17 @@
#include <OS.h> #include <OS.h>
// _pthread_thread::flags values
#define THREAD_DETACHED 0x01
#define THREAD_DEAD 0x02
#define THREAD_CANCELED 0x04
#define THREAD_CANCEL_ENABLED 0x08
#define THREAD_CANCEL_ASYNCHRONOUS 0x10
struct thread_creation_attributes;
// The public *_t types are only pointers to these structures // The public *_t types are only pointers to these structures
// This way, we are completely free to change them, which might be // This way, we are completely free to change them, which might be
// necessary in the future (not only due to the incomplete implementation // necessary in the future (not only due to the incomplete implementation
@@ -55,9 +66,6 @@ typedef struct _pthread_thread {
void *(*entry)(void*); void *(*entry)(void*);
void *entry_argument; void *entry_argument;
void *exit_value; void *exit_value;
int cancel_state;
int cancel_type;
bool cancelled;
struct pthread_key_data specific[PTHREAD_KEYS_MAX]; struct pthread_key_data specific[PTHREAD_KEYS_MAX];
struct __pthread_cleanup_handler *cleanup_handlers; struct __pthread_cleanup_handler *cleanup_handlers;
} pthread_thread; } pthread_thread;
@@ -69,7 +77,13 @@ extern "C" {
void __pthread_key_call_destructors(pthread_thread *thread); void __pthread_key_call_destructors(pthread_thread *thread);
void __pthread_destroy_thread(void); void __pthread_destroy_thread(void);
pthread_thread *__allocate_pthread(void *data); pthread_thread *__allocate_pthread(void* (*entry)(void*), void *data);
void __init_pthread(pthread_thread* thread, void* (*entry)(void*), void* data);
status_t __pthread_init_creation_attributes(
const pthread_attr_t* pthreadAttributes, pthread_t thread,
status_t (*entryFunction)(void*, void*), void* argument1,
void* argument2, const char* name,
struct thread_creation_attributes* attributes);
#ifdef __cplusplus #ifdef __cplusplus
} }
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_SIGNAL_PRIVATE_H
#define _LIBROOT_SIGNAL_PRIVATE_H
#include <signal.h>
#include <sys/cdefs.h>
#include <signal_defs.h>
#define MAX_SIGNAL_NUMBER_BEOS 29
typedef __haiku_int32 sigset_t_beos;
struct sigaction_beos {
__sighandler_t sa_handler;
sigset_t_beos sa_mask;
int sa_flags;
void* sa_userdata;
};
static inline sigset_t_beos
to_beos_sigset(sigset_t set)
{
// restrict to BeOS signals
sigset_t_beos beosSet = (sigset_t_beos)(set
& SIGNAL_RANGE_TO_MASK(1, MAX_SIGNAL_NUMBER_BEOS));
// if SIGBUS is set, set SIGSEGV, since they have the same number in BeOS
if ((set & SIGNAL_TO_MASK(SIGBUS)) != 0)
beosSet |= SIGNAL_TO_MASK(SIGSEGV);
return beosSet;
}
static inline sigset_t
from_beos_sigset(sigset_t_beos beosSet)
{
sigset_t set = beosSet;
// if SIGSEGV is set, set SIGBUS, since they have the same number in BeOS
if ((set & SIGNAL_TO_MASK(SIGSEGV)) != 0)
set |= SIGNAL_TO_MASK(SIGBUS);
return set;
}
__BEGIN_DECLS
__sighandler_t __signal_beos(int signal, __sighandler_t signalHandler);
__sighandler_t __signal(int signal, __sighandler_t signalHandler);
int __sigaction_beos(int signal, const struct sigaction_beos* beosAction,
struct sigaction_beos* beosOldAction);
int __sigaction(int signal, const struct sigaction* action,
struct sigaction* oldAction);
__sighandler_t __sigset_beos(int signal, __sighandler_t signalHandler);
__sighandler_t __sigset(int signal, __sighandler_t signalHandler);
int __sigignore_beos(int signal);
int __sigignore(int signal);
int __sighold_beos(int signal);
int __sighold(int signal);
int __sigrelse_beos(int signal);
int __sigrelse(int signal);
int __sigpause_beos(int signal);
int __sigpause(int signal);
int __siginterrupt_beos(int signal, int flag);
int __siginterrupt(int signal, int flag);
int __pthread_sigmask_beos(int how, const sigset_t_beos* beosSet,
sigset_t_beos* beosOldSet);
int __sigprocmask_beos(int how, const sigset_t_beos* beosSet,
sigset_t_beos* beosOldSet);
int __pthread_sigmask(int how, const sigset_t* set, sigset_t* oldSet);
int __sigprocmask(int how, const sigset_t* set, sigset_t* oldSet);
int __sigpending_beos(sigset_t_beos* beosSet);
int __sigpending(sigset_t* set);
int __sigsuspend_beos(const sigset_t_beos* beosMask);
int __sigsuspend(const sigset_t* mask);
int __sigwait_beos(const sigset_t_beos* beosSet, int* _signal);
int __sigwait(const sigset_t* set, int* _signal);
int __sigemptyset_beos(sigset_t_beos* set);
int __sigfillset_beos(sigset_t_beos* set);
int __sigismember_beos(const sigset_t_beos* set, int signal);
int __sigaddset_beos(sigset_t_beos* set, int signal);
int __sigdelset_beos(sigset_t_beos* set, int signal);
int __sigemptyset(sigset_t* set);
int __sigfillset(sigset_t* set);
int __sigismember(const sigset_t* set, int signal);
int __sigaddset(sigset_t* set, int signal);
int __sigdelset(sigset_t* set, int signal);
__END_DECLS
#endif // _LIBROOT_SIGNAL_PRIVATE_H
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_TIME_PRIVATE_H
#define _LIBROOT_TIME_PRIVATE_H
#include <errno.h>
#include <sys/cdefs.h>
#include <sys/time.h>
#include <time.h>
#include <SupportDefs.h>
#include <new>
#define CLOCKS_PER_SEC_BEOS 1000
#define CLK_TCK_BEOS CLOCKS_PER_SEC_BEOS
#define MICROSECONDS_PER_CLOCK_TICK (1000000 / CLOCKS_PER_SEC)
#define MICROSECONDS_PER_CLOCK_TICK_BEOS (1000000 / CLOCKS_PER_SEC_BEOS)
struct __timer_t {
int32 id;
thread_id thread;
void SetTo(int32 id, thread_id thread)
{
this->id = id;
this->thread = thread;
}
};
static inline void
bigtime_to_timespec(bigtime_t time, timespec& spec)
{
spec.tv_sec = time / 1000000;
spec.tv_nsec = (time % 1000000) * 1000;
}
static inline bool
timespec_to_bigtime(const timespec& spec, bigtime_t& _time)
{
if (spec.tv_sec < 0 || spec.tv_nsec < 0 || spec.tv_nsec >= 1000000000)
return false;
_time = (bigtime_t)spec.tv_sec * 1000000 + (spec.tv_nsec + 999) / 1000;
return true;
}
static inline bool
timeval_to_timespec(const timeval& val, timespec& spec)
{
if (val.tv_sec < 0 || val.tv_usec < 0 || val.tv_usec >= 1000000)
return false;
spec.tv_sec = val.tv_sec;
spec.tv_nsec = val.tv_usec * 1000;
return true;
}
static inline void
timespec_to_timeval(const timespec& spec, timeval& val)
{
val.tv_sec = spec.tv_sec;
val.tv_usec = spec.tv_nsec / 1000;
}
__BEGIN_DECLS
clock_t __clock_beos(void);
clock_t __clock(void);
__END_DECLS
#endif // _LIBROOT_TIME_PRIVATE_H
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_TIMES_PRIVATE_H
#define _LIBROOT_TIMES_PRIVATE_H
#include <sys/cdefs.h>
#include <sys/times.h>
__BEGIN_DECLS
clock_t __times_beos(struct tms* tms);
clock_t __times(struct tms* tms);
__END_DECLS
#endif // _LIBROOT_TIMES_PRIVATE_H
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_UNISTD_PRIVATE_H
#define _LIBROOT_UNISTD_PRIVATE_H
#include <sys/cdefs.h>
#include <sys/times.h>
__BEGIN_DECLS
long __sysconf_beos(int name);
long __sysconf(int name);
__END_DECLS
#endif // _LIBROOT_UNISTD_PRIVATE_H
+26 -6
View File
@@ -1,18 +1,38 @@
/* /*
* Copyright 2008, Ingo Weinhold, [email protected]. * Copyright 2008-2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SYSCALL_UTILS_H #ifndef _SYSCALL_UTILS_H
#define _SYSCALL_UTILS_H #define _SYSCALL_UTILS_H
#define RETURN_AND_SET_ERRNO(err) \ #define RETURN_AND_SET_ERRNO(err) \
do { \ do { \
__typeof(err) raseResult = (err); \ __typeof(err) __result = (err); \
if (raseResult < 0) { \ if (__result < 0) { \
errno = raseResult; \ errno = __result; \
return -1; \ return -1; \
} \ } \
return raseResult; \ return __result; \
} while (false) } while (0)
#define RETURN_AND_TEST_CANCEL(err) \
do { \
__typeof(err) __result = (err); \
pthread_testcancel(); \
return __result; \
} while (0)
#define RETURN_AND_SET_ERRNO_TEST_CANCEL(err) \
do { \
__typeof(err) __result = (err); \
pthread_testcancel(); \
if (__result < 0) { \
errno = __result; \
return -1; \
} \
return __result; \
} while (0)
#endif // _SYSCALL_UTILS_H #endif // _SYSCALL_UTILS_H
@@ -12,6 +12,10 @@
#define COMMPAGE_ENTRY_X86_SYSCALL (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0) #define COMMPAGE_ENTRY_X86_SYSCALL (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 0)
#define COMMPAGE_ENTRY_X86_MEMCPY (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1) #define COMMPAGE_ENTRY_X86_MEMCPY (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 1)
#define COMMPAGE_ENTRY_X86_MEMSET (COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 2) #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) #define ARCH_USER_COMMPAGE_ADDR (0xffff0000)
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright 2011, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_SIGNAL_DEFS_H
#define _SYSTEM_SIGNAL_DEFS_H
#include <signal.h>
#include <unistd.h>
// The total number of signals a process may have queued at receivers at any
// time.
#define MAX_QUEUED_SIGNALS _POSIX_SIGQUEUE_MAX
// realtime signal number range
#define SIGNAL_REALTIME_MIN 33
#define SIGNAL_REALTIME_MAX 40
// greatest actually supported signal number
#define MAX_SIGNAL_NUMBER SIGNAL_REALTIME_MAX
// additional send_signal_etc() flags
#define SIGNAL_FLAG_QUEUING_REQUIRED (0x10000)
// force signal queuing, i.e. fail instead of falling back to unqueued
// signals, when queuing isn't possible
#define SIGNAL_FLAG_SEND_TO_THREAD (0x20000)
// interpret the the given ID as a thread_id rather than a team_id (syscall
// 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
#define SIGNAL_TO_MASK(signal) ((sigset_t)1 << ((signal) - 1))
#define SIGNAL_RANGE_TO_MASK(first, last) \
((((SIGNAL_TO_MASK(last) - 1) << 1) | 1) & ~(SIGNAL_TO_MASK(first) - 1))
// Note: The last mask computation looks that way to avoid an overflow for
// last == 64.
#endif /* _SYSTEM_SIGNAL_DEFS_H */
+31 -10
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2010, Haiku Inc. All rights reserved. * Copyright 2004-2011, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SYSTEM_SYSCALLS_H #ifndef _SYSTEM_SYSCALLS_H
@@ -35,8 +35,10 @@ struct _sem_t;
struct sembuf; struct sembuf;
union semun; union semun;
struct sigaction; struct sigaction;
struct signal_frame_data;
struct stat; struct stat;
struct system_profiler_parameters; struct system_profiler_parameters;
struct user_timer_info;
struct disk_device_job_progress_info; struct disk_device_job_progress_info;
struct partitionable_space_data; struct partitionable_space_data;
@@ -134,8 +136,8 @@ extern void __NO_RETURN _kern_exit_team(status_t returnValue);
extern status_t _kern_kill_team(team_id team); extern status_t _kern_kill_team(team_id team);
extern team_id _kern_get_current_team(); extern team_id _kern_get_current_team();
extern status_t _kern_wait_for_team(team_id team, status_t *_returnCode); extern status_t _kern_wait_for_team(team_id team, status_t *_returnCode);
extern thread_id _kern_wait_for_child(thread_id child, uint32 flags, extern pid_t _kern_wait_for_child(thread_id child, uint32 flags,
int32 *_reason, status_t *_returnCode); siginfo_t* info);
extern status_t _kern_exec(const char *path, const char* const* flatArgs, extern status_t _kern_exec(const char *path, const char* const* flatArgs,
size_t flatArgsSize, int32 argCount, int32 envCount, size_t flatArgsSize, int32 argCount, int32 envCount,
mode_t umask); mode_t umask);
@@ -155,6 +157,8 @@ extern status_t _kern_set_thread_priority(thread_id thread,
int32 newPriority); int32 newPriority);
extern status_t _kern_kill_thread(thread_id thread); extern status_t _kern_kill_thread(thread_id thread);
extern void _kern_exit_thread(status_t returnValue); extern void _kern_exit_thread(status_t returnValue);
extern status_t _kern_cancel_thread(thread_id threadID,
void (*cancelFunction)(int));
extern void _kern_thread_yield(void); extern void _kern_thread_yield(void);
extern status_t _kern_wait_for_thread(thread_id thread, extern status_t _kern_wait_for_thread(thread_id thread,
status_t *_returnCode); status_t *_returnCode);
@@ -163,7 +167,8 @@ extern status_t _kern_send_data(thread_id thread, int32 code,
const void *buffer, size_t bufferSize); const void *buffer, size_t bufferSize);
extern int32 _kern_receive_data(thread_id *_sender, void *buffer, extern int32 _kern_receive_data(thread_id *_sender, void *buffer,
size_t bufferSize); size_t bufferSize);
extern int64 _kern_restore_signal_frame(); extern int64 _kern_restore_signal_frame(
struct signal_frame_data* signalFrameData);
extern status_t _kern_get_thread_info(thread_id id, thread_info *info); extern status_t _kern_get_thread_info(thread_id id, thread_info *info);
extern status_t _kern_get_next_thread_info(team_id team, int32 *cookie, extern status_t _kern_get_next_thread_info(team_id team, int32 *cookie,
@@ -198,13 +203,14 @@ extern ssize_t _kern_getgroups(int groupCount, gid_t* groupList);
extern status_t _kern_setgroups(int groupCount, const gid_t* groupList); extern status_t _kern_setgroups(int groupCount, const gid_t* groupList);
// signal functions // signal functions
extern status_t _kern_send_signal(pid_t tid, uint sig); extern status_t _kern_send_signal(int32 id, uint32 signal,
extern status_t _kern_sigprocmask(int how, const sigset_t *set, const union sigval* userValue, uint32 flags);
extern status_t _kern_set_signal_mask(int how, const sigset_t *set,
sigset_t *oldSet); sigset_t *oldSet);
extern status_t _kern_sigaction(int sig, const struct sigaction *action, extern status_t _kern_sigaction(int sig, const struct sigaction *action,
struct sigaction *oldAction); struct sigaction *oldAction);
extern bigtime_t _kern_set_alarm(bigtime_t time, uint32 mode); extern status_t _kern_sigwait(const sigset_t *set, siginfo_t *info,
extern status_t _kern_sigwait(const sigset_t *set, int *_signal); uint32 flags, bigtime_t timeout);
extern status_t _kern_sigsuspend(const sigset_t *mask); extern status_t _kern_sigsuspend(const sigset_t *mask);
extern status_t _kern_sigpending(sigset_t *set); extern status_t _kern_sigpending(sigset_t *set);
extern status_t _kern_set_signal_stack(const stack_t *newStack, extern status_t _kern_set_signal_stack(const stack_t *newStack,
@@ -370,7 +376,7 @@ extern status_t _kern_stop_watching(dev_t device, ino_t node, port_id port,
uint32 token); uint32 token);
// time functions // time functions
extern status_t _kern_set_real_time_clock(uint32 time); extern status_t _kern_set_real_time_clock(bigtime_t time);
extern status_t _kern_set_timezone(int32 timezoneOffset, const char *name, extern status_t _kern_set_timezone(int32 timezoneOffset, const char *name,
size_t nameLength); size_t nameLength);
extern status_t _kern_get_timezone(int32 *_timezoneOffset, char *name, extern status_t _kern_get_timezone(int32 *_timezoneOffset, char *name,
@@ -378,8 +384,23 @@ extern status_t _kern_get_timezone(int32 *_timezoneOffset, char *name,
extern status_t _kern_set_real_time_clock_is_gmt(bool isGMT); extern status_t _kern_set_real_time_clock_is_gmt(bool isGMT);
extern status_t _kern_get_real_time_clock_is_gmt(bool *_isGMT); extern status_t _kern_get_real_time_clock_is_gmt(bool *_isGMT);
extern status_t _kern_get_clock(clockid_t clockID, bigtime_t* _time);
extern status_t _kern_set_clock(clockid_t clockID, bigtime_t time);
extern bigtime_t _kern_system_time(); extern bigtime_t _kern_system_time();
extern status_t _kern_snooze_etc(bigtime_t time, int timebase, int32 flags); extern status_t _kern_snooze_etc(bigtime_t time, int timebase, int32 flags,
bigtime_t* _remainingTime);
extern int32 _kern_create_timer(clockid_t clockID, thread_id threadID,
uint32 flags, const struct sigevent* event,
const struct thread_creation_attributes*
threadAttributes);
extern status_t _kern_delete_timer(int32 timerID, thread_id threadID);
extern status_t _kern_get_timer(int32 timerID, thread_id threadID,
struct user_timer_info* info);
extern status_t _kern_set_timer(int32 timerID, thread_id threadID,
bigtime_t startTime, bigtime_t interval, uint32 flags,
struct user_timer_info* oldInfo);
// area functions // area functions
extern area_id _kern_create_area(const char *name, void **address, extern area_id _kern_create_area(const char *name, void **address,
+12 -11
View File
@@ -1,18 +1,16 @@
/* /*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SYSTEM_THREAD_DEFS_H #ifndef _SYSTEM_THREAD_DEFS_H
#define _SYSTEM_THREAD_DEFS_H #define _SYSTEM_THREAD_DEFS_H
#include <pthread.h>
#include <OS.h> #include <OS.h>
#define THREAD_RETURN_EXIT 0x1
#define THREAD_RETURN_INTERRUPTED 0x2
#define THREAD_STOPPED 0x3
#define THREAD_CONTINUED 0x4
/** Size of the stack given to teams in user space */ /** Size of the stack given to teams in user space */
#define USER_STACK_GUARD_PAGES 4 // 16 kB #define USER_STACK_GUARD_PAGES 4 // 16 kB
#define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024 \ #define USER_MAIN_THREAD_STACK_SIZE (16 * 1024 * 1024 \
@@ -39,18 +37,21 @@ enum {
}; };
#define THREAD_CREATION_FLAG_DEFER_SIGNALS 0x01
// create the thread with signals deferred, i.e. with
// user_thread::defer_signals set to 1
struct thread_creation_attributes { struct thread_creation_attributes {
int32 (*entry)(thread_func, void *); int32 (*entry)(void*, void*);
const char* name; const char* name;
int32 priority; int32 priority;
void* args1; void* args1;
void* args2; void* args2;
void* stack_address; void* stack_address;
size_t stack_size; size_t stack_size;
pthread_t pthread;
// when calling from kernel only uint32 flags;
team_id team;
thread_id thread;
}; };
#endif /* _SYSTEM_THREAD_DEFS_H */ #endif /* _SYSTEM_THREAD_DEFS_H */
-1
View File
@@ -19,7 +19,6 @@ enum {
TLS_ERRNO_SLOT, TLS_ERRNO_SLOT,
TLS_ON_EXIT_THREAD_SLOT, TLS_ON_EXIT_THREAD_SLOT,
TLS_USER_THREAD_SLOT, TLS_USER_THREAD_SLOT,
TLS_PTHREAD_SLOT,
// Note: these entries can safely be changed between // Note: these entries can safely be changed between
// releases; 3rd party code always calls tls_allocate() // releases; 3rd party code always calls tls_allocate()
+9 -3
View File
@@ -1,18 +1,24 @@
/* /*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _SYSTEM_USER_THREAD_DEFS_H #ifndef _SYSTEM_USER_THREAD_DEFS_H
#define _SYSTEM_USER_THREAD_DEFS_H #define _SYSTEM_USER_THREAD_DEFS_H
#include <pthread.h>
#include <signal.h>
#include <SupportDefs.h> #include <SupportDefs.h>
struct user_thread { struct user_thread {
pthread_t pthread; // pthread pointer
uint32 flags;
status_t wait_status; // wait status for thread blocking
int32 defer_signals; // counter; 0 == signals allowed int32 defer_signals; // counter; 0 == signals allowed
uint32 pending_signals; // signals that are pending, when sigset_t pending_signals; // signals that are pending, when
// signals are deferred // signals are deferred
status_t wait_status;
}; };
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_USER_TIMER_DEFS_H
#define _SYSTEM_USER_TIMER_DEFS_H
#include <limits.h>
#include <time.h>
#include <SupportDefs.h>
#define CLOCK_PROCESS_USER_CPUTIME_ID ((clockid_t)-4)
/* clock measuring the used user CPU time of the current process */
// limits
#define MAX_USER_TIMERS_PER_TEAM _POSIX_TIMER_MAX
// maximum numbers of user-defined user timers (timer_create())
#define MAX_USER_TIMER_OVERRUN_COUNT INT_MAX
// cap value of a timer's overrun counter
#if MAX_USER_TIMER_OVERRUN_COUNT < _POSIX_DELAYTIMER_MAX
# error "MAX_USER_TIMER_OVERRUN_COUNT < _POSIX_DELAYTIMER_MAX"
#endif
#define USER_TIMER_REAL_TIME_ID 0
// predefined ID for the real time timer
#define USER_TIMER_TEAM_TOTAL_TIME_ID 1
// predefined ID for the team's total (kernel + user) time timer
#define USER_TIMER_TEAM_USER_TIME_ID 2
// predefined ID for the team's user time timer
#define USER_TIMER_FIRST_USER_DEFINED_ID 3
// first ID assigned to a user-defined timer (timer_create())
// _kern_create_user_timer() flag:
#define USER_TIMER_SIGNAL_THREAD 0x01
// send the signal to the thread instead of the team (valid only for thread
// timers)
struct user_timer_info {
bigtime_t remaining_time;
bigtime_t interval;
uint32 overrun_count;
};
#endif /* _SYSTEM_USER_TIMER_DEFS_H */
@@ -50,7 +50,7 @@ std_ops(int32 op, ...)
if (thread < B_OK) if (thread < B_OK)
return thread; return thread;
send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE); resume_thread(thread);
return B_OK; return B_OK;
} else if (op == B_MODULE_UNINIT) { } else if (op == B_MODULE_UNINIT) {
// deleting the sem will also cause the thread to exit // deleting the sem will also cause the thread to exit
@@ -103,7 +103,7 @@ std_ops(int32 op, ...)
if (thread < B_OK) if (thread < B_OK)
return thread; return thread;
send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE); resume_thread(thread);
add_debugger_command_etc("on_exit", &add_run_on_exit_command, add_debugger_command_etc("on_exit", &add_run_on_exit_command,
"Adds a command to be run when leaving the kernel debugger", "Adds a command to be run when leaving the kernel debugger",
+1 -1
View File
@@ -77,7 +77,7 @@ TermApp::ReadyToRun()
// a shell exits. // a shell exits.
struct sigaction action; struct sigaction action;
#ifdef __HAIKU__ #ifdef __HAIKU__
action.sa_handler = (sighandler_t)_SigChildHandler; action.sa_handler = (__sighandler_t)_SigChildHandler;
#else #else
action.sa_handler = (__signal_func_ptr)_SigChildHandler; action.sa_handler = (__signal_func_ptr)_SigChildHandler;
#endif #endif
+1 -1
View File
@@ -653,7 +653,7 @@ profile_all(const char* const* programArgs, int programArgCount)
// install signal handlers so we can exit gracefully // install signal handlers so we can exit gracefully
struct sigaction action; struct sigaction action;
action.sa_handler = (sighandler_t)signal_handler; action.sa_handler = (__sighandler_t)signal_handler;
sigemptyset(&action.sa_mask); sigemptyset(&action.sa_mask);
action.sa_userdata = NULL; action.sa_userdata = NULL;
if (sigaction(SIGHUP, &action, NULL) < 0 if (sigaction(SIGHUP, &action, NULL) < 0
@@ -116,7 +116,7 @@ public:
// install signal handlers so we can exit gracefully // install signal handlers so we can exit gracefully
struct sigaction action; struct sigaction action;
action.sa_handler = (sighandler_t)_SignalHandler; action.sa_handler = (__sighandler_t)_SignalHandler;
sigemptyset(&action.sa_mask); sigemptyset(&action.sa_mask);
action.sa_userdata = this; action.sa_userdata = this;
if (sigaction(SIGHUP, &action, NULL) < 0 if (sigaction(SIGHUP, &action, NULL) < 0
+28 -13
View File
@@ -1,8 +1,9 @@
/* /*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -11,27 +12,41 @@
#include "MemoryReader.h" #include "MemoryReader.h"
// constructor
MemoryReader::MemoryReader(port_id nubPort) MemoryReader::MemoryReader()
: fNubPort(nubPort), :
fNubPort(-1),
fReplyPort(-1) fReplyPort(-1)
{ {
fReplyPort = create_port(1, "memory reader reply");
if (fReplyPort < 0) {
fprintf(stderr, "Failed to create memory reader reply port: %s\n",
strerror(fReplyPort));
exit(1);
}
} }
// constructor
MemoryReader::~MemoryReader() MemoryReader::~MemoryReader()
{ {
if (fReplyPort >= 0) if (fReplyPort >= 0)
delete_port(fReplyPort); delete_port(fReplyPort);
} }
// Read
status_t
MemoryReader::Init(port_id nubPort)
{
if (fReplyPort >= 0)
delete_port(fReplyPort);
fNubPort = nubPort;
fReplyPort = create_port(1, "memory reader reply");
if (fReplyPort < 0) {
fprintf(stderr, "Failed to create memory reader reply port: %s\n",
strerror(fReplyPort));
return fReplyPort;
}
return B_OK;
}
status_t status_t
MemoryReader::Read(void *_address, void *_buffer, int32 size, int32 &bytesRead) MemoryReader::Read(void *_address, void *_buffer, int32 size, int32 &bytesRead)
{ {
@@ -63,7 +78,7 @@ MemoryReader::Read(void *_address, void *_buffer, int32 size, int32 &bytesRead)
return B_OK; return B_OK;
} }
// _Read
status_t status_t
MemoryReader::_Read(void *address, void *buffer, int32 size, int32 &bytesRead) MemoryReader::_Read(void *address, void *buffer, int32 size, int32 &bytesRead)
{ {
+11 -4
View File
@@ -1,22 +1,29 @@
/* /*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef STRACE_MEMORY_READER_H #ifndef STRACE_MEMORY_READER_H
#define STRACE_MEMORY_READER_H #define STRACE_MEMORY_READER_H
#include <OS.h> #include <OS.h>
class MemoryReader { class MemoryReader {
public: public:
MemoryReader(port_id nubPort); MemoryReader();
~MemoryReader(); ~MemoryReader();
status_t Read(void *address, void *buffer, int32 size, int32 &bytesRead); status_t Init(port_id nubPort);
status_t Read(void *address, void *buffer, int32 size,
int32 &bytesRead);
private: private:
status_t _Read(void *address, void *buffer, int32 size, int32 &bytesRead); status_t _Read(void *address, void *buffer, int32 size,
int32 &bytesRead);
private:
port_id fNubPort; port_id fNubPort;
port_id fReplyPort; port_id fReplyPort;
}; };
+153 -91
View File
@@ -1,8 +1,9 @@
/* /*
* Copyright 2005-2008, Ingo Weinhold, bonefish@users.sf.net. * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -25,10 +26,12 @@
#include "Syscall.h" #include "Syscall.h"
#include "TypeHandler.h" #include "TypeHandler.h"
using std::map; using std::map;
using std::string; using std::string;
using std::vector; using std::vector;
extern void get_syscalls0(vector<Syscall*> &syscalls); extern void get_syscalls0(vector<Syscall*> &syscalls);
extern void get_syscalls1(vector<Syscall*> &syscalls); extern void get_syscalls1(vector<Syscall*> &syscalls);
extern void get_syscalls2(vector<Syscall*> &syscalls); extern void get_syscalls2(vector<Syscall*> &syscalls);
@@ -50,9 +53,11 @@ extern void get_syscalls17(vector<Syscall*> &syscalls);
extern void get_syscalls18(vector<Syscall*> &syscalls); extern void get_syscalls18(vector<Syscall*> &syscalls);
extern void get_syscalls19(vector<Syscall*> &syscalls); extern void get_syscalls19(vector<Syscall*> &syscalls);
extern const char *__progname; extern const char *__progname;
static const char *kCommandName = __progname; static const char *kCommandName = __progname;
// usage // usage
static const char *kUsage = static const char *kUsage =
"Usage: %s [ <options> ] [ <thread or team ID> | <executable with args> ]\n" "Usage: %s [ <options> ] [ <thread or team ID> | <executable with args> ]\n"
@@ -74,6 +79,8 @@ static const char *kUsage =
" -r - Don't print syscall return values.\n" " -r - Don't print syscall return values.\n"
" -s - Also trace all threads spawned by the supplied thread,\n" " -s - Also trace all threads spawned by the supplied thread,\n"
" respectively the loaded executable's main thread.\n" " respectively the loaded executable's main thread.\n"
" -t - Also recursively trace all teams created by a traced\n"
" thread or team.\n"
" -T - Trace all threads of the supplied or loaded executable's\n" " -T - Trace all threads of the supplied or loaded executable's\n"
" team. If an ID is supplied, it is interpreted as a team\n" " team. If an ID is supplied, it is interpreted as a team\n"
" ID.\n" " ID.\n"
@@ -82,6 +89,7 @@ static const char *kUsage =
" -g - turns off signal tracing.\n" " -g - turns off signal tracing.\n"
; ;
// terminal color escape sequences // terminal color escape sequences
// (http://www.dee.ufcg.edu.br/~rrbrandt/tools/ansi.html) // (http://www.dee.ufcg.edu.br/~rrbrandt/tools/ansi.html)
static const char *kTerminalTextNormal = "\33[0m"; static const char *kTerminalTextNormal = "\33[0m";
@@ -89,38 +97,6 @@ static const char *kTerminalTextRed = "\33[31m";
static const char *kTerminalTextMagenta = "\33[35m"; static const char *kTerminalTextMagenta = "\33[35m";
static const char *kTerminalTextBlue = "\33[34m"; static const char *kTerminalTextBlue = "\33[34m";
static const char *kSignalName[] = {
/* 0 */ "SIG0",
/* 1 */ "SIGHUP",
/* 2 */ "SIGINT",
/* 3 */ "SIGQUIT",
/* 4 */ "SIGILL",
/* 5 */ "SIGCHLD",
/* 6 */ "SIGABRT",
/* 7 */ "SIGPIPE",
/* 8 */ "SIGFPE",
/* 9 */ "SIGKILL",
/* 10 */ "SIGSTOP",
/* 11 */ "SIGSEGV",
/* 12 */ "SIGCONT",
/* 13 */ "SIGTSTP",
/* 14 */ "SIGALRM",
/* 15 */ "SIGTERM",
/* 16 */ "SIGTTIN",
/* 17 */ "SIGTTOU",
/* 18 */ "SIGUSR1",
/* 19 */ "SIGUSR2",
/* 20 */ "SIGWINCH",
/* 21 */ "SIGKILLTHR",
/* 22 */ "SIGTRAP",
/* 23 */ "SIGPOLL",
/* 24 */ "SIGPROF",
/* 25 */ "SIGSYS",
/* 26 */ "SIGURG",
/* 27 */ "SIGVTALRM",
/* 28 */ "SIGXCPU",
/* 29 */ "SIGXFSZ",
};
// command line args // command line args
static int sArgc; static int sArgc;
@@ -130,26 +106,73 @@ static const char *const *sArgv;
static vector<Syscall*> sSyscallVector; static vector<Syscall*> sSyscallVector;
static map<string, Syscall*> sSyscallMap; static map<string, Syscall*> sSyscallMap;
// print_usage
void struct Team {
Team(team_id id)
:
fID(id),
fNubPort(-1)
{
}
team_id ID() const
{
return fID;
}
port_id NubPort() const
{
return fNubPort;
}
MemoryReader& GetMemoryReader()
{
return fMemoryReader;
}
status_t InstallDebugger(port_id debuggerPort, bool traceTeam,
bool traceChildTeams, bool traceSignal)
{
fNubPort = install_team_debugger(fID, debuggerPort);
if (fNubPort < 0) {
fprintf(stderr, "%s: Failed to install team debugger: %s\n",
kCommandName, strerror(fNubPort));
return fNubPort;
}
// set team debugging flags
int32 teamDebugFlags = (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0)
| (traceChildTeams ? B_TEAM_DEBUG_TEAM_CREATION : 0)
| (traceSignal ? B_TEAM_DEBUG_SIGNALS : 0);
set_team_debugging_flags(fNubPort, teamDebugFlags);
return fMemoryReader.Init(fNubPort);
}
private:
team_id fID;
port_id fNubPort;
MemoryReader fMemoryReader;
};
static void
print_usage(bool error) print_usage(bool error)
{ {
// print usage // print usage
fprintf((error ? stderr : stdout), kUsage, kCommandName); fprintf((error ? stderr : stdout), kUsage, kCommandName);
} }
// print_usage_and_exit
static static void
void
print_usage_and_exit(bool error) print_usage_and_exit(bool error)
{ {
print_usage(error); print_usage(error);
exit(error ? 1 : 0); exit(error ? 1 : 0);
} }
// get_id
static static bool
bool
get_id(const char *str, int32 &id) get_id(const char *str, int32 &id)
{ {
int32 len = strlen(str); int32 len = strlen(str);
@@ -162,7 +185,7 @@ get_id(const char *str, int32 &id)
return true; return true;
} }
// get_syscall
Syscall * Syscall *
get_syscall(const char *name) get_syscall(const char *name)
{ {
@@ -173,7 +196,7 @@ get_syscall(const char *name)
return i->second; return i->second;
} }
// patch_syscalls
static void static void
patch_syscalls() patch_syscalls()
{ {
@@ -185,9 +208,8 @@ patch_syscalls()
patch_ioctl(); patch_ioctl();
} }
// init_syscalls
static static void
void
init_syscalls() init_syscalls()
{ {
// init the syscall vector // init the syscall vector
@@ -222,9 +244,8 @@ init_syscalls()
patch_syscalls(); patch_syscalls();
} }
// print_to_string
static static void
void
print_to_string(char **_buffer, int32 *_length, const char *format, ...) print_to_string(char **_buffer, int32 *_length, const char *format, ...)
{ {
va_list list; va_list list;
@@ -236,9 +257,8 @@ print_to_string(char **_buffer, int32 *_length, const char *format, ...)
*_length -= length; *_length -= length;
} }
// print_syscall
static static void
void
print_syscall(FILE *outputFile, debug_post_syscall &message, print_syscall(FILE *outputFile, debug_post_syscall &message,
MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags, MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags,
bool printReturnValue, bool colorize, bool decimal) bool printReturnValue, bool colorize, bool decimal)
@@ -324,21 +344,20 @@ print_syscall(FILE *outputFile, debug_post_syscall &message,
_kern_debug_output(buffer); _kern_debug_output(buffer);
} }
static
const char * static const char *
signal_name(int signal) signal_name(int signal)
{ {
if (signal >= 0 && signal < NSIG) if (signal >= 0 && signal < NSIG)
return kSignalName[signal]; return strsignal(signal);
static char buffer[32]; static char buffer[32];
sprintf(buffer, "%d", signal); sprintf(buffer, "%d", signal);
return buffer; return buffer;
} }
// print_signal
static static void
void
print_signal(FILE *outputFile, debug_signal_received &message, print_signal(FILE *outputFile, debug_signal_received &message,
bool colorize) bool colorize)
{ {
@@ -364,7 +383,7 @@ print_signal(FILE *outputFile, debug_signal_received &message,
_kern_debug_output(buffer); _kern_debug_output(buffer);
} }
// main
int int
main(int argc, const char *const *argv) main(int argc, const char *const *argv)
{ {
@@ -383,6 +402,7 @@ main(int argc, const char *const *argv)
bool printReturnValues = true; bool printReturnValues = true;
bool traceChildThreads = false; bool traceChildThreads = false;
bool traceTeam = false; bool traceTeam = false;
bool traceChildTeams = false;
bool traceSignal = true; bool traceSignal = true;
bool serialOutput = false; bool serialOutput = false;
FILE *outputFile = stdout; FILE *outputFile = stdout;
@@ -433,6 +453,8 @@ main(int argc, const char *const *argv)
printReturnValues = false; printReturnValues = false;
} else if (strcmp(arg, "-s") == 0) { } else if (strcmp(arg, "-s") == 0) {
traceChildThreads = true; traceChildThreads = true;
} else if (strcmp(arg, "-t") == 0) {
traceChildTeams = true;
} else if (strcmp(arg, "-T") == 0) { } else if (strcmp(arg, "-T") == 0) {
traceTeam = true; traceTeam = true;
} else if (strcmp(arg, "-g") == 0) { } else if (strcmp(arg, "-g") == 0) {
@@ -488,29 +510,29 @@ main(int argc, const char *const *argv)
colorize = false; colorize = false;
// get thread/team to be debugged // get thread/team to be debugged
thread_id thread = -1; thread_id threadID = -1;
team_id team = -1; team_id teamID = -1;
if (programArgCount > 1 if (programArgCount > 1
|| !get_id(*programArgs, (traceTeam ? team : thread))) { || !get_id(*programArgs, (traceTeam ? teamID : threadID))) {
// we've been given an executable and need to load it // we've been given an executable and need to load it
thread = load_program(programArgs, programArgCount, traceLoading); threadID = load_program(programArgs, programArgCount, traceLoading);
if (thread < 0) { if (threadID < 0) {
fprintf(stderr, "%s: Failed to start `%s': %s\n", kCommandName, fprintf(stderr, "%s: Failed to start `%s': %s\n", kCommandName,
programArgs[0], strerror(thread)); programArgs[0], strerror(threadID));
exit(1); exit(1);
} }
} }
// get the team ID, if we have none yet // get the team ID, if we have none yet
if (team < 0) { if (teamID < 0) {
thread_info threadInfo; thread_info threadInfo;
status_t error = get_thread_info(thread, &threadInfo); status_t error = get_thread_info(threadID, &threadInfo);
if (error != B_OK) { if (error != B_OK) {
fprintf(stderr, "%s: Failed to get info for thread %ld: %s\n", fprintf(stderr, "%s: Failed to get info for thread %ld: %s\n",
kCommandName, thread, strerror(error)); kCommandName, threadID, strerror(error));
exit(1); exit(1);
} }
team = threadInfo.team; teamID = threadInfo.team;
} }
// create a debugger port // create a debugger port
@@ -522,34 +544,36 @@ main(int argc, const char *const *argv)
} }
// install ourselves as the team debugger // install ourselves as the team debugger
port_id nubPort = install_team_debugger(team, debuggerPort); typedef map<team_id, Team*> TeamMap;
if (nubPort < 0) { TeamMap debuggedTeams;
fprintf(stderr, "%s: Failed to install team debugger: %s\n", port_id nubPort;
kCommandName, strerror(nubPort));
{
Team* team = new Team(teamID);
status_t error = team->InstallDebugger(debuggerPort, traceTeam,
traceChildTeams, traceSignal);
if (error != B_OK)
exit(1); exit(1);
debuggedTeams[team->ID()] = team;
nubPort = team->NubPort();
} }
// set team debugging flags
int32 teamDebugFlags = (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0)
| (traceSignal ? B_TEAM_DEBUG_SIGNALS : 0);
set_team_debugging_flags(nubPort, teamDebugFlags);
// set thread debugging flags // set thread debugging flags
if (thread >= 0) { if (threadID >= 0) {
int32 threadDebugFlags = 0; int32 threadDebugFlags = 0;
if (!traceTeam) { if (!traceTeam) {
threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
| (traceChildThreads | (traceChildThreads
? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
} }
set_thread_debugging_flags(nubPort, thread, threadDebugFlags); set_thread_debugging_flags(nubPort, threadID, threadDebugFlags);
// resume the target thread to be sure, it's running // resume the target thread to be sure, it's running
resume_thread(thread); resume_thread(threadID);
} }
MemoryReader memoryReader(nubPort);
// debug loop // debug loop
while (true) { while (true) {
bool quitLoop = false; bool quitLoop = false;
@@ -570,6 +594,13 @@ main(int argc, const char *const *argv)
switch (code) { switch (code) {
case B_DEBUGGER_MESSAGE_POST_SYSCALL: case B_DEBUGGER_MESSAGE_POST_SYSCALL:
{ {
TeamMap::iterator it = debuggedTeams.find(message.origin.team);
if (it == debuggedTeams.end())
break;
Team* team = it->second;
MemoryReader& memoryReader = team->GetMemoryReader();
print_syscall(outputFile, message.post_syscall, memoryReader, print_syscall(outputFile, message.post_syscall, memoryReader,
printArguments, contentsFlags, printReturnValues, printArguments, contentsFlags, printReturnValues,
colorize, decimalFormat); colorize, decimalFormat);
@@ -578,10 +609,8 @@ main(int argc, const char *const *argv)
case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
{ {
if (traceSignal) { if (traceSignal)
print_signal(outputFile, message.signal_received, print_signal(outputFile, message.signal_received, colorize);
colorize);
}
break; break;
} }
@@ -592,17 +621,50 @@ main(int argc, const char *const *argv)
case B_DEBUGGER_MESSAGE_SINGLE_STEP: case B_DEBUGGER_MESSAGE_SINGLE_STEP:
case B_DEBUGGER_MESSAGE_PRE_SYSCALL: case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
case B_DEBUGGER_MESSAGE_TEAM_CREATED:
case B_DEBUGGER_MESSAGE_THREAD_CREATED: case B_DEBUGGER_MESSAGE_THREAD_CREATED:
case B_DEBUGGER_MESSAGE_THREAD_DELETED: case B_DEBUGGER_MESSAGE_THREAD_DELETED:
case B_DEBUGGER_MESSAGE_IMAGE_CREATED: case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
case B_DEBUGGER_MESSAGE_IMAGE_DELETED: case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
break; break;
case B_DEBUGGER_MESSAGE_TEAM_DELETED: case B_DEBUGGER_MESSAGE_TEAM_CREATED:
// the debugged team is gone {
quitLoop = true; if (!traceChildTeams)
break; break;
Team* team = new(std::nothrow) Team(
message.team_created.new_team);
if (team == NULL) {
fprintf(stderr, "%s: Out of memory!\n", kCommandName);
break;
}
status_t error = team->InstallDebugger(debuggerPort, true, true,
traceSignal);
if (error != B_OK) {
delete team;
break;
}
debuggedTeams[team->ID()] = team;
break;
}
case B_DEBUGGER_MESSAGE_TEAM_DELETED:
{
// a debugged team is gone
TeamMap::iterator it = debuggedTeams.find(message.origin.team);
if (it == debuggedTeams.end())
break;
Team* team = it->second;
debuggedTeams.erase(it);
delete team;
// if all debugged teams are gone, we're done
quitLoop = debuggedTeams.empty();
break;
}
} }
if (quitLoop) if (quitLoop)
+1 -1
View File
@@ -114,7 +114,7 @@
/* #undef HAVE_ON_EXIT */ /* #undef HAVE_ON_EXIT */
/* Define to 1 if you have the `psignal' function. */ /* Define to 1 if you have the `psignal' function. */
/* #undef HAVE_PSIGNAL */ #define HAVE_PSIGNAL 1
/* Define to 1 if you have the `pstat_getdynamic' function. */ /* Define to 1 if you have the `pstat_getdynamic' function. */
/* #undef HAVE_PSTAT_GETDYNAMIC */ /* #undef HAVE_PSTAT_GETDYNAMIC */
+15 -7
View File
@@ -12,6 +12,7 @@
#include <errno.h> #include <errno.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@@ -176,7 +177,8 @@ connect(int socket, const struct sockaddr *address, socklen_t addressLength)
addressLength = sizeof(struct sockaddr_in); addressLength = sizeof(struct sockaddr_in);
} }
RETURN_AND_SET_ERRNO(_kern_connect(socket, address, addressLength)); RETURN_AND_SET_ERRNO_TEST_CANCEL(
_kern_connect(socket, address, addressLength));
} }
@@ -205,6 +207,9 @@ accept(int socket, struct sockaddr *_address, socklen_t *_addressLength)
} }
int acceptSocket = _kern_accept(socket, address, &addressLength); int acceptSocket = _kern_accept(socket, address, &addressLength);
pthread_testcancel();
if (acceptSocket < 0) { if (acceptSocket < 0) {
errno = acceptSocket; errno = acceptSocket;
return -1; return -1;
@@ -224,7 +229,7 @@ accept(int socket, struct sockaddr *_address, socklen_t *_addressLength)
extern "C" ssize_t extern "C" ssize_t
recv(int socket, void *data, size_t length, int flags) recv(int socket, void *data, size_t length, int flags)
{ {
RETURN_AND_SET_ERRNO(_kern_recv(socket, data, length, flags)); RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recv(socket, data, length, flags));
} }
@@ -248,6 +253,9 @@ recvfrom(int socket, void *data, size_t length, int flags,
ssize_t bytesReceived = _kern_recvfrom(socket, data, length, flags, ssize_t bytesReceived = _kern_recvfrom(socket, data, length, flags,
address, &addressLength); address, &addressLength);
pthread_testcancel();
if (bytesReceived < 0) { if (bytesReceived < 0) {
errno = bytesReceived; errno = bytesReceived;
return -1; return -1;
@@ -267,14 +275,14 @@ recvfrom(int socket, void *data, size_t length, int flags,
extern "C" ssize_t extern "C" ssize_t
recvmsg(int socket, struct msghdr *message, int flags) recvmsg(int socket, struct msghdr *message, int flags)
{ {
RETURN_AND_SET_ERRNO(_kern_recvmsg(socket, message, flags)); RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recvmsg(socket, message, flags));
} }
extern "C" ssize_t extern "C" ssize_t
send(int socket, const void *data, size_t length, int flags) send(int socket, const void *data, size_t length, int flags)
{ {
RETURN_AND_SET_ERRNO(_kern_send(socket, data, length, flags)); RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_send(socket, data, length, flags));
} }
@@ -290,15 +298,15 @@ sendto(int socket, const void *data, size_t length, int flags,
addressLength = sizeof(struct sockaddr_in); addressLength = sizeof(struct sockaddr_in);
} }
RETURN_AND_SET_ERRNO(_kern_sendto(socket, data, length, flags, address, RETURN_AND_SET_ERRNO_TEST_CANCEL(
addressLength)); _kern_sendto(socket, data, length, flags, address, addressLength));
} }
extern "C" ssize_t extern "C" ssize_t
sendmsg(int socket, const struct msghdr *message, int flags) sendmsg(int socket, const struct msghdr *message, int flags)
{ {
RETURN_AND_SET_ERRNO(_kern_sendmsg(socket, message, flags)); RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sendmsg(socket, message, flags));
} }
+1
View File
@@ -14,4 +14,5 @@ StaticLibrary libposix_error_mapper.a :
pthread_spinlock.cpp pthread_spinlock.cpp
pthread_thread.cpp pthread_thread.cpp
signal.cpp signal.cpp
time.cpp
; ;
@@ -1,10 +1,11 @@
/* /*
* Copyright 2009-2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <pthread.h> #include <pthread.h>
#include <signal.h>
#include "posix_error_mapper.h" #include "posix_error_mapper.h"
+6 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2010-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -13,3 +13,8 @@ WRAPPER_FUNCTION(int, pthread_sigmask,
(int how, const sigset_t *set, sigset_t *oldSet), (int how, const sigset_t *set, sigset_t *oldSet),
return B_TO_POSITIVE_ERROR(sReal_pthread_sigmask(how, set, oldSet)); return B_TO_POSITIVE_ERROR(sReal_pthread_sigmask(how, set, oldSet));
) )
WRAPPER_FUNCTION(int, sigwait, (const sigset_t *set, int *signal),
return B_TO_POSITIVE_ERROR(sReal_sigwait(set, signal));
)
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <time.h>
#include "posix_error_mapper.h"
WRAPPER_FUNCTION(int, clock_nanosleep,
(clockid_t clockID, int flags, const struct timespec* time,
struct timespec* remainingTime),
return B_TO_POSITIVE_ERROR(sReal_clock_nanosleep(clockID, flags, time,
remainingTime));
)
WRAPPER_FUNCTION(int, clock_getcpuclockid,
(pid_t pid, clockid_t* _clockID),
return B_TO_POSITIVE_ERROR(sReal_clock_getcpuclockid(pid, _clockID));
)
+327
View File
@@ -0,0 +1,327 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <DPC.h>
#include <util/AutoLock.h>
#define NORMAL_PRIORITY B_NORMAL_PRIORITY
#define HIGH_PRIORITY B_URGENT_DISPLAY_PRIORITY
#define REAL_TIME_PRIORITY B_FIRST_REAL_TIME_PRIORITY
#define DEFAULT_QUEUE_SLOT_COUNT 64
static DPCQueue sNormalPriorityQueue;
static DPCQueue sHighPriorityQueue;
static DPCQueue sRealTimePriorityQueue;
// #pragma mark - FunctionDPCCallback
FunctionDPCCallback::FunctionDPCCallback(DPCQueue* owner)
:
fOwner(owner)
{
}
void
FunctionDPCCallback::SetTo(void (*function)(void*), void* argument)
{
fFunction = function;
fArgument = argument;
}
void
FunctionDPCCallback::DoDPC(DPCQueue* queue)
{
fFunction(fArgument);
if (fOwner != NULL)
fOwner->Recycle(this);
}
// #pragma mark - DPCCallback
DPCCallback::DPCCallback()
:
fInQueue(NULL)
{
}
DPCCallback::~DPCCallback()
{
}
// #pragma mark - DPCQueue
DPCQueue::DPCQueue()
:
fThreadID(-1),
fCallbackInProgress(NULL),
fCallbackDoneCondition(NULL)
{
B_INITIALIZE_SPINLOCK(&fLock);
fPendingCallbacksCondition.Init(this, "dpc queue");
}
DPCQueue::~DPCQueue()
{
// close, if not closed yet
{
InterruptsSpinLocker locker(fLock);
if (!_IsClosed()) {
locker.Unlock();
Close(false);
}
}
// delete function callbacks
while (DPCCallback* callback = fUnusedFunctionCallbacks.RemoveHead())
delete callback;
}
/*static*/ DPCQueue*
DPCQueue::DefaultQueue(int priority)
{
if (priority <= NORMAL_PRIORITY)
return &sNormalPriorityQueue;
if (priority <= HIGH_PRIORITY)
return &sHighPriorityQueue;
return &sRealTimePriorityQueue;
}
status_t
DPCQueue::Init(const char* name, int32 priority, uint32 reservedSlots)
{
// create function callbacks
for (uint32 i = 0; i < reservedSlots; i++) {
FunctionDPCCallback* callback
= new(std::nothrow) FunctionDPCCallback(this);
if (callback == NULL)
return B_NO_MEMORY;
fUnusedFunctionCallbacks.Add(callback);
}
// spawn the thread
fThreadID = spawn_kernel_thread(&_ThreadEntry, name, priority, this);
if (fThreadID < 0)
return fThreadID;
resume_thread(fThreadID);
return B_OK;
}
void
DPCQueue::Close(bool cancelPending)
{
InterruptsSpinLocker locker(fLock);
if (_IsClosed())
return;
// If requested, dequeue all pending callbacks
if (cancelPending)
fCallbacks.MakeEmpty();
// mark the queue closed
thread_id thread = fThreadID;
fThreadID = -1;
locker.Unlock();
// wake up the thread and wait for it
fPendingCallbacksCondition.NotifyAll();
wait_for_thread(thread, NULL);
}
status_t
DPCQueue::Add(DPCCallback* callback, bool schedulerLocked)
{
// queue the callback, if the queue isn't closed already
InterruptsSpinLocker locker(fLock);
if (_IsClosed())
return B_NOT_INITIALIZED;
bool wasEmpty = fCallbacks.IsEmpty();
fCallbacks.Add(callback);
callback->fInQueue = this;
locker.Unlock();
// notify the condition variable, if necessary
if (wasEmpty)
fPendingCallbacksCondition.NotifyAll(schedulerLocked);
return B_OK;
}
status_t
DPCQueue::Add(void (*function)(void*), void* argument, bool schedulerLocked)
{
if (function == NULL)
return B_BAD_VALUE;
// get a free callback
InterruptsSpinLocker locker(fLock);
DPCCallback* callback = fUnusedFunctionCallbacks.RemoveHead();
if (callback == NULL)
return B_NO_MEMORY;
locker.Unlock();
// init the callback
FunctionDPCCallback* functionCallback
= static_cast<FunctionDPCCallback*>(callback);
functionCallback->SetTo(function, argument);
// add it
status_t error = Add(functionCallback, schedulerLocked);
if (error != B_OK)
Recycle(functionCallback);
return error;
}
bool
DPCQueue::Cancel(DPCCallback* callback)
{
InterruptsSpinLocker locker(fLock);
// If the callback is queued, remove it.
if (callback->fInQueue == this) {
fCallbacks.Remove(callback);
return true;
}
// The callback is not queued. If it isn't in progress, we're done, too.
if (callback != fCallbackInProgress)
return false;
// The callback is currently being executed. We need to wait for it to be
// done.
// Set the respective condition, if not set yet. For the unlikely case that
// there are multiple threads trying to cancel the callback at the same
// time, the condition variable of the first thread will be used.
ConditionVariable condition;
if (fCallbackDoneCondition == NULL)
fCallbackDoneCondition = &condition;
// add our wait entry
ConditionVariableEntry waitEntry;
fCallbackDoneCondition->Add(&waitEntry);
// wait
locker.Unlock();
waitEntry.Wait();
return false;
}
void
DPCQueue::Recycle(FunctionDPCCallback* callback)
{
InterruptsSpinLocker locker(fLock);
fUnusedFunctionCallbacks.Insert(callback, false);
}
/*static*/ status_t
DPCQueue::_ThreadEntry(void* data)
{
return ((DPCQueue*)data)->_Thread();
}
status_t
DPCQueue::_Thread()
{
while (true) {
InterruptsSpinLocker locker(fLock);
// get the next pending callback
DPCCallback* callback = fCallbacks.RemoveHead();
if (callback == NULL) {
// nothing is pending -- wait unless the queue is already closed
if (_IsClosed())
break;
ConditionVariableEntry waitEntry;
fPendingCallbacksCondition.Add(&waitEntry);
locker.Unlock();
waitEntry.Wait();
continue;
}
callback->fInQueue = NULL;
fCallbackInProgress = callback;
// call the callback
locker.Unlock();
callback->DoDPC(this);
locker.Lock();
fCallbackInProgress = NULL;
// wake up threads waiting for the callback to be done
ConditionVariable* doneCondition = fCallbackDoneCondition;
fCallbackDoneCondition = NULL;
locker.Unlock();
if (doneCondition != NULL)
doneCondition->NotifyAll();
}
return B_OK;
}
// #pragma mark - kernel private
void
dpc_init()
{
// create the default queues
new(&sNormalPriorityQueue) DPCQueue;
new(&sHighPriorityQueue) DPCQueue;
new(&sRealTimePriorityQueue) DPCQueue;
if (sNormalPriorityQueue.Init("dpc: normal priority", NORMAL_PRIORITY,
DEFAULT_QUEUE_SLOT_COUNT) != B_OK
|| sHighPriorityQueue.Init("dpc: high priority", HIGH_PRIORITY,
DEFAULT_QUEUE_SLOT_COUNT) != B_OK
|| sRealTimePriorityQueue.Init("dpc: real-time priority",
REAL_TIME_PRIORITY, DEFAULT_QUEUE_SLOT_COUNT) != B_OK) {
panic("Failed to create default DPC queues!");
}
}
+3
View File
@@ -28,6 +28,7 @@ KernelMergeObject kernel_core.o :
commpage.cpp commpage.cpp
condition_variable.cpp condition_variable.cpp
cpu.cpp cpu.cpp
DPC.cpp
elf.cpp elf.cpp
heap.cpp heap.cpp
image.cpp image.cpp
@@ -50,7 +51,9 @@ KernelMergeObject kernel_core.o :
team.cpp team.cpp
thread.cpp thread.cpp
timer.cpp timer.cpp
UserEvent.cpp
usergroup.cpp usergroup.cpp
UserTimer.cpp
wait_for_objects.cpp wait_for_objects.cpp
# locks # locks
+184
View File
@@ -0,0 +1,184 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_TEAM_THREAD_TABLES_H
#define KERNEL_TEAM_THREAD_TABLES_H
#include <thread_types.h>
namespace BKernel {
template<typename Element>
struct TeamThreadTable {
public:
typedef typename Element::id_type id_type;
typedef typename Element::iterator_type IteratorEntry;
struct Iterator {
Iterator()
:
fNext(NULL)
{
}
Iterator(IteratorEntry* nextEntry)
{
_SetNext(nextEntry);
}
bool HasNext() const
{
return fNext != NULL;
}
Element* Next()
{
Element* result = fNext;
if (result != NULL)
_SetNext(result->GetDoublyLinkedListLink()->next);
return result;
}
private:
void _SetNext(IteratorEntry* entry)
{
while (entry != NULL) {
if (entry->id >= 0) {
fNext = static_cast<Element*>(entry);
return;
}
entry = entry->GetDoublyLinkedListLink()->next;
}
fNext = NULL;
}
private:
Element* fNext;
};
public:
TeamThreadTable()
:
fNextSerialNumber(1)
{
}
status_t Init(size_t initialSize)
{
return fTable.Init(initialSize);
}
void Insert(Element* element)
{
element->serial_number = fNextSerialNumber++;
fTable.InsertUnchecked(element);
fList.Add(element);
}
void Remove(Element* element)
{
fTable.RemoveUnchecked(element);
fList.Remove(element);
}
Element* Lookup(id_type id, bool visibleOnly = true) const
{
Element* element = fTable.Lookup(id);
return element != NULL && (!visibleOnly || element->visible)
? element : NULL;
}
/*! Gets an iterator.
The iterator iterates through all, including invisible, entries!
*/
Iterator GetIterator()
{
return Iterator(fList.Head());
}
void InsertIteratorEntry(IteratorEntry* entry)
{
// add to front
entry->id = -1;
entry->visible = false;
fList.Add(entry, false);
}
void RemoveIteratorEntry(IteratorEntry* entry)
{
fList.Remove(entry);
}
Element* NextElement(IteratorEntry* entry, bool visibleOnly = true)
{
if (entry == fList.Tail())
return NULL;
IteratorEntry* nextEntry = entry;
while (true) {
nextEntry = nextEntry->GetDoublyLinkedListLink()->next;
if (nextEntry == NULL) {
// end of list -- requeue entry at the end and return NULL
fList.Remove(entry);
fList.Add(entry);
return NULL;
}
if (nextEntry->id >= 0 && (!visibleOnly || nextEntry->visible)) {
// found an element -- requeue entry after element
Element* element = static_cast<Element*>(nextEntry);
fList.Remove(entry);
fList.InsertAfter(nextEntry, entry);
return element;
}
}
}
private:
struct HashDefinition {
typedef id_type KeyType;
typedef Element ValueType;
size_t HashKey(id_type key) const
{
return key;
}
size_t Hash(Element* value) const
{
return HashKey(value->id);
}
bool Compare(id_type key, Element* value) const
{
return value->id == key;
}
Element*& GetLink(Element* value) const
{
return value->hash_next;
}
};
typedef BOpenHashTable<HashDefinition> ElementTable;
typedef DoublyLinkedList<IteratorEntry> List;
private:
ElementTable fTable;
List fList;
int64 fNextSerialNumber;
};
} // namespace BKernel
#endif // KERNEL_TEAM_THREAD_TABLES_H
+243
View File
@@ -0,0 +1,243 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <UserEvent.h>
#include <ksignal.h>
#include <thread_types.h>
#include <util/AutoLock.h>
// #pragma mark - UserEvent
UserEvent::~UserEvent()
{
}
// #pragma mark - SignalEvent
struct SignalEvent::EventSignal : Signal {
EventSignal(uint32 number, int32 signalCode, int32 errorCode,
pid_t sendingProcess)
:
Signal(number, signalCode, errorCode, sendingProcess),
fInUse(false)
{
}
bool IsInUse() const
{
return fInUse;
}
void SetInUse(bool inUse)
{
fInUse = inUse;
}
virtual void Handled()
{
// mark not-in-use
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
fInUse = false;
schedulerLocker.Unlock();
Signal::Handled();
}
private:
bool fInUse;
};
SignalEvent::SignalEvent(EventSignal* signal)
:
fSignal(signal)
{
}
SignalEvent::~SignalEvent()
{
fSignal->ReleaseReference();
}
void
SignalEvent::SetUserValue(union sigval userValue)
{
fSignal->SetUserValue(userValue);
}
// #pragma mark - TeamSignalEvent
TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
:
SignalEvent(signal),
fTeam(team)
{
}
/*static*/ TeamSignalEvent*
TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
int32 errorCode)
{
// create the signal
EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
signalCode, errorCode, team->id);
if (signal == NULL)
return NULL;
// create the event
TeamSignalEvent* event = new TeamSignalEvent(team, signal);
if (event == NULL) {
delete signal;
return NULL;
}
return event;
}
status_t
TeamSignalEvent::Fire()
{
// called with the scheduler lock held
if (fSignal->IsInUse())
return B_BUSY;
fSignal->AcquireReference();
// one reference is transferred to send_signal_to_team_locked
status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
fSignal, B_DO_NOT_RESCHEDULE);
if (error == B_OK) {
// Mark the signal in-use. There are situations (for certain signals),
// in which send_signal_to_team_locked() succeeds without queuing the
// signal.
fSignal->SetInUse(fSignal->IsPending());
}
return error;
}
// #pragma mark - ThreadSignalEvent
ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal)
:
SignalEvent(signal),
fThread(thread)
{
}
/*static*/ ThreadSignalEvent*
ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
int32 errorCode, pid_t sendingTeam)
{
// create the signal
EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
signalCode, errorCode, sendingTeam);
if (signal == NULL)
return NULL;
// create the event
ThreadSignalEvent* event = new ThreadSignalEvent(thread, signal);
if (event == NULL) {
delete signal;
return NULL;
}
return event;
}
status_t
ThreadSignalEvent::Fire()
{
// called with the scheduler lock held
if (fSignal->IsInUse())
return B_BUSY;
fSignal->AcquireReference();
// one reference is transferred to send_signal_to_team_locked
status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
fSignal, B_DO_NOT_RESCHEDULE);
if (error == B_OK) {
// Mark the signal in-use. There are situations (for certain signals),
// in which send_signal_to_team_locked() succeeds without queuing the
// signal.
fSignal->SetInUse(fSignal->IsPending());
}
return error;
}
// #pragma mark - UserEvent
CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
:
fCreationAttributes(attributes),
fPendingDPC(false)
{
// attributes.name is a pointer to a temporary buffer. Copy the name into
// our own buffer and replace the name pointer.
strlcpy(fThreadName, attributes.name, sizeof(fThreadName));
fCreationAttributes.name = fThreadName;
}
CreateThreadEvent::~CreateThreadEvent()
{
// cancel the DPC to be on the safe side
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Cancel(this);
}
/*static*/ CreateThreadEvent*
CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
{
return new(std::nothrow) CreateThreadEvent(attributes);
}
status_t
CreateThreadEvent::Fire()
{
if (fPendingDPC)
return B_BUSY;
fPendingDPC = true;
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true);
return B_OK;
}
void
CreateThreadEvent::DoDPC(DPCQueue* queue)
{
// We're no longer queued in the DPC queue, so we can be reused.
{
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
fPendingDPC = false;
}
// create the thread
thread_id threadID = thread_create_thread(fCreationAttributes, false);
if (threadID >= 0)
resume_thread(threadID);
}
File diff suppressed because it is too large Load Diff
+6 -41
View File
@@ -63,47 +63,11 @@ arch_thread_init_thread_struct(Thread *thread)
} }
status_t void
arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void), arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*entry_func)(void), void (*exit_func)(void)) void (*function)(void*), const void* data)
{ {
/* addr_t *kstack = (addr_t *)t->kernel_stack_base;
addr_t *kstackTop = (addr_t *)t->kernel_stack_base;
// clear the kernel stack
#ifdef DEBUG_KERNEL_STACKS
# ifdef STACK_GROWS_DOWNWARDS
memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0,
KERNEL_STACK_SIZE);
# else
memset(kstack, 0, KERNEL_STACK_SIZE);
# endif
#else
memset(kstack, 0, KERNEL_STACK_SIZE);
#endif
// space for frame pointer and return address, and stack frames must be
// 16 byte aligned
kstackTop -= 2;
kstackTop = (addr_t*)((addr_t)kstackTop & ~0xf);
// LR, CR, r2, r13-r31, f13-f31, as pushed by m68k_context_switch()
kstackTop -= 22 + 2 * 19;
// let LR point to m68k_kernel_thread_root()
kstackTop[0] = (addr_t)&m68k_kernel_thread_root;
// the arguments of m68k_kernel_thread_root() are the functions to call,
// provided in registers r13-r15
kstackTop[3] = (addr_t)entry_func;
kstackTop[4] = (addr_t)start_func;
kstackTop[5] = (addr_t)exit_func;
// save this stack position
t->arch_info.sp = (void *)kstackTop;
*/
#warning ARM:WRITEME #warning ARM:WRITEME
return B_OK;
} }
@@ -157,14 +121,15 @@ arch_on_signal_stack(Thread *thread)
status_t status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *sa, int sig, int sigMask) arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
struct signal_frame_data *signalFrameData)
{ {
return B_ERROR; return B_ERROR;
} }
int64 int64
arch_restore_signal_frame(void) arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
{ {
return 0; return 0;
} }
+1 -1
View File
@@ -129,7 +129,7 @@ stack_trace(int argc, char **argv)
} else { } else {
// TODO: Add support for stack traces of other threads. // TODO: Add support for stack traces of other threads.
/* thread_id id = strtoul(argv[1], NULL, 0); /* thread_id id = strtoul(argv[1], NULL, 0);
thread = thread_get_thread_struct_locked(id); thread = Thread::GetDebug(id);
if (thread == NULL) { if (thread == NULL) {
kprintf("could not find thread %ld\n", id); kprintf("could not find thread %ld\n", id);
return 0; return 0;
+5 -3
View File
@@ -23,6 +23,7 @@
#include <smp.h> #include <smp.h>
#include <thread.h> #include <thread.h>
#include <timer.h> #include <timer.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
#include <vm/vm.h> #include <vm/vm.h>
@@ -296,18 +297,19 @@ dprintf("handling I/O interrupts done\n");
int state = disable_interrupts(); int state = disable_interrupts();
if (thread->cpu->invoke_scheduler) { if (thread->cpu->invoke_scheduler) {
GRAB_THREAD_LOCK(); SpinLocker schedulerLocker(gSchedulerLock);
scheduler_reschedule(); scheduler_reschedule();
RELEASE_THREAD_LOCK(); schedulerLocker.Unlock();
restore_interrupts(state); restore_interrupts(state);
} else if (hardwareInterrupt && thread->post_interrupt_callback != NULL) { } else if (hardwareInterrupt && thread->post_interrupt_callback != NULL) {
restore_interrupts(state);
void (*callback)(void*) = thread->post_interrupt_callback; void (*callback)(void*) = thread->post_interrupt_callback;
void* data = thread->post_interrupt_data; void* data = thread->post_interrupt_data;
thread->post_interrupt_callback = NULL; thread->post_interrupt_callback = NULL;
thread->post_interrupt_data = NULL; thread->post_interrupt_data = NULL;
restore_interrupts(state);
callback(data); callback(data);
} }
+10 -5
View File
@@ -146,10 +146,11 @@ arch_thread_init_thread_struct(Thread *thread)
} }
status_t void
arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void), arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*entry_func)(void), void (*exit_func)(void)) void (*function)(void*), const void* data)
{ {
#if 0
addr_t *kstack = (addr_t *)t->kernel_stack_base; addr_t *kstack = (addr_t *)t->kernel_stack_base;
addr_t *kstackTop = (addr_t *)t->kernel_stack_base; addr_t *kstackTop = (addr_t *)t->kernel_stack_base;
@@ -186,6 +187,9 @@ arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void),
t->arch_info.sp = (void *)kstackTop; t->arch_info.sp = (void *)kstackTop;
return B_OK; return B_OK;
#else
panic("arch_thread_init_kthread_stack(): Implement me!");
#endif
} }
@@ -237,14 +241,15 @@ arch_on_signal_stack(Thread *thread)
status_t status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *sa, int sig, int sigMask) arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
struct signal_frame_data *signalFrameData)
{ {
return B_ERROR; return B_ERROR;
} }
int64 int64
arch_restore_signal_frame(void) arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
{ {
return 0; return 0;
} }
@@ -86,12 +86,11 @@ arch_thread_init_thread_struct(Thread *thread)
} }
status_t void
arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void), arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*entry_func)(void), void (*exit_func)(void)) void (*function)(void*), const void* data)
{ {
#warning IMPLEMENT arch_thread_init_kthread_stack #warning IMPLEMENT arch_thread_init_kthread_stack
return B_ERROR;
} }
@@ -136,8 +135,8 @@ arch_on_signal_stack(Thread *thread)
status_t status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *sa, int sig, arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
int sigMask) struct signal_frame_data *signalFrameData)
{ {
#warning IMPLEMENT arch_setup_signal_frame #warning IMPLEMENT arch_setup_signal_frame
return B_ERROR; return B_ERROR;
@@ -145,7 +144,7 @@ arch_setup_signal_frame(Thread *thread, struct sigaction *sa, int sig,
int64 int64
arch_restore_signal_frame(void) arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
{ {
#warning IMPLEMENT arch_restore_signal_frame #warning IMPLEMENT arch_restore_signal_frame
return 0; return 0;
+1 -1
View File
@@ -129,7 +129,7 @@ stack_trace(int argc, char **argv)
} else { } else {
// TODO: Add support for stack traces of other threads. // TODO: Add support for stack traces of other threads.
/* thread_id id = strtoul(argv[1], NULL, 0); /* thread_id id = strtoul(argv[1], NULL, 0);
thread = thread_get_thread_struct_locked(id); thread = Thread::GetDebug(id);
if (thread == NULL) { if (thread == NULL) {
kprintf("could not find thread %ld\n", id); kprintf("could not find thread %ld\n", id);
return 0; return 0;
+5 -3
View File
@@ -21,6 +21,7 @@
#include <smp.h> #include <smp.h>
#include <thread.h> #include <thread.h>
#include <timer.h> #include <timer.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h> #include <util/DoublyLinkedList.h>
#include <util/kernel_cpp.h> #include <util/kernel_cpp.h>
#include <vm/vm.h> #include <vm/vm.h>
@@ -243,18 +244,19 @@ dprintf("handling I/O interrupts done\n");
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
if (thread->cpu->invoke_scheduler) { if (thread->cpu->invoke_scheduler) {
GRAB_THREAD_LOCK(); SpinLocker schedulerLocker(gSchedulerLock);
scheduler_reschedule(); scheduler_reschedule();
RELEASE_THREAD_LOCK(); schedulerLocker.Unlock();
restore_interrupts(state); restore_interrupts(state);
} else if (thread->post_interrupt_callback != NULL) { } else if (thread->post_interrupt_callback != NULL) {
restore_interrupts(state);
void (*callback)(void*) = thread->post_interrupt_callback; void (*callback)(void*) = thread->post_interrupt_callback;
void* data = thread->post_interrupt_data; void* data = thread->post_interrupt_data;
thread->post_interrupt_callback = NULL; thread->post_interrupt_callback = NULL;
thread->post_interrupt_data = NULL; thread->post_interrupt_data = NULL;
restore_interrupts(state);
callback(data); callback(data);
} }
+10 -5
View File
@@ -114,10 +114,11 @@ arch_thread_init_thread_struct(Thread *thread)
} }
status_t void
arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void), arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*entry_func)(void), void (*exit_func)(void)) void (*function)(void*), const void* data)
{ {
#if 0
addr_t *kstack = (addr_t *)t->kernel_stack_base; addr_t *kstack = (addr_t *)t->kernel_stack_base;
addr_t *kstackTop = (addr_t *)t->kernel_stack_top; addr_t *kstackTop = (addr_t *)t->kernel_stack_top;
@@ -154,6 +155,9 @@ arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void),
t->arch_info.sp = (void *)kstackTop; t->arch_info.sp = (void *)kstackTop;
return B_OK; return B_OK;
#else
panic("arch_thread_init_kthread_stack(): Implement me!");
#endif
} }
@@ -212,14 +216,15 @@ arch_on_signal_stack(Thread *thread)
status_t status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *sa, int sig, int sigMask) arch_setup_signal_frame(Thread *thread, struct sigaction *sa,
struct signal_frame_data *signalFrameData)
{ {
return B_ERROR; return B_ERROR;
} }
int64 int64
arch_restore_signal_frame(void) arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
{ {
return 0; return 0;
} }
+3 -1
View File
@@ -45,11 +45,13 @@ KernelMergeObject kernel_arch_x86.o :
pic.cpp pic.cpp
syscall.S syscall.S
vm86.cpp vm86.cpp
x86_signals.cpp
x86_signals_asm.S
x86_syscalls.cpp
# paging # paging
x86_physical_page_mapper.cpp x86_physical_page_mapper.cpp
x86_physical_page_mapper_large_memory.cpp x86_physical_page_mapper_large_memory.cpp
x86_syscalls.cpp
X86PagingMethod.cpp X86PagingMethod.cpp
X86PagingStructures.cpp X86PagingStructures.cpp
X86VMTranslationMap.cpp X86VMTranslationMap.cpp
+5 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2007, Travis Geiselbrecht. All rights reserved. * Copyright 2007, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -7,6 +7,7 @@
#include <commpage.h> #include <commpage.h>
#include "x86_signals.h"
#include "x86_syscalls.h" #include "x86_syscalls.h"
@@ -23,5 +24,8 @@ arch_commpage_init_post_cpus(void)
// select the optimum syscall mechanism and patch the commpage // select the optimum syscall mechanism and patch the commpage
x86_initialize_commpage_syscall(); x86_initialize_commpage_syscall();
// initialize the signal handler code in the commpage
x86_initialize_commpage_signal_handler();
return B_OK; return B_OK;
} }
+3 -3
View File
@@ -388,7 +388,7 @@ setup_for_thread(char *arg, Thread **_thread, uint32 *_ebp,
if (arg != NULL) { if (arg != NULL) {
thread_id id = strtoul(arg, NULL, 0); thread_id id = strtoul(arg, NULL, 0);
thread = thread_get_thread_struct_locked(id); thread = Thread::GetDebug(id);
if (thread == NULL) { if (thread == NULL) {
kprintf("could not find thread %ld\n", id); kprintf("could not find thread %ld\n", id);
return false; return false;
@@ -855,7 +855,7 @@ dump_iframes(int argc, char **argv)
thread = thread_get_current_thread(); thread = thread_get_current_thread();
} else if (argc == 2) { } else if (argc == 2) {
thread_id id = strtoul(argv[1], NULL, 0); thread_id id = strtoul(argv[1], NULL, 0);
thread = thread_get_thread_struct_locked(id); thread = Thread::GetDebug(id);
if (thread == NULL) { if (thread == NULL) {
kprintf("could not find thread %ld\n", id); kprintf("could not find thread %ld\n", id);
return 0; return 0;
@@ -925,7 +925,7 @@ cmd_in_context(int argc, char** argv)
return 0; return 0;
// get the thread // get the thread
Thread* thread = thread_get_thread_struct_locked(threadID); Thread* thread = Thread::GetDebug(threadID);
if (thread == NULL) { if (thread == NULL) {
kprintf("Could not find thread with ID \"%s\".\n", threadIDString); kprintf("Could not find thread with ID \"%s\".\n", threadIDString);
return 0; return 0;
+45 -17
View File
@@ -17,6 +17,7 @@
#include <smp.h> #include <smp.h>
#include <team.h> #include <team.h>
#include <thread.h> #include <thread.h>
#include <util/AutoLock.h>
#include <vm/vm.h> #include <vm/vm.h>
#include <vm/vm_priv.h> #include <vm/vm_priv.h>
@@ -244,7 +245,10 @@ static void
unexpected_exception(struct iframe* frame) unexpected_exception(struct iframe* frame)
{ {
debug_exception_type type; debug_exception_type type;
int signal; uint32 signalNumber;
int32 signalCode;
addr_t signalAddress = 0;
int32 signalError = B_ERROR;
if (IFRAME_IS_VM86(frame)) { if (IFRAME_IS_VM86(frame)) {
x86_vm86_return((struct vm86_iframe *)frame, (frame->vector == 13) ? x86_vm86_return((struct vm86_iframe *)frame, (frame->vector == 13) ?
@@ -255,42 +259,62 @@ unexpected_exception(struct iframe* frame)
switch (frame->vector) { switch (frame->vector) {
case 0: // Divide Error Exception (#DE) case 0: // Divide Error Exception (#DE)
type = B_DIVIDE_ERROR; type = B_DIVIDE_ERROR;
signal = SIGFPE; signalNumber = SIGFPE;
signalCode = FPE_INTDIV;
signalAddress = frame->eip;
break; break;
case 4: // Overflow Exception (#OF) case 4: // Overflow Exception (#OF)
type = B_OVERFLOW_EXCEPTION; type = B_OVERFLOW_EXCEPTION;
signal = SIGTRAP; signalNumber = SIGFPE;
signalCode = FPE_INTOVF;
signalAddress = frame->eip;
break; break;
case 5: // BOUND Range Exceeded Exception (#BR) case 5: // BOUND Range Exceeded Exception (#BR)
type = B_BOUNDS_CHECK_EXCEPTION; type = B_BOUNDS_CHECK_EXCEPTION;
signal = SIGTRAP; signalNumber = SIGTRAP;
signalCode = SI_USER;
break; break;
case 6: // Invalid Opcode Exception (#UD) case 6: // Invalid Opcode Exception (#UD)
type = B_INVALID_OPCODE_EXCEPTION; type = B_INVALID_OPCODE_EXCEPTION;
signal = SIGILL; signalNumber = SIGILL;
signalCode = ILL_ILLOPC;
signalAddress = frame->eip;
break; break;
case 13: // General Protection Exception (#GP) case 13: // General Protection Exception (#GP)
type = B_GENERAL_PROTECTION_FAULT; type = B_GENERAL_PROTECTION_FAULT;
signal = SIGILL; signalNumber = SIGILL;
signalCode = ILL_PRVOPC; // or ILL_PRVREG
signalAddress = frame->eip;
break; break;
case 16: // x87 FPU Floating-Point Error (#MF) case 16: // x87 FPU Floating-Point Error (#MF)
type = B_FLOATING_POINT_EXCEPTION; type = B_FLOATING_POINT_EXCEPTION;
signal = SIGFPE; signalNumber = SIGFPE;
signalCode = FPE_FLTDIV;
// TODO: Determine the correct cause via the FPU status
// register!
signalAddress = frame->eip;
break; break;
case 17: // Alignment Check Exception (#AC) case 17: // Alignment Check Exception (#AC)
type = B_ALIGNMENT_EXCEPTION; type = B_ALIGNMENT_EXCEPTION;
signal = SIGTRAP; signalNumber = SIGBUS;
signalCode = BUS_ADRALN;
// TODO: Also get the address (from where?). Since we don't enable
// alignment checking this exception should never happen, though.
signalError = EFAULT;
break; break;
case 19: // SIMD Floating-Point Exception (#XF) case 19: // SIMD Floating-Point Exception (#XF)
type = B_FLOATING_POINT_EXCEPTION; type = B_FLOATING_POINT_EXCEPTION;
signal = SIGFPE; signalNumber = SIGFPE;
signalCode = FPE_FLTDIV;
// TODO: Determine the correct cause via the MXCSR register!
signalAddress = frame->eip;
break; break;
default: default:
@@ -306,12 +330,15 @@ unexpected_exception(struct iframe* frame)
// If the thread has a signal handler for the signal, we simply send it // If the thread has a signal handler for the signal, we simply send it
// the signal. Otherwise we notify the user debugger first. // the signal. Otherwise we notify the user debugger first.
if (sigaction(signal, NULL, &action) == 0 if ((sigaction(signalNumber, NULL, &action) == 0
&& action.sa_handler != SIG_DFL && action.sa_handler != SIG_DFL
&& action.sa_handler != SIG_IGN) { && action.sa_handler != SIG_IGN)
send_signal(thread->id, signal); || user_debug_exception_occurred(type, signalNumber)) {
} else if (user_debug_exception_occurred(type, signal)) Signal signal(signalNumber, signalCode, signalError,
send_signal(team_get_current_team_id(), signal); thread->team->id);
signal.SetAddress((void*)signalAddress);
send_signal_to_thread(thread, signal, 0);
}
} else { } else {
char name[32]; char name[32];
panic("Unexpected exception \"%s\" occurred in kernel mode! " panic("Unexpected exception \"%s\" occurred in kernel mode! "
@@ -500,18 +527,19 @@ hardware_interrupt(struct iframe* frame)
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
if (thread->cpu->invoke_scheduler) { if (thread->cpu->invoke_scheduler) {
GRAB_THREAD_LOCK(); SpinLocker schedulerLocker(gSchedulerLock);
scheduler_reschedule(); scheduler_reschedule();
RELEASE_THREAD_LOCK(); schedulerLocker.Unlock();
restore_interrupts(state); restore_interrupts(state);
} else if (thread->post_interrupt_callback != NULL) { } else if (thread->post_interrupt_callback != NULL) {
restore_interrupts(state);
void (*callback)(void*) = thread->post_interrupt_callback; void (*callback)(void*) = thread->post_interrupt_callback;
void* data = thread->post_interrupt_data; void* data = thread->post_interrupt_data;
thread->post_interrupt_callback = NULL; thread->post_interrupt_callback = NULL;
thread->post_interrupt_data = NULL; thread->post_interrupt_data = NULL;
restore_interrupts(state);
callback(data); callback(data);
} }
} }
+46 -28
View File
@@ -22,6 +22,18 @@
#include "syscall_table.h" #include "syscall_table.h"
#define LOCK_THREAD_TIME() \
lea THREAD_time_lock(%edi), %eax; \
pushl %eax; \
call acquire_spinlock;
/* leave spinlock address on stack for UNLOCK_THREAD_TIME() */
#define UNLOCK_THREAD_TIME() \
/* spinlock address still on stack from */ \
/* LOCK_THREAD_TIME() */ \
call release_spinlock; \
addl $4, %esp;
#define UPDATE_THREAD_USER_TIME_COMMON() \ #define UPDATE_THREAD_USER_TIME_COMMON() \
movl %eax, %ebx; /* save for later */ \ movl %eax, %ebx; /* save for later */ \
movl %edx, %ecx; \ movl %edx, %ecx; \
@@ -37,19 +49,33 @@
movl %ecx, (THREAD_last_time + 4)(%edi); \ movl %ecx, (THREAD_last_time + 4)(%edi); \
\ \
/* thread->in_kernel = true; */ \ /* thread->in_kernel = true; */ \
movb $1, THREAD_in_kernel(%edi) movb $1, THREAD_in_kernel(%edi);
#define UPDATE_THREAD_USER_TIME() \ #define UPDATE_THREAD_USER_TIME() \
LOCK_THREAD_TIME() \
call system_time; \ call system_time; \
UPDATE_THREAD_USER_TIME_COMMON() UPDATE_THREAD_USER_TIME_COMMON() \
UNLOCK_THREAD_TIME()
#define UPDATE_THREAD_USER_TIME_PUSH_TIME() \ #define UPDATE_THREAD_USER_TIME_PUSH_TIME() \
call system_time; \ call system_time; \
push %edx; \ push %edx; \
push %eax; \ push %eax; \
UPDATE_THREAD_USER_TIME_COMMON() \
LOCK_THREAD_TIME() \
\
/* recover the system time, note that */ \
/* LOCK_THREAD_TIME() leaves an address on the stack */ \
movl 4(%esp), %eax; \
movl 8(%esp), %edx; \
\
UPDATE_THREAD_USER_TIME_COMMON() \
\
UNLOCK_THREAD_TIME()
#define UPDATE_THREAD_KERNEL_TIME() \ #define UPDATE_THREAD_KERNEL_TIME() \
LOCK_THREAD_TIME() \
\
call system_time; \ call system_time; \
\ \
movl %eax, %ebx; /* save for later */ \ movl %eax, %ebx; /* save for later */ \
@@ -66,7 +92,9 @@
movl %ecx, (THREAD_last_time + 4)(%edi); \ movl %ecx, (THREAD_last_time + 4)(%edi); \
\ \
/* thread->in_kernel = false; */ \ /* thread->in_kernel = false; */ \
movb $0, THREAD_in_kernel(%edi) movb $0, THREAD_in_kernel(%edi); \
\
UNLOCK_THREAD_TIME() \
#define PUSH_IFRAME_BOTTOM(iframeType) \ #define PUSH_IFRAME_BOTTOM(iframeType) \
pusha; \ pusha; \
@@ -798,32 +826,22 @@ FUNCTION(x86_sysenter):
FUNCTION_END(x86_sysenter) FUNCTION_END(x86_sysenter)
/*! Is copied to the signal stack call to restore the original frame when /*! \fn void x86_return_to_userland(iframe* frame)
the signal handler exits. \brief Returns to the userland environment given by \a frame.
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):
Before returning to userland all potentially necessary kernel exit work is
done.
/*! void i386_restore_frame_from_syscall(struct iframe iframe); \a frame must point to a location somewhere on the caller's stack (e.g. a
Pops the regs of the iframe from the stack to make it current and then local variable).
return to userland. The function must be called with interrupts disabled.
Interrupts are disabled.
\param frame The iframe defining the userland environment.
*/ */
FUNCTION(i386_restore_frame_from_syscall): FUNCTION(x86_return_to_userland):
lea 4(%esp), %ebp // iframe to %ebp // get the iframe* parameter
movl 4(%esp), %ebp
movl %ebp, %esp
// check, if any kernel exit work has to be done // check, if any kernel exit work has to be done
movl %dr3, %edi movl %dr3, %edi
@@ -835,7 +853,7 @@ FUNCTION(i386_restore_frame_from_syscall):
// update the thread's kernel time and return // update the thread's kernel time and return
UPDATE_THREAD_KERNEL_TIME() UPDATE_THREAD_KERNEL_TIME()
POP_IFRAME_AND_RETURN() POP_IFRAME_AND_RETURN()
FUNCTION_END(i386_restore_frame_from_syscall) FUNCTION_END(x86_return_to_userland)
/* status_t x86_vm86_enter(struct vm86_iframe *frame) */ /* status_t x86_vm86_enter(struct vm86_iframe *frame) */
+207 -219
View File
@@ -22,11 +22,13 @@
#include <thread.h> #include <thread.h>
#include <tls.h> #include <tls.h>
#include <tracing.h> #include <tracing.h>
#include <util/AutoLock.h>
#include <vm/vm_types.h> #include <vm/vm_types.h>
#include <vm/VMAddressSpace.h> #include <vm/VMAddressSpace.h>
#include "paging/X86PagingStructures.h" #include "paging/X86PagingStructures.h"
#include "paging/X86VMTranslationMap.h" #include "paging/X86VMTranslationMap.h"
#include "x86_signals.h"
#include "x86_syscalls.h" #include "x86_syscalls.h"
@@ -66,7 +68,7 @@ class RestartSyscall : public AbstractTraceEntry {
// from arch_interrupts.S // from arch_interrupts.S
extern "C" void i386_stack_init(struct farcall *interrupt_stack_offset); extern "C" void i386_stack_init(struct farcall *interrupt_stack_offset);
extern "C" void i386_restore_frame_from_syscall(struct iframe frame); extern "C" void x86_return_to_userland(iframe* frame);
// from arch_cpu.c // from arch_cpu.c
extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState); extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
@@ -135,6 +137,48 @@ get_current_iframe(void)
} }
static inline void
set_fs_register(uint32 segment)
{
asm("movl %0,%%fs" :: "r" (segment));
}
static void
set_tls_context(Thread *thread)
{
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
set_fs_register((entry << 3) | DPL_USER);
}
/*! Returns to the userland environment given by \a frame for a thread not
having been userland before.
Before returning to userland all potentially necessary kernel exit work is
done.
\param thread The current thread.
\param frame The iframe defining the userland environment. Must point to a
location somewhere on the caller's stack (e.g. a local variable).
*/
static void
initial_return_to_userland(Thread* thread, iframe* frame)
{
// disable interrupts and set up CPU specifics for this thread
disable_interrupts();
i386_set_tss_and_kstack(thread->kernel_stack_top);
set_tls_context(thread);
x86_set_syscall_stack(thread->kernel_stack_top);
// return to userland
x86_return_to_userland(frame);
}
/*! /*!
\brief Returns the current thread's topmost (i.e. most recent) \brief Returns the current thread's topmost (i.e. most recent)
userland->kernel transition iframe (usually the first one, save for userland->kernel transition iframe (usually the first one, save for
@@ -206,23 +250,6 @@ x86_next_page_directory(Thread *from, Thread *to)
} }
static inline void
set_fs_register(uint32 segment)
{
asm("movl %0,%%fs" :: "r" (segment));
}
static void
set_tls_context(Thread *thread)
{
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
set_fs_register((entry << 3) | DPL_USER);
}
void void
x86_restart_syscall(struct iframe* frame) x86_restart_syscall(struct iframe* frame)
{ {
@@ -241,20 +268,19 @@ x86_restart_syscall(struct iframe* frame)
} }
static uint32 * static uint8*
get_signal_stack(Thread *thread, struct iframe *frame, int signal) get_signal_stack(Thread* thread, struct iframe* frame, struct sigaction* action)
{ {
// use the alternate signal stack if we should and can // use the alternate signal stack if we should and can
if (thread->signal_stack_enabled if (thread->signal_stack_enabled
&& (thread->sig_action[signal - 1].sa_flags & SA_ONSTACK) != 0 && (action->sa_flags & SA_ONSTACK) != 0
&& (frame->user_esp < thread->signal_stack_base && (frame->user_esp < thread->signal_stack_base
|| frame->user_esp >= thread->signal_stack_base || frame->user_esp >= thread->signal_stack_base
+ thread->signal_stack_size)) { + thread->signal_stack_size)) {
return (uint32 *)(thread->signal_stack_base return (uint8*)(thread->signal_stack_base + thread->signal_stack_size);
+ thread->signal_stack_size);
} }
return (uint32 *)frame->user_esp; return (uint8*)frame->user_esp;
} }
@@ -277,57 +303,40 @@ arch_thread_init_thread_struct(Thread *thread)
} }
status_t /*! Prepares the given thread's kernel stack for executing its entry function.
arch_thread_init_kthread_stack(Thread *t, int (*start_func)(void),
void (*entry_func)(void), void (*exit_func)(void)) \param thread The thread.
\param stack The usable bottom of the thread's kernel stack.
\param stackTop The usable top of the thread's kernel stack.
\param function The entry function the thread shall execute.
\param data Pointer to be passed to the entry function.
*/
void
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
void (*function)(void*), const void* data)
{ {
addr_t *kstack = (addr_t *)t->kernel_stack_base; addr_t* stackTop = (addr_t*)_stackTop;
addr_t *kstack_top = (addr_t *)t->kernel_stack_top;
int i;
TRACE(("arch_thread_initialize_kthread_stack: kstack 0x%p, start_func 0x%p, entry_func 0x%p\n", TRACE(("arch_thread_init_kthread_stack: stack top %p, function %, data: "
kstack, start_func, entry_func)); "%p\n", stackTop, function, data));
// clear the kernel stack // push the function argument, a pointer to the data
#ifdef DEBUG_KERNEL_STACKS *--stackTop = (addr_t)data;
# ifdef STACK_GROWS_DOWNWARDS
memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0,
KERNEL_STACK_SIZE);
# else
memset(kstack, 0, KERNEL_STACK_SIZE);
# endif
#else
memset(kstack, 0, KERNEL_STACK_SIZE);
#endif
// set the final return address to be thread_kthread_exit // push a dummy return address for the function
kstack_top--; *--stackTop = 0;
*kstack_top = (unsigned int)exit_func;
// set the return address to be the start of the first function // push the function address -- that's the return address used after the
kstack_top--; // context switch
*kstack_top = (unsigned int)start_func; *--stackTop = (addr_t)function;
// set the return address to be the start of the entry (thread setup) // simulate pushad as done by x86_context_switch()
// function for (int i = 0; i < 8; i++)
kstack_top--; *--stackTop = 0;
*kstack_top = (unsigned int)entry_func;
// simulate pushfl
// kstack_top--;
// *kstack_top = 0x00; // interrupts still disabled after the switch
// simulate initial popad
for (i = 0; i < 8; i++) {
kstack_top--;
*kstack_top = 0;
}
// save the stack position // save the stack position
t->arch_info.current_stack.esp = kstack_top; thread->arch_info.current_stack.esp = stackTop;
t->arch_info.current_stack.ss = (addr_t *)KERNEL_DATA_SEG; thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SEG;
return B_OK;
} }
@@ -411,20 +420,19 @@ arch_thread_dump_info(void *info)
} }
/** Sets up initial thread context and enters user space /*! Sets up initial thread context and enters user space
*/ */
status_t status_t
arch_thread_enter_userspace(Thread *t, addr_t entry, void *args1, arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
void *args2) void* args2)
{ {
addr_t stackTop = t->user_stack_base + t->user_stack_size; addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
uint32 codeSize = (addr_t)x86_end_userspace_thread_exit uint32 codeSize = (addr_t)x86_end_userspace_thread_exit
- (addr_t)x86_userspace_thread_exit; - (addr_t)x86_userspace_thread_exit;
uint32 args[3]; uint32 args[3];
TRACE(("arch_thread_enter_uspace: entry 0x%lx, args %p %p, ustack_top 0x%lx\n", TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
entry, args1, args2, stackTop)); "ustack_top 0x%lx\n", entry, args1, args2, stackTop));
// copy the little stub that calls exit_thread() when the thread entry // copy the little stub that calls exit_thread() when the thread entry
// function returns, as well as the arguments of the entry function // function returns, as well as the arguments of the entry function
@@ -441,20 +449,22 @@ arch_thread_enter_userspace(Thread *t, addr_t entry, void *args1,
if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK) if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
thread_at_kernel_exit(); // prepare the user iframe
// also disables interrupts iframe frame = {};
frame.type = IFRAME_TYPE_SYSCALL;
frame.gs = USER_DATA_SEG;
// frame.fs not used -- we call set_tls_context() below
frame.es = USER_DATA_SEG;
frame.ds = USER_DATA_SEG;
frame.eip = entry;
frame.cs = USER_CODE_SEG;
frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
frame.user_esp = stackTop;
frame.user_ss = USER_DATA_SEG;
// install user breakpoints, if any // return to userland
if ((t->flags & THREAD_FLAGS_BREAKPOINTS_DEFINED) != 0) initial_return_to_userland(thread, &frame);
x86_init_user_debug_at_kernel_exit(NULL);
i386_set_tss_and_kstack(t->kernel_stack_top);
// set the CPU dependent GDT entry for TLS
set_tls_context(t);
x86_set_syscall_stack(t->kernel_stack_top);
x86_enter_userspace(entry, stackTop);
return B_OK; return B_OK;
// never gets here // never gets here
@@ -472,9 +482,35 @@ arch_on_signal_stack(Thread *thread)
} }
/*! Sets up the user iframe for invoking a signal handler.
The function fills in the remaining fields of the given \a signalFrameData,
copies it to the thread's userland stack (the one on which the signal shall
be handled), and sets up the user iframe so that when returning to userland
a wrapper function is executed that calls the user-defined signal handler.
When the signal handler returns, the wrapper function shall call the
"restore signal frame" syscall with the (possibly modified) signal frame
data.
The following fields of the \a signalFrameData structure still need to be
filled in:
- \c context.uc_stack: The stack currently used by the thread.
- \c context.uc_mcontext: The current userland state of the registers.
- \c syscall_restart_return_value: Architecture specific use. On x86 the
value of eax and edx which are overwritten by the syscall return value.
Furthermore the function needs to set \c thread->user_signal_context to the
userland pointer to the \c ucontext_t on the user stack.
\param thread The current thread.
\param action The signal action specified for the signal to be handled.
\param signalFrameData A partially initialized structure of all the data
that need to be copied to userland.
\return \c B_OK on success, another error code, if something goes wrong.
*/
status_t status_t
arch_setup_signal_frame(Thread *thread, struct sigaction *action, arch_setup_signal_frame(Thread* thread, struct sigaction* action,
int signal, int signalMask) struct signal_frame_data* signalFrameData)
{ {
struct iframe *frame = get_current_iframe(); struct iframe *frame = get_current_iframe();
if (!IFRAME_IS_USER(frame)) { if (!IFRAME_IS_USER(frame)) {
@@ -482,136 +518,94 @@ arch_setup_signal_frame(Thread *thread, struct sigaction *action,
return B_BAD_VALUE; return B_BAD_VALUE;
} }
uint32 *signalCode; // In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
uint32 *userRegs; // had the same signal number.
struct vregs regs; if ((action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0
uint32 buffer[6]; && signalFrameData->info.si_signo == SIGBUS) {
status_t status; signalFrameData->info.si_signo = SIGSEGV;
}
// start stuffing stuff on the user stack // store the register state in signalFrameData->context.uc_mcontext
uint32* userStack = get_signal_stack(thread, frame, signal); signalFrameData->context.uc_mcontext.eip = frame->eip;
signalFrameData->context.uc_mcontext.eflags = frame->flags;
signalFrameData->context.uc_mcontext.eax = frame->eax;
signalFrameData->context.uc_mcontext.ecx = frame->ecx;
signalFrameData->context.uc_mcontext.edx = frame->edx;
signalFrameData->context.uc_mcontext.ebp = frame->ebp;
signalFrameData->context.uc_mcontext.esp = frame->user_esp;
signalFrameData->context.uc_mcontext.edi = frame->edi;
signalFrameData->context.uc_mcontext.esi = frame->esi;
signalFrameData->context.uc_mcontext.ebx = frame->ebx;
i386_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
// copy syscall restart info onto the user stack // fill in signalFrameData->context.uc_stack
userStack -= (sizeof(thread->syscall_restart.parameters) + 12 + 3) / 4; signal_get_user_stack(frame->user_esp, &signalFrameData->context.uc_stack);
uint32 threadFlags = atomic_and(&thread->flags,
~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN)); // store orig_eax/orig_edx in syscall_restart_return_value
if (user_memcpy(userStack, &threadFlags, 4) < B_OK signalFrameData->syscall_restart_return_value
|| user_memcpy(userStack + 1, &frame->orig_eax, 4) < B_OK = (uint64)frame->orig_edx << 32 | frame->orig_eax;
|| user_memcpy(userStack + 2, &frame->orig_edx, 4) < B_OK)
// get the stack to use -- that's either the current one or a special signal
// stack
uint8* userStack = get_signal_stack(thread, frame, action);
// copy the signal frame data onto the stack
userStack -= sizeof(*signalFrameData);
signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
if (user_memcpy(userSignalFrameData, signalFrameData,
sizeof(*signalFrameData)) != B_OK) {
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
status = user_memcpy(userStack + 3, thread->syscall_restart.parameters, }
sizeof(thread->syscall_restart.parameters));
if (status < B_OK)
return status;
// store the saved regs onto the user stack // prepare the user stack frame for a function call to the signal handler
regs.eip = frame->eip; // wrapper function
regs.eflags = frame->flags; uint32 stackFrame[2] = {
regs.eax = frame->eax; frame->eip, // return address
regs.ecx = frame->ecx; (addr_t)userSignalFrameData, // parameter: pointer to signal frame data
regs.edx = frame->edx; };
regs.ebp = frame->ebp;
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->ebx;
i386_fnsave((void *)(&regs.xregs));
userStack -= (sizeof(struct vregs) + 3) / 4; userStack -= sizeof(stackFrame);
userRegs = userStack; if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
status = user_memcpy(userRegs, &regs, sizeof(regs)); return B_BAD_ADDRESS;
if (status < B_OK)
return status;
// now store a code snippet on the stack // Update Thread::user_signal_context, now that everything seems to have
userStack -= ((uint32)i386_end_return_from_signal + 3 // gone fine.
- (uint32)i386_return_from_signal) / 4; thread->user_signal_context = &userSignalFrameData->context;
signalCode = userStack;
status = user_memcpy(signalCode, (const void *)&i386_return_from_signal,
((uint32)i386_end_return_from_signal
- (uint32)i386_return_from_signal));
if (status < B_OK)
return status;
// now set up the final part // Adjust the iframe's esp and eip, so that the thread will continue with
buffer[0] = (uint32)signalCode; // return address when sa_handler done // the prepared stack, executing the signal handler wrapper function.
buffer[1] = signal; // arguments to sa_handler frame->user_esp = (addr_t)userStack;
buffer[2] = (uint32)action->sa_userdata; frame->eip = x86_get_user_signal_handler_wrapper(
buffer[3] = (uint32)userRegs; (action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0);
buffer[4] = signalMask; // Old signal mask to restore
buffer[5] = (uint32)userRegs; // Int frame + extra regs to restore
userStack -= sizeof(buffer) / 4;
status = user_memcpy(userStack, buffer, sizeof(buffer));
if (status < B_OK)
return status;
frame->user_esp = (uint32)userStack;
frame->eip = (uint32)action->sa_handler;
return B_OK; return B_OK;
} }
int64 int64
arch_restore_signal_frame(void) arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
{ {
Thread *thread = thread_get_current_thread(); struct iframe* frame = get_current_iframe();
struct iframe *frame = get_current_iframe();
int32 signalMask;
uint32 *userStack;
struct vregs* regsPointer;
struct vregs regs;
TRACE(("### arch_restore_signal_frame: entry\n")); TRACE(("### arch_restore_signal_frame: entry\n"));
userStack = (uint32 *)frame->user_esp; frame->orig_eax = (uint32)signalFrameData->syscall_restart_return_value;
if (user_memcpy(&signalMask, &userStack[0], 4) < B_OK frame->orig_edx
|| user_memcpy(&regsPointer, &userStack[1], 4) < B_OK = (uint32)(signalFrameData->syscall_restart_return_value >> 32);
|| user_memcpy(&regs, regsPointer, sizeof(vregs)) < B_OK) {
return B_BAD_ADDRESS;
}
uint32* syscallRestartInfo frame->eip = signalFrameData->context.uc_mcontext.eip;
= (uint32*)regsPointer + (sizeof(struct vregs) + 3) / 4; frame->flags = (frame->flags & ~(uint32)X86_EFLAGS_USER_FLAGS)
uint32 threadFlags; | (signalFrameData->context.uc_mcontext.eflags & X86_EFLAGS_USER_FLAGS);
if (user_memcpy(&threadFlags, syscallRestartInfo, 4) < B_OK frame->eax = signalFrameData->context.uc_mcontext.eax;
|| user_memcpy(&frame->orig_eax, syscallRestartInfo + 1, 4) < B_OK frame->ecx = signalFrameData->context.uc_mcontext.ecx;
|| user_memcpy(&frame->orig_edx, syscallRestartInfo + 2, 4) < B_OK frame->edx = signalFrameData->context.uc_mcontext.edx;
|| user_memcpy(thread->syscall_restart.parameters, frame->ebp = signalFrameData->context.uc_mcontext.ebp;
syscallRestartInfo + 3, frame->user_esp = signalFrameData->context.uc_mcontext.esp;
sizeof(thread->syscall_restart.parameters)) < B_OK) { frame->edi = signalFrameData->context.uc_mcontext.edi;
return B_BAD_ADDRESS; frame->esi = signalFrameData->context.uc_mcontext.esi;
} frame->ebx = signalFrameData->context.uc_mcontext.ebx;
// set restart/64bit return value flags from previous syscall i386_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
atomic_and(&thread->flags,
~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
atomic_or(&thread->flags, threadFlags
& (THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
// TODO: Verify that just restoring the old signal mask is right! Bash for
// instance changes the procmask in a signal handler. Those changes are
// lost the way we do it.
atomic_set(&thread->sig_block_mask, signalMask);
update_current_thread_signals_flag();
frame->eip = regs.eip;
frame->flags = regs.eflags;
frame->eax = regs.eax;
frame->ecx = regs.ecx;
frame->edx = regs.edx;
frame->ebp = regs.ebp;
frame->esp = regs.esp;
frame->user_esp = regs._reserved_1;
frame->edi = regs._reserved_2[0];
frame->esi = regs._reserved_2[1];
frame->ebx = regs._reserved_2[2];
i386_frstor((void *)(&regs.xregs));
TRACE(("### arch_restore_signal_frame: exit\n")); TRACE(("### arch_restore_signal_frame: exit\n"));
@@ -637,27 +631,21 @@ arch_store_fork_frame(struct arch_fork_arg *arg)
} }
/** Restores the frame from a forked team as specified by the provided /*! Restores the frame from a forked team as specified by the provided
* arch_fork_arg structure. arch_fork_arg structure.
* Needs to be called from within the child team, ie. instead of Needs to be called from within the child team, i.e. instead of
* arch_thread_enter_uspace() as thread "starter". arch_thread_enter_userspace() as thread "starter".
* This function does not return to the caller, but will enter userland This function does not return to the caller, but will enter userland
* in the child team at the same position where the parent team left of. in the child team at the same position where the parent team left of.
*/
\param arg The architecture specific fork arguments including the
environment to restore. Must point to a location somewhere on the
caller's stack.
*/
void void
arch_restore_fork_frame(struct arch_fork_arg *arg) arch_restore_fork_frame(struct arch_fork_arg* arg)
{ {
Thread *thread = thread_get_current_thread(); initial_return_to_userland(thread_get_current_thread(), &arg->iframe);
disable_interrupts();
i386_set_tss_and_kstack(thread->kernel_stack_top);
// set the CPU dependent GDT entry for TLS (set the current %fs register)
set_tls_context(thread);
i386_restore_frame_from_syscall(arg->iframe);
} }
@@ -781,18 +781,16 @@ x86_init_user_debug_at_kernel_exit(struct iframe *frame)
// disable kernel breakpoints // disable kernel breakpoints
disable_breakpoints(); disable_breakpoints();
GRAB_THREAD_LOCK(); // install the user breakpoints
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info;
// install the user breakpoints
install_breakpoints(teamInfo); install_breakpoints(teamInfo);
atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED); atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_INSTALLED);
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
RELEASE_THREAD_LOCK();
} }
@@ -815,20 +813,19 @@ x86_exit_user_debug_at_kernel_entry()
if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED)) if (!(thread->flags & THREAD_FLAGS_BREAKPOINTS_INSTALLED))
return; return;
GRAB_THREAD_LOCK();
// disable user breakpoints // disable user breakpoints
disable_breakpoints(); disable_breakpoints();
// install kernel breakpoints // install kernel breakpoints
Team* kernelTeam = team_get_kernel_team(); Team* kernelTeam = team_get_kernel_team();
GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
install_breakpoints(kernelTeam->debug_info.arch_info); install_breakpoints(kernelTeam->debug_info.arch_info);
RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED); atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_INSTALLED);
RELEASE_THREAD_LOCK(); RELEASE_TEAM_DEBUG_INFO_LOCK(kernelTeam->debug_info);
} }
@@ -927,7 +924,8 @@ x86_handle_debug_exception(struct iframe *frame)
// We need to ignore the exception now and send a single-step // We need to ignore the exception now and send a single-step
// notification later, when the thread wants to return from the // notification later, when the thread wants to return from the
// kernel. // kernel.
InterruptsSpinLocker threadLocker(gThreadSpinlock); InterruptsSpinLocker threadDebugInfoLocker(
thread->debug_info.lock);
// Check whether the team is still being debugged and set // Check whether the team is still being debugged and set
// the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and // the B_THREAD_DEBUG_NOTIFY_SINGLE_STEP and
-21
View File
@@ -157,27 +157,6 @@ FUNCTION_END(x86_userspace_thread_exit)
SYMBOL(x86_end_userspace_thread_exit): SYMBOL(x86_end_userspace_thread_exit):
/* void x86_enter_userspace(addr_t entry, addr_t stackTop); */
FUNCTION(x86_enter_userspace):
movl 4(%esp), %eax // get entry point
movl 8(%esp), %ebx // get user stack
movl $USER_DATA_SEG, %ecx
movw %cx, %ds
movw %cx, %es
//movw $0x33 + cpu_num, %fs -> fs points to the TLS storage (CPU dependent segment)
movw %cx, %gs
xorl %ebp, %ebp // this is the last stack frame - we don't need one on return
// (%ebp marks the beginning of this stack frame)
pushl %ecx // user data segment
pushl %ebx // user stack
pushl $(1 << 9) | 2 // user flags
pushl $USER_CODE_SEG // user code segment
pushl %eax // user IP
iret
FUNCTION_END(x86_enter_userspace)
null_idt_descr: null_idt_descr:
.word 0 .word 0
.word 0,0 .word 0,0
@@ -13,6 +13,7 @@
#include <arch_cpu.h> #include <arch_cpu.h>
#include <cpu.h> #include <cpu.h>
#include <ksignal.h>
#include <ksyscalls.h> #include <ksyscalls.h>
#include <thread_types.h> #include <thread_types.h>
@@ -34,6 +35,7 @@ dummy()
DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler_stack_pointer); DEFINE_OFFSET_MACRO(CPU_ENT, cpu_ent, fault_handler_stack_pointer);
// struct Thread // struct Thread
DEFINE_OFFSET_MACRO(THREAD, Thread, time_lock);
DEFINE_OFFSET_MACRO(THREAD, Thread, kernel_time); DEFINE_OFFSET_MACRO(THREAD, Thread, kernel_time);
DEFINE_OFFSET_MACRO(THREAD, Thread, user_time); DEFINE_OFFSET_MACRO(THREAD, Thread, user_time);
DEFINE_OFFSET_MACRO(THREAD, Thread, last_time); DEFINE_OFFSET_MACRO(THREAD, Thread, last_time);
@@ -43,6 +45,7 @@ dummy()
DEFINE_OFFSET_MACRO(THREAD, Thread, fault_handler); DEFINE_OFFSET_MACRO(THREAD, Thread, fault_handler);
// struct iframe // struct iframe
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
DEFINE_OFFSET_MACRO(IFRAME, iframe, cs); DEFINE_OFFSET_MACRO(IFRAME, iframe, cs);
DEFINE_OFFSET_MACRO(IFRAME, iframe, eax); DEFINE_OFFSET_MACRO(IFRAME, iframe, eax);
DEFINE_OFFSET_MACRO(IFRAME, iframe, edx); DEFINE_OFFSET_MACRO(IFRAME, iframe, edx);
@@ -66,4 +69,20 @@ dummy()
memcpy); memcpy);
DEFINE_OFFSET_MACRO(X86_OPTIMIZED_FUNCTIONS, x86_optimized_functions, DEFINE_OFFSET_MACRO(X86_OPTIMIZED_FUNCTIONS, x86_optimized_functions,
memset); 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);
} }
+125
View File
@@ -0,0 +1,125 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "x86_signals.h"
#include <string.h>
#include <KernelExport.h>
#include <commpage.h>
#include <cpu.h>
#include <elf.h>
#include <smp.h>
#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)
{
// Note: This function is copied to the commpage. Hence it needs to be
// position independent. We don't build this source file with the respective
// flags, but the code the compiler generates for this function is position
// independent anyway. It simply doesn't contain constructs that could
// result in position dependent code. The potentially problematic jumps
// needed due to the "if" statement are all harmless relative jumps.
if (frameData->siginfo_handler) {
// SA_SIGINFO style handler function -- we additionally pass the user
// data pointer
void (*handler)(int, siginfo_t*, void*, void*)
= (void (*)(int, siginfo_t*, void*, void*))frameData->handler;
handler(frameData->info.si_signo, &frameData->info,
&frameData->context, frameData->user_data);
} else {
// 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,
&frameData->context.uc_mcontext);
}
#define TO_STRING_LITERAL_HELPER(number) #number
#define TO_STRING_LITERAL(number) TO_STRING_LITERAL_HELPER(number)
// call the restore_signal_frame() syscall -- does not return (here)
asm volatile(
// push frameData -- the parameter to restore_signal_frame()
"pushl %0;"
// push a dummy return value
"pushl $0;"
// syscall number to eax
"movl $" TO_STRING_LITERAL(SYSCALL_RESTORE_SIGNAL_FRAME) ", %%eax;"
// syscall
"int $99;"
:: "r"(frameData)
);
#undef TO_STRING_LITERAL_HELPER
#undef TO_STRING_LITERAL
}
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(functionName, &symbolInfo)
!= B_OK) {
panic("x86_initialize_commpage_signal_handler(): Failed to find "
"signal frame function \"%s\"!", functionName);
}
ASSERT(expectedAddress == symbolInfo.address);
// fill in the commpage table entry
fill_commpage_entry(commpageIndex, (void*)symbolInfo.address,
symbolInfo.size);
// add symbol to the commpage image
image_id image = get_commpage_image();
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(bool beosHandler)
{
int32 index = beosHandler
? COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS
: COMMPAGE_ENTRY_X86_SIGNAL_HANDLER;
return ((addr_t*)USER_COMMPAGE_ADDR)[index];
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_ARCH_X86_SIGNALS_H
#define _KERNEL_ARCH_X86_SIGNALS_H
#include <SupportDefs.h>
void x86_initialize_commpage_signal_handler();
addr_t x86_get_user_signal_handler_wrapper(bool beosHandler);
#endif // _KERNEL_ARCH_X86_SIGNALS_H
@@ -0,0 +1,71 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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)
+1 -3
View File
@@ -75,7 +75,7 @@ init_amd_syscall_registers(void* dummy, int cpuNum)
// #pragma mark - // #pragma mark -
status_t void
x86_initialize_commpage_syscall(void) x86_initialize_commpage_syscall(void)
{ {
void* syscallCode = (void *)&_user_syscall_int; void* syscallCode = (void *)&_user_syscall_int;
@@ -113,6 +113,4 @@ x86_initialize_commpage_syscall(void)
elf_add_memory_image_symbol(image, "commpage_syscall", elf_add_memory_image_symbol(image, "commpage_syscall",
((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SYSCALL], len, ((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_SYSCALL], len,
B_SYMBOL_TYPE_TEXT); B_SYMBOL_TYPE_TEXT);
return B_OK;
} }
+1 -1
View File
@@ -12,7 +12,7 @@
extern void (*gX86SetSyscallStack)(addr_t stackTop); extern void (*gX86SetSyscallStack)(addr_t stackTop);
status_t x86_initialize_commpage_syscall(); void x86_initialize_commpage_syscall();
static inline void static inline void
+14 -13
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2007-2008, Ingo Weinhold, bonefish@cs.tu-berlin.de. * Copyright 2007-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -134,14 +134,15 @@ ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
conditionLocker.Unlock(); conditionLocker.Unlock();
SpinLocker threadLocker(gThreadSpinlock); SpinLocker schedulerLocker(gSchedulerLock);
status_t error; status_t error;
if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0)
error = thread_block_with_timeout_locked(flags, timeout); error = thread_block_with_timeout_locked(flags, timeout);
else else
error = thread_block_locked(thread_get_current_thread()); error = thread_block_locked(thread_get_current_thread());
threadLocker.Unlock();
schedulerLocker.Unlock();
conditionLocker.Lock(); conditionLocker.Lock();
@@ -220,12 +221,12 @@ ConditionVariable::Publish(const void* object, const char* objectType)
void void
ConditionVariable::Unpublish(bool threadsLocked) ConditionVariable::Unpublish(bool schedulerLocked)
{ {
ASSERT(fObject != NULL); ASSERT(fObject != NULL);
InterruptsLocker _; InterruptsLocker _;
SpinLocker threadLocker(threadsLocked ? NULL : &gThreadSpinlock); SpinLocker schedulerLocker(schedulerLocked ? NULL : &gSchedulerLock);
SpinLocker locker(sConditionVariablesLock); SpinLocker locker(sConditionVariablesLock);
#if KDEBUG #if KDEBUG
@@ -262,7 +263,7 @@ ConditionVariable::Wait(uint32 flags, bigtime_t timeout)
/*static*/ void /*static*/ void
ConditionVariable::NotifyOne(const void* object, bool threadsLocked, ConditionVariable::NotifyOne(const void* object, bool schedulerLocked,
status_t result) status_t result)
{ {
InterruptsSpinLocker locker(sConditionVariablesLock); InterruptsSpinLocker locker(sConditionVariablesLock);
@@ -271,13 +272,13 @@ ConditionVariable::NotifyOne(const void* object, bool threadsLocked,
if (variable == NULL) if (variable == NULL)
return; return;
variable->NotifyOne(threadsLocked, result); variable->NotifyOne(schedulerLocked, result);
} }
/*static*/ void /*static*/ void
ConditionVariable::NotifyAll(const void* object, ConditionVariable::NotifyAll(const void* object, bool schedulerLocked,
bool threadsLocked, status_t result) status_t result)
{ {
InterruptsSpinLocker locker(sConditionVariablesLock); InterruptsSpinLocker locker(sConditionVariablesLock);
ConditionVariable* variable = sConditionVariableHash.Lookup(object); ConditionVariable* variable = sConditionVariableHash.Lookup(object);
@@ -285,7 +286,7 @@ ConditionVariable::NotifyAll(const void* object,
if (variable == NULL) if (variable == NULL)
return; return;
variable->NotifyAll(threadsLocked, result); variable->NotifyAll(schedulerLocked, result);
} }
@@ -321,10 +322,10 @@ ConditionVariable::Dump() const
void void
ConditionVariable::_Notify(bool all, bool threadsLocked, status_t result) ConditionVariable::_Notify(bool all, bool schedulerLocked, status_t result)
{ {
InterruptsLocker _; InterruptsLocker _;
SpinLocker threadLocker(threadsLocked ? NULL : &gThreadSpinlock); SpinLocker schedulerLocker(schedulerLocked ? NULL : &gSchedulerLock);
SpinLocker locker(sConditionVariablesLock); SpinLocker locker(sConditionVariablesLock);
if (!fEntries.IsEmpty()) { if (!fEntries.IsEmpty()) {
@@ -339,7 +340,7 @@ ConditionVariable::_Notify(bool all, bool threadsLocked, status_t result)
/*! Called with interrupts disabled and the condition variable spinlock and /*! Called with interrupts disabled and the condition variable spinlock and
thread lock held. scheduler lock held.
*/ */
void void
ConditionVariable::_NotifyLocked(bool all, status_t result) ConditionVariable::_NotifyLocked(bool all, status_t result)
+8 -15
View File
@@ -10,12 +10,14 @@
#include <cpu.h> #include <cpu.h>
#include <thread_types.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <boot/kernel_args.h>
#include <string.h> #include <string.h>
#include <boot/kernel_args.h>
#include <thread_types.h>
#include <util/AutoLock.h>
/* global per-cpu structure */ /* global per-cpu structure */
cpu_ent gCPU[MAX_BOOT_CPUS]; cpu_ent gCPU[MAX_BOOT_CPUS];
@@ -66,24 +68,15 @@ cpu_preboot_init_percpu(kernel_args *args, int curr_cpu)
bigtime_t bigtime_t
cpu_get_active_time(int32 cpu) cpu_get_active_time(int32 cpu)
{ {
bigtime_t activeTime;
cpu_status state;
if (cpu < 0 || cpu > smp_get_num_cpus()) if (cpu < 0 || cpu > smp_get_num_cpus())
return 0; return 0;
// We need to grab the thread lock here, because the thread activity // We need to grab the scheduler lock here, because the thread activity
// time is not maintained atomically (because there is no need to) // time is not maintained atomically (because there is no need to).
state = disable_interrupts(); InterruptsSpinLocker schedulerLocker(gSchedulerLock);
GRAB_THREAD_LOCK();
activeTime = gCPU[cpu].active_time; return gCPU[cpu].active_time;
RELEASE_THREAD_LOCK();
restore_interrupts(state);
return activeTime;
} }
+3 -3
View File
@@ -12,11 +12,11 @@
#include <vm/vm.h> #include <vm/vm.h>
#define INITIAL_HEAP_SIZE B_PAGE_SIZE #define INITIAL_DEBUG_HEAP_SIZE B_PAGE_SIZE
static char sInitialHeap[INITIAL_HEAP_SIZE] __attribute__ ((aligned (8))); static char sInitialHeap[INITIAL_DEBUG_HEAP_SIZE] __attribute__ ((aligned (8)));
static void* sHeapBase = sInitialHeap; static void* sHeapBase = sInitialHeap;
static size_t sHeapSize = INITIAL_HEAP_SIZE; static size_t sHeapSize = INITIAL_DEBUG_HEAP_SIZE;
const kdebug_alloc_t kdebug_alloc = {}; const kdebug_alloc_t kdebug_alloc = {};
+109 -57
View File
@@ -108,10 +108,6 @@ private:
inline void _MaybeNotifyProfilerThreadLocked(); inline void _MaybeNotifyProfilerThreadLocked();
inline void _MaybeNotifyProfilerThread(); inline void _MaybeNotifyProfilerThread();
static bool _InitialTeamIterator(Team* team,
void* cookie);
static bool _InitialThreadIterator(Thread* thread,
void* cookie);
static bool _InitialImageIterator(struct image* image, static bool _InitialImageIterator(struct image* image,
void* cookie); void* cookie);
@@ -189,6 +185,8 @@ private:
size_t fBufferStart; size_t fBufferStart;
size_t fBufferSize; size_t fBufferSize;
uint64 fDroppedEvents; uint64 fDroppedEvents;
int64 fLastTeamAddedSerialNumber;
int64 fLastThreadAddedSerialNumber;
bool fTeamNotificationsRequested; bool fTeamNotificationsRequested;
bool fTeamNotificationsEnabled; bool fTeamNotificationsEnabled;
bool fThreadNotificationsRequested; bool fThreadNotificationsRequested;
@@ -203,7 +201,6 @@ private:
bool fProfilingActive; bool fProfilingActive;
bool fReentered[B_MAX_CPU_COUNT]; bool fReentered[B_MAX_CPU_COUNT];
CPUProfileData fCPUData[B_MAX_CPU_COUNT]; CPUProfileData fCPUData[B_MAX_CPU_COUNT];
Thread** fRunningThreads;
WaitObject* fWaitObjectBuffer; WaitObject* fWaitObjectBuffer;
int32 fWaitObjectCount; int32 fWaitObjectCount;
WaitObjectList fUsedWaitObjects; WaitObjectList fUsedWaitObjects;
@@ -212,6 +209,9 @@ private:
}; };
/*! Notifies the profiler thread when the profiling buffer is full enough.
The caller must hold the scheduler lock and fLock.
*/
inline void inline void
SystemProfiler::_MaybeNotifyProfilerThreadLocked() SystemProfiler::_MaybeNotifyProfilerThreadLocked()
{ {
@@ -219,7 +219,9 @@ SystemProfiler::_MaybeNotifyProfilerThreadLocked()
if (fWaitingProfilerThread != NULL && fBufferSize > fBufferCapacity / 2) { if (fWaitingProfilerThread != NULL && fBufferSize > fBufferCapacity / 2) {
int cpu = smp_get_current_cpu(); int cpu = smp_get_current_cpu();
fReentered[cpu] = true; fReentered[cpu] = true;
thread_unblock_locked(fWaitingProfilerThread, B_OK); thread_unblock_locked(fWaitingProfilerThread, B_OK);
fWaitingProfilerThread = NULL; fWaitingProfilerThread = NULL;
fReentered[cpu] = false; fReentered[cpu] = false;
} }
@@ -232,7 +234,7 @@ SystemProfiler::_MaybeNotifyProfilerThread()
if (fWaitingProfilerThread == NULL) if (fWaitingProfilerThread == NULL)
return; return;
InterruptsSpinLocker threadsLocker(gThreadSpinlock); InterruptsSpinLocker schedulerLocker(gSchedulerLock);
SpinLocker locker(fLock); SpinLocker locker(fLock);
_MaybeNotifyProfilerThreadLocked(); _MaybeNotifyProfilerThreadLocked();
@@ -255,6 +257,8 @@ SystemProfiler::SystemProfiler(team_id team, const area_info& userAreaInfo,
fBufferStart(0), fBufferStart(0),
fBufferSize(0), fBufferSize(0),
fDroppedEvents(0), fDroppedEvents(0),
fLastTeamAddedSerialNumber(0),
fLastThreadAddedSerialNumber(0),
fTeamNotificationsRequested(false), fTeamNotificationsRequested(false),
fTeamNotificationsEnabled(false), fTeamNotificationsEnabled(false),
fThreadNotificationsRequested(false), fThreadNotificationsRequested(false),
@@ -294,6 +298,7 @@ SystemProfiler::~SystemProfiler()
// inactive. // inactive.
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
if (fWaitingProfilerThread != NULL) { if (fWaitingProfilerThread != NULL) {
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
thread_unblock_locked(fWaitingProfilerThread, B_OK); thread_unblock_locked(fWaitingProfilerThread, B_OK);
fWaitingProfilerThread = NULL; fWaitingProfilerThread = NULL;
} }
@@ -302,7 +307,7 @@ SystemProfiler::~SystemProfiler()
// stop scheduler listening // stop scheduler listening
if (fSchedulerNotificationsRequested) { if (fSchedulerNotificationsRequested) {
InterruptsSpinLocker threadsLocker(gThreadSpinlock); InterruptsSpinLocker schedulerLocker(gSchedulerLock);
scheduler_remove_listener(this); scheduler_remove_listener(this);
} }
@@ -446,11 +451,24 @@ SystemProfiler::Init()
// teams // teams
if ((fFlags & B_SYSTEM_PROFILER_TEAM_EVENTS) != 0) { if ((fFlags & B_SYSTEM_PROFILER_TEAM_EVENTS) != 0) {
InterruptsSpinLocker teamsLocker(gTeamSpinlock); InterruptsSpinLocker locker(fLock);
if (team_iterate_through_teams(&_InitialTeamIterator, this) != NULL)
TeamListIterator iterator;
while (Team* team = iterator.Next()) {
locker.Unlock();
bool added = _TeamAdded(team);
// release the reference returned by the iterator
team->ReleaseReference();
if (!added)
return B_BUFFER_OVERFLOW; return B_BUFFER_OVERFLOW;
locker.Lock();
}
fTeamNotificationsEnabled = true; fTeamNotificationsEnabled = true;
teamsLocker.Unlock();
} }
// images // images
@@ -460,21 +478,29 @@ SystemProfiler::Init()
} }
// threads // threads
Thread* runningThreads[B_MAX_CPU_COUNT]; if ((fFlags & B_SYSTEM_PROFILER_THREAD_EVENTS) != 0) {
memset(runningThreads, 0, sizeof(runningThreads)); InterruptsSpinLocker locker(fLock);
fRunningThreads = runningThreads;
InterruptsSpinLocker threadsLocker(gThreadSpinlock); ThreadListIterator iterator;
if ((fFlags & B_SYSTEM_PROFILER_THREAD_EVENTS) != 0 while (Thread* thread = iterator.Next()) {
|| (fFlags & B_SYSTEM_PROFILER_SCHEDULING_EVENTS) != 0) { locker.Unlock();
if (thread_iterate_through_threads(&_InitialThreadIterator, this)
!= NULL) { bool added = _ThreadAdded(thread);
// release the reference returned by the iterator
thread->ReleaseReference();
if (!added)
return B_BUFFER_OVERFLOW; return B_BUFFER_OVERFLOW;
locker.Lock();
} }
fThreadNotificationsEnabled
= (fFlags & B_SYSTEM_PROFILER_THREAD_EVENTS) != 0; fThreadNotificationsEnabled = true;
} }
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
fProfilingActive = true; fProfilingActive = true;
// start scheduler and wait object listening // start scheduler and wait object listening
@@ -490,12 +516,13 @@ SystemProfiler::Init()
// fake schedule events for the initially running threads // fake schedule events for the initially running threads
int32 cpuCount = smp_get_num_cpus(); int32 cpuCount = smp_get_num_cpus();
for (int32 i = 0; i < cpuCount; i++) { for (int32 i = 0; i < cpuCount; i++) {
if (runningThreads[i] != NULL) Thread* thread = gCPU[i].running_thread;
ThreadScheduled(runningThreads[i], runningThreads[i]); if (thread != NULL)
ThreadScheduled(thread, thread);
} }
} }
threadsLocker.Unlock(); schedulerLocker.Unlock();
// I/O scheduling // I/O scheduling
if ((fFlags & B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS) != 0) { if ((fFlags & B_SYSTEM_PROFILER_IO_SCHEDULING_EVENTS) != 0) {
@@ -545,9 +572,12 @@ SystemProfiler::NextBuffer(size_t bytesRead, uint64* _droppedEvents)
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();
fWaitingProfilerThread = thread; fWaitingProfilerThread = thread;
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
thread_prepare_to_block(thread, B_CAN_INTERRUPT, thread_prepare_to_block(thread, B_CAN_INTERRUPT,
THREAD_BLOCK_TYPE_OTHER, "system profiler buffer"); THREAD_BLOCK_TYPE_OTHER, "system profiler buffer");
schedulerLocker.Unlock();
locker.Unlock(); locker.Unlock();
status_t error = thread_block_with_timeout(B_RELATIVE_TIMEOUT, 1000000); status_t error = thread_block_with_timeout(B_RELATIVE_TIMEOUT, 1000000);
@@ -587,15 +617,13 @@ SystemProfiler::EventOccurred(NotificationService& service,
return; return;
if (strcmp(service.Name(), "teams") == 0) { if (strcmp(service.Name(), "teams") == 0) {
if (!fTeamNotificationsEnabled)
return;
Team* team = (Team*)event->GetPointer("teamStruct", NULL); Team* team = (Team*)event->GetPointer("teamStruct", NULL);
if (team == NULL) if (team == NULL)
return; return;
switch (eventCode) { switch (eventCode) {
case TEAM_ADDED: case TEAM_ADDED:
if (fTeamNotificationsEnabled)
_TeamAdded(team); _TeamAdded(team);
break; break;
@@ -613,28 +641,39 @@ SystemProfiler::EventOccurred(NotificationService& service,
return; return;
} }
// When we're still doing the initial team list scan, we are
// also interested in removals that happened to teams we have
// already seen.
if (fTeamNotificationsEnabled
|| team->serial_number <= fLastTeamAddedSerialNumber) {
_TeamRemoved(team); _TeamRemoved(team);
}
break; break;
case TEAM_EXEC: case TEAM_EXEC:
if (fTeamNotificationsEnabled)
_TeamExec(team); _TeamExec(team);
break; break;
} }
} else if (strcmp(service.Name(), "threads") == 0) { } else if (strcmp(service.Name(), "threads") == 0) {
if (!fThreadNotificationsEnabled)
return;
Thread* thread = (Thread*)event->GetPointer("threadStruct", NULL); Thread* thread = (Thread*)event->GetPointer("threadStruct", NULL);
if (thread == NULL) if (thread == NULL)
return; return;
switch (eventCode) { switch (eventCode) {
case THREAD_ADDED: case THREAD_ADDED:
if (fThreadNotificationsEnabled)
_ThreadAdded(thread); _ThreadAdded(thread);
break; break;
case THREAD_REMOVED: case THREAD_REMOVED:
// When we're still doing the initial thread list scan, we are
// also interested in removals that happened to threads we have
// already seen.
if (fThreadNotificationsEnabled
|| thread->serial_number <= fLastThreadAddedSerialNumber) {
_ThreadRemoved(thread); _ThreadRemoved(thread);
}
break; break;
} }
} else if (strcmp(service.Name(), "images") == 0) { } else if (strcmp(service.Name(), "images") == 0) {
@@ -820,11 +859,22 @@ SystemProfiler::RWLockInitialized(rw_lock* lock)
bool bool
SystemProfiler::_TeamAdded(Team* team) SystemProfiler::_TeamAdded(Team* team)
{ {
size_t nameLen = strlen(team->name); TeamLocker teamLocker(team);
size_t argsLen = strlen(team->args);
size_t nameLen = strlen(team->Name());
size_t argsLen = strlen(team->Args());
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
// During the initial scan check whether the team is already gone again.
// Later this cannot happen, since the team creator notifies us before
// actually starting the team.
if (!fTeamNotificationsEnabled && team->state >= TEAM_STATE_DEATH)
return true;
if (team->serial_number > fLastTeamAddedSerialNumber)
fLastTeamAddedSerialNumber = team->serial_number;
system_profiler_team_added* event = (system_profiler_team_added*) system_profiler_team_added* event = (system_profiler_team_added*)
_AllocateBuffer( _AllocateBuffer(
sizeof(system_profiler_team_added) + nameLen + 1 + argsLen, sizeof(system_profiler_team_added) + nameLen + 1 + argsLen,
@@ -833,9 +883,9 @@ SystemProfiler::_TeamAdded(Team* team)
return false; return false;
event->team = team->id; event->team = team->id;
strcpy(event->name, team->name); strcpy(event->name, team->Name());
event->args_offset = nameLen + 1; event->args_offset = nameLen + 1;
strcpy(event->name + nameLen + 1, team->args); strcpy(event->name + nameLen + 1, team->Args());
fHeader->size = fBufferSize; fHeader->size = fBufferSize;
@@ -846,6 +896,12 @@ SystemProfiler::_TeamAdded(Team* team)
bool bool
SystemProfiler::_TeamRemoved(Team* team) SystemProfiler::_TeamRemoved(Team* team)
{ {
// TODO: It is possible that we get remove notifications for teams that
// had already been removed from the global team list when we did the
// initial scan, but were still in the process of dying. ATM it is not
// really possible to identify such a case.
TeamLocker teamLocker(team);
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
system_profiler_team_removed* event = (system_profiler_team_removed*) system_profiler_team_removed* event = (system_profiler_team_removed*)
@@ -865,7 +921,9 @@ SystemProfiler::_TeamRemoved(Team* team)
bool bool
SystemProfiler::_TeamExec(Team* team) SystemProfiler::_TeamExec(Team* team)
{ {
size_t argsLen = strlen(team->args); TeamLocker teamLocker(team);
size_t argsLen = strlen(team->Args());
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
@@ -878,7 +936,7 @@ SystemProfiler::_TeamExec(Team* team)
event->team = team->id; event->team = team->id;
strlcpy(event->thread_name, team->main_thread->name, strlcpy(event->thread_name, team->main_thread->name,
sizeof(event->thread_name)); sizeof(event->thread_name));
strcpy(event->args, team->args); strcpy(event->args, team->Args());
fHeader->size = fBufferSize; fHeader->size = fBufferSize;
@@ -889,8 +947,18 @@ SystemProfiler::_TeamExec(Team* team)
bool bool
SystemProfiler::_ThreadAdded(Thread* thread) SystemProfiler::_ThreadAdded(Thread* thread)
{ {
ThreadLocker threadLocker(thread);
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
// During the initial scan check whether the team is already gone again.
// Later this cannot happen, since the team creator notifies us before
// actually starting the thread.
if (!fThreadNotificationsEnabled && !thread->IsAlive())
return true;
if (thread->serial_number > fLastThreadAddedSerialNumber)
fLastThreadAddedSerialNumber = thread->serial_number;
system_profiler_thread_added* event = (system_profiler_thread_added*) system_profiler_thread_added* event = (system_profiler_thread_added*)
_AllocateBuffer(sizeof(system_profiler_thread_added), _AllocateBuffer(sizeof(system_profiler_thread_added),
B_SYSTEM_PROFILER_THREAD_ADDED, 0, 0); B_SYSTEM_PROFILER_THREAD_ADDED, 0, 0);
@@ -910,6 +978,12 @@ SystemProfiler::_ThreadAdded(Thread* thread)
bool bool
SystemProfiler::_ThreadRemoved(Thread* thread) SystemProfiler::_ThreadRemoved(Thread* thread)
{ {
// TODO: It is possible that we get remove notifications for threads that
// had already been removed from the global thread list when we did the
// initial scan, but were still in the process of dying. ATM it is not
// really possible to identify such a case.
ThreadLocker threadLocker(thread);
InterruptsSpinLocker locker(fLock); InterruptsSpinLocker locker(fLock);
system_profiler_thread_removed* event system_profiler_thread_removed* event
@@ -1236,28 +1310,6 @@ SystemProfiler::_WaitObjectUsed(addr_t object, uint32 type)
} }
/*static*/ bool
SystemProfiler::_InitialTeamIterator(Team* team, void* cookie)
{
SystemProfiler* self = (SystemProfiler*)cookie;
return !self->_TeamAdded(team);
}
/*static*/ bool
SystemProfiler::_InitialThreadIterator(Thread* thread, void* cookie)
{
SystemProfiler* self = (SystemProfiler*)cookie;
if ((self->fFlags & B_SYSTEM_PROFILER_SCHEDULING_EVENTS) != 0
&& thread->state == B_THREAD_RUNNING && thread->cpu != NULL) {
self->fRunningThreads[thread->cpu->cpu_num] = thread;
}
return !self->_ThreadAdded(thread);
}
/*static*/ bool /*static*/ bool
SystemProfiler::_InitialImageIterator(struct image* image, void* cookie) SystemProfiler::_InitialImageIterator(struct image* image, void* cookie)
{ {
+213 -217
View File
@@ -64,12 +64,12 @@ static status_t ensure_debugger_installed();
static void get_team_debug_info(team_debug_info &teamDebugInfo); static void get_team_debug_info(team_debug_info &teamDebugInfo);
static status_t static inline status_t
kill_interruptable_write_port(port_id port, int32 code, const void *buffer, kill_interruptable_write_port(port_id port, int32 code, const void *buffer,
size_t bufferSize) size_t bufferSize)
{ {
return write_port_etc(port, code, buffer, bufferSize, return write_port_etc(port, code, buffer, bufferSize, B_KILL_CAN_INTERRUPT,
B_KILL_CAN_INTERRUPT, 0); 0);
} }
@@ -127,7 +127,7 @@ debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
/*! Updates the thread::flags field according to what user debugger flags are /*! Updates the thread::flags field according to what user debugger flags are
set for the thread. set for the thread.
Interrupts must be disabled and the thread lock must be held. Interrupts must be disabled and the thread's debug info lock must be held.
*/ */
static void static void
update_thread_user_debug_flag(Thread* thread) update_thread_user_debug_flag(Thread* thread)
@@ -141,7 +141,7 @@ update_thread_user_debug_flag(Thread* thread)
/*! Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of the /*! Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of the
given thread. given thread.
Interrupts must be disabled and the team lock must be held. Interrupts must be disabled and the thread debug info lock must be held.
*/ */
static void static void
update_thread_breakpoints_flag(Thread* thread) update_thread_breakpoints_flag(Thread* thread)
@@ -155,15 +155,16 @@ update_thread_breakpoints_flag(Thread* thread)
} }
/*! Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of all /*! Updates the Thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of all
threads of the current team. threads of the current team.
*/ */
static void static void
update_threads_breakpoints_flag() update_threads_breakpoints_flag()
{ {
InterruptsSpinLocker _(gTeamSpinlock);
Team* team = thread_get_current_thread()->team; Team* team = thread_get_current_thread()->team;
TeamLocker teamLocker(team);
Thread* thread = team->thread_list; Thread* thread = team->thread_list;
if (arch_has_breakpoints(&team->debug_info.arch_info)) { if (arch_has_breakpoints(&team->debug_info.arch_info)) {
@@ -177,8 +178,7 @@ update_threads_breakpoints_flag()
/*! Updates the thread::flags B_TEAM_DEBUG_DEBUGGER_INSTALLED bit of the /*! Updates the thread::flags B_TEAM_DEBUG_DEBUGGER_INSTALLED bit of the
given thread. given thread, which must be the current thread.
Interrupts must be disabled and the team lock must be held.
*/ */
static void static void
update_thread_debugger_installed_flag(Thread* thread) update_thread_debugger_installed_flag(Thread* thread)
@@ -194,7 +194,7 @@ update_thread_debugger_installed_flag(Thread* thread)
/*! Updates the thread::flags THREAD_FLAGS_DEBUGGER_INSTALLED bit of all /*! Updates the thread::flags THREAD_FLAGS_DEBUGGER_INSTALLED bit of all
threads of the given team. threads of the given team.
Interrupts must be disabled and the team lock must be held. The team's lock must be held.
*/ */
static void static void
update_threads_debugger_installed_flag(Team* team) update_threads_debugger_installed_flag(Team* team)
@@ -296,6 +296,7 @@ void
init_thread_debug_info(struct thread_debug_info *info) init_thread_debug_info(struct thread_debug_info *info)
{ {
if (info) { if (info) {
B_INITIALIZE_SPINLOCK(&info->lock);
arch_clear_thread_debug_info(&info->arch_info); arch_clear_thread_debug_info(&info->arch_info);
info->flags = B_THREAD_DEBUG_DEFAULT_FLAGS; info->flags = B_THREAD_DEBUG_DEFAULT_FLAGS;
info->debug_port = -1; info->debug_port = -1;
@@ -309,7 +310,8 @@ init_thread_debug_info(struct thread_debug_info *info)
} }
/*! Invoked with thread lock being held. /*! Clears the debug info for the current thread.
Invoked with thread debug info lock being held.
*/ */
void void
clear_thread_debug_info(struct thread_debug_info *info, bool dying) clear_thread_debug_info(struct thread_debug_info *info, bool dying)
@@ -373,19 +375,18 @@ prepare_debugger_change(team_id teamID, ConditionVariable& condition,
while (true) { while (true) {
// get the team // get the team
InterruptsSpinLocker teamLocker(gTeamSpinlock); team = Team::GetAndLock(teamID);
if (team == NULL)
team = team_get_team_struct_locked(teamID);
if (team == NULL || team->death_entry != NULL)
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
BReference<Team> teamReference(team, true);
TeamLocker teamLocker(team, true);
// don't allow messing with the kernel team // don't allow messing with the kernel team
if (team == team_get_kernel_team()) if (team == team_get_kernel_team())
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
// check whether the condition is already set // check whether the condition is already set
SpinLocker threadLocker(gThreadSpinlock); InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
SpinLocker debugInfoLocker(team->debug_info.lock);
if (team->debug_info.debugger_changed_condition == NULL) { if (team->debug_info.debugger_changed_condition == NULL) {
// nobody there yet -- set our condition variable and be done // nobody there yet -- set our condition variable and be done
@@ -398,7 +399,6 @@ prepare_debugger_change(team_id teamID, ConditionVariable& condition,
team->debug_info.debugger_changed_condition->Add(&entry); team->debug_info.debugger_changed_condition->Add(&entry);
debugInfoLocker.Unlock(); debugInfoLocker.Unlock();
threadLocker.Unlock();
teamLocker.Unlock(); teamLocker.Unlock();
entry.Wait(); entry.Wait();
@@ -411,8 +411,7 @@ prepare_debugger_change(Team* team, ConditionVariable& condition)
{ {
while (true) { while (true) {
// check whether the condition is already set // check whether the condition is already set
InterruptsSpinLocker threadLocker(gThreadSpinlock); InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
SpinLocker debugInfoLocker(team->debug_info.lock);
if (team->debug_info.debugger_changed_condition == NULL) { if (team->debug_info.debugger_changed_condition == NULL) {
// nobody there yet -- set our condition variable and be done // nobody there yet -- set our condition variable and be done
@@ -425,7 +424,6 @@ prepare_debugger_change(Team* team, ConditionVariable& condition)
team->debug_info.debugger_changed_condition->Add(&entry); team->debug_info.debugger_changed_condition->Add(&entry);
debugInfoLocker.Unlock(); debugInfoLocker.Unlock();
threadLocker.Unlock();
entry.Wait(); entry.Wait();
} }
@@ -436,13 +434,12 @@ static void
finish_debugger_change(Team* team) finish_debugger_change(Team* team)
{ {
// unset our condition variable and notify all threads waiting on it // unset our condition variable and notify all threads waiting on it
InterruptsSpinLocker threadLocker(gThreadSpinlock); InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
SpinLocker debugInfoLocker(team->debug_info.lock);
ConditionVariable* condition = team->debug_info.debugger_changed_condition; ConditionVariable* condition = team->debug_info.debugger_changed_condition;
team->debug_info.debugger_changed_condition = NULL; team->debug_info.debugger_changed_condition = NULL;
condition->NotifyAll(true); condition->NotifyAll(false);
} }
@@ -460,14 +457,12 @@ user_debug_prepare_for_exec()
// get the port // get the port
port_id debugPort = -1; port_id debugPort = -1;
cpu_status state = disable_interrupts(); InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
GRAB_THREAD_LOCK();
if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) if ((thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) != 0)
debugPort = thread->debug_info.debug_port; debugPort = thread->debug_info.debug_port;
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
restore_interrupts(state);
// set the new port ownership // set the new port ownership
if (debugPort >= 0) if (debugPort >= 0)
@@ -489,14 +484,12 @@ user_debug_finish_after_exec()
// get the port // get the port
port_id debugPort = -1; port_id debugPort = -1;
cpu_status state = disable_interrupts(); InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
GRAB_THREAD_LOCK();
if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED)
debugPort = thread->debug_info.debug_port; debugPort = thread->debug_info.debug_port;
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
restore_interrupts(state);
// set the new port ownership // set the new port ownership
if (debugPort >= 0) if (debugPort >= 0)
@@ -565,8 +558,8 @@ thread_hit_debug_event_internal(debug_debugger_message event,
port_id nubPort = -1; port_id nubPort = -1;
status_t error = B_OK; status_t error = B_OK;
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
GRAB_THREAD_LOCK();
GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
uint32 threadFlags = thread->debug_info.flags; uint32 threadFlags = thread->debug_info.flags;
threadFlags &= ~B_THREAD_DEBUG_STOP; threadFlags &= ~B_THREAD_DEBUG_STOP;
@@ -578,7 +571,6 @@ thread_hit_debug_event_internal(debug_debugger_message event,
thread->id)); thread->id));
error = B_ERROR; error = B_ERROR;
} else if (debuggerInstalled || !requireDebugger) { } else if (debuggerInstalled || !requireDebugger) {
if (debuggerInstalled) { if (debuggerInstalled) {
debuggerPort = thread->team->debug_info.debugger_port; debuggerPort = thread->team->debug_info.debugger_port;
@@ -613,8 +605,8 @@ thread_hit_debug_event_internal(debug_debugger_message event,
update_thread_user_debug_flag(thread); update_thread_user_debug_flag(thread);
threadDebugInfoLocker.Unlock();
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
RELEASE_THREAD_LOCK();
restore_interrupts(state); restore_interrupts(state);
// delete the superfluous port // delete the superfluous port
@@ -738,7 +730,7 @@ thread_hit_debug_event_internal(debug_debugger_message event,
thread_debug_info threadDebugInfo; thread_debug_info threadDebugInfo;
state = disable_interrupts(); state = disable_interrupts();
GRAB_THREAD_LOCK(); threadDebugInfoLocker.Lock();
// check, if the team is still being debugged // check, if the team is still being debugged
int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
@@ -765,7 +757,7 @@ thread_hit_debug_event_internal(debug_debugger_message event,
destroyThreadInfo = true; destroyThreadInfo = true;
} }
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
restore_interrupts(state); restore_interrupts(state);
// enable/disable single stepping // enable/disable single stepping
@@ -790,7 +782,7 @@ thread_hit_debug_event(debug_debugger_message event, const void *message,
requireDebugger, restart); requireDebugger, restart);
} while (result >= 0 && restart); } while (result >= 0 && restart);
// Prepare to continue -- we install a debugger change condition, so no-one // Prepare to continue -- we install a debugger change condition, so no one
// will change the debugger while we're playing with the breakpoint manager. // will change the debugger while we're playing with the breakpoint manager.
// TODO: Maybe better use ref-counting and a flag in the breakpoint manager. // TODO: Maybe better use ref-counting and a flag in the breakpoint manager.
Team* team = thread_get_current_thread()->team; Team* team = thread_get_current_thread()->team;
@@ -954,8 +946,9 @@ void
user_debug_stop_thread() user_debug_stop_thread()
{ {
// check whether this is actually an emulated single-step notification // check whether this is actually an emulated single-step notification
InterruptsSpinLocker threadsLocker(gThreadSpinlock);
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();
InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
bool singleStepped = false; bool singleStepped = false;
if ((atomic_and(&thread->debug_info.flags, if ((atomic_and(&thread->debug_info.flags,
~B_THREAD_DEBUG_NOTIFY_SINGLE_STEP) ~B_THREAD_DEBUG_NOTIFY_SINGLE_STEP)
@@ -963,7 +956,7 @@ user_debug_stop_thread()
singleStepped = true; singleStepped = true;
} }
threadsLocker.Unlock(); threadDebugInfoLocker.Unlock();
if (singleStepped) { if (singleStepped) {
user_debug_single_stepped(); user_debug_single_stepped();
@@ -1035,19 +1028,15 @@ user_debug_team_exec()
} }
/*! Called by a new userland thread to update the debugging related flags of
\c Thread::flags before the thread first enters userland.
\param thread The calling thread.
*/
void void
user_debug_update_new_thread_flags(thread_id threadID) user_debug_update_new_thread_flags(Thread* thread)
{ {
// Update thread::flags of the thread. // lock it and update it's flags
InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
InterruptsLocker interruptsLocker;
SpinLocker teamLocker(gTeamSpinlock);
SpinLocker threadLocker(gThreadSpinlock);
Thread *thread = thread_get_thread_struct_locked(threadID);
if (!thread)
return;
update_thread_user_debug_flag(thread); update_thread_user_debug_flag(thread);
update_thread_breakpoints_flag(thread); update_thread_breakpoints_flag(thread);
@@ -1082,20 +1071,18 @@ user_debug_thread_deleted(team_id teamID, thread_id threadID)
// the debugged team (but to the kernel). So we can't use debugger_write(). // the debugged team (but to the kernel). So we can't use debugger_write().
// get the team debug flags and debugger port // get the team debug flags and debugger port
InterruptsSpinLocker teamLocker(gTeamSpinlock); Team* team = Team::Get(teamID);
Team *team = team_get_team_struct_locked(teamID);
if (team == NULL) if (team == NULL)
return; return;
BReference<Team> teamReference(team, true);
SpinLocker debugInfoLocker(team->debug_info.lock); InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
int32 teamDebugFlags = atomic_get(&team->debug_info.flags); int32 teamDebugFlags = atomic_get(&team->debug_info.flags);
port_id debuggerPort = team->debug_info.debugger_port; port_id debuggerPort = team->debug_info.debugger_port;
sem_id writeLock = team->debug_info.debugger_write_lock; sem_id writeLock = team->debug_info.debugger_write_lock;
debugInfoLocker.Unlock(); debugInfoLocker.Unlock();
teamLocker.Unlock();
// check, if a debugger is installed and is interested in thread events // check, if a debugger is installed and is interested in thread events
if (~teamDebugFlags if (~teamDebugFlags
@@ -1109,19 +1096,12 @@ user_debug_thread_deleted(team_id teamID, thread_id threadID)
return; return;
// re-get the team debug info -- we need to check whether anything changed // re-get the team debug info -- we need to check whether anything changed
teamLocker.Lock();
team = team_get_team_struct_locked(teamID);
if (team == NULL)
return;
debugInfoLocker.Lock(); debugInfoLocker.Lock();
teamDebugFlags = atomic_get(&team->debug_info.flags); teamDebugFlags = atomic_get(&team->debug_info.flags);
port_id newDebuggerPort = team->debug_info.debugger_port; port_id newDebuggerPort = team->debug_info.debugger_port;
debugInfoLocker.Unlock(); debugInfoLocker.Unlock();
teamLocker.Unlock();
// Send the message only if the debugger hasn't changed in the meantime or // Send the message only if the debugger hasn't changed in the meantime or
// the team is about to be handed over. // the team is about to be handed over.
@@ -1141,14 +1121,18 @@ user_debug_thread_deleted(team_id teamID, thread_id threadID)
} }
/*! Called for a thread that is about to die, cleaning up all user debug
facilities installed for the thread.
\param thread The current thread, the one that is going to die.
*/
void void
user_debug_thread_exiting(Thread* thread) user_debug_thread_exiting(Thread* thread)
{ {
InterruptsLocker interruptsLocker; // thread is the current thread, so using team is safe
SpinLocker teamLocker(gTeamSpinlock);
Team* team = thread->team; Team* team = thread->team;
InterruptsLocker interruptsLocker;
GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
int32 teamDebugFlags = atomic_get(&team->debug_info.flags); int32 teamDebugFlags = atomic_get(&team->debug_info.flags);
@@ -1156,8 +1140,6 @@ user_debug_thread_exiting(Thread* thread)
RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
teamLocker.Unlock();
// check, if a debugger is installed // check, if a debugger is installed
if ((teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) == 0 if ((teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) == 0
|| debuggerPort < 0) { || debuggerPort < 0) {
@@ -1165,7 +1147,7 @@ user_debug_thread_exiting(Thread* thread)
} }
// detach the profile info and mark the thread dying // detach the profile info and mark the thread dying
SpinLocker threadLocker(gThreadSpinlock); SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
thread_debug_info& threadDebugInfo = thread->debug_info; thread_debug_info& threadDebugInfo = thread->debug_info;
if (threadDebugInfo.profile.samples == NULL) if (threadDebugInfo.profile.samples == NULL)
@@ -1183,7 +1165,7 @@ user_debug_thread_exiting(Thread* thread)
atomic_or(&threadDebugInfo.flags, B_THREAD_DEBUG_DYING); atomic_or(&threadDebugInfo.flags, B_THREAD_DEBUG_DYING);
threadLocker.Unlock(); threadDebugInfoLocker.Unlock();
interruptsLocker.Unlock(); interruptsLocker.Unlock();
// notify the debugger // notify the debugger
@@ -1294,17 +1276,26 @@ user_debug_single_stepped()
} }
/*! Schedules the profiling timer for the current thread.
The caller must hold the thread's debug info lock.
\param thread The current thread.
\param interval The time after which the timer should fire.
*/
static void static void
schedule_profiling_timer(Thread* thread, bigtime_t interval) schedule_profiling_timer(Thread* thread, bigtime_t interval)
{ {
struct timer* timer = &sProfilingTimers[thread->cpu->cpu_num]; struct timer* timer = &sProfilingTimers[thread->cpu->cpu_num];
thread->debug_info.profile.installed_timer = timer; thread->debug_info.profile.installed_timer = timer;
thread->debug_info.profile.timer_end = system_time() + interval; thread->debug_info.profile.timer_end = system_time() + interval;
add_timer(timer, &profiling_event, interval, add_timer(timer, &profiling_event, interval, B_ONE_SHOT_RELATIVE_TIMER);
B_ONE_SHOT_RELATIVE_TIMER | B_TIMER_ACQUIRE_THREAD_LOCK);
} }
/*! Samples the current thread's instruction pointer/stack trace.
The caller must hold the current thread's debug info lock.
\param flushBuffer Return parameter: Set to \c true when the sampling
buffer must be flushed.
*/
static bool static bool
profiling_do_sample(bool& flushBuffer) profiling_do_sample(bool& flushBuffer)
{ {
@@ -1385,10 +1376,15 @@ profiling_do_sample(bool& flushBuffer)
static void static void
profiling_buffer_full(void*) profiling_buffer_full(void*)
{ {
// It is undefined whether the function is called with interrupts enabled
// or disabled. We are allowed to enable interrupts, though. First make
// sure interrupts are disabled.
disable_interrupts();
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();
thread_debug_info& debugInfo = thread->debug_info; thread_debug_info& debugInfo = thread->debug_info;
GRAB_THREAD_LOCK(); SpinLocker threadDebugInfoLocker(debugInfo.lock);
if (debugInfo.profile.samples != NULL && debugInfo.profile.buffer_full) { if (debugInfo.profile.samples != NULL && debugInfo.profile.buffer_full) {
int32 sampleCount = debugInfo.profile.sample_count; int32 sampleCount = debugInfo.profile.sample_count;
@@ -1401,7 +1397,7 @@ profiling_buffer_full(void*)
debugInfo.profile.sample_count = 0; debugInfo.profile.sample_count = 0;
debugInfo.profile.dropped_ticks = 0; debugInfo.profile.dropped_ticks = 0;
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
enable_interrupts(); enable_interrupts();
// prepare the message // prepare the message
@@ -1417,7 +1413,7 @@ profiling_buffer_full(void*)
sizeof(message), false); sizeof(message), false);
disable_interrupts(); disable_interrupts();
GRAB_THREAD_LOCK(); threadDebugInfoLocker.Lock();
// do the sampling and reschedule timer, if still profiling this thread // do the sampling and reschedule timer, if still profiling this thread
bool flushBuffer; bool flushBuffer;
@@ -1427,11 +1423,13 @@ profiling_buffer_full(void*)
} }
} }
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
enable_interrupts();
} }
/*! The thread spinlock is being held. /*! Profiling timer event callback.
Called with interrupts disabled.
*/ */
static int32 static int32
profiling_event(timer* /*unused*/) profiling_event(timer* /*unused*/)
@@ -1439,6 +1437,8 @@ profiling_event(timer* /*unused*/)
Thread* thread = thread_get_current_thread(); Thread* thread = thread_get_current_thread();
thread_debug_info& debugInfo = thread->debug_info; thread_debug_info& debugInfo = thread->debug_info;
SpinLocker threadDebugInfoLocker(debugInfo.lock);
bool flushBuffer = false; bool flushBuffer = false;
if (profiling_do_sample(flushBuffer)) { if (profiling_do_sample(flushBuffer)) {
if (flushBuffer) { if (flushBuffer) {
@@ -1458,9 +1458,14 @@ profiling_event(timer* /*unused*/)
} }
/*! Called by the scheduler when a debugged thread has been unscheduled.
The scheduler lock is being held.
*/
void void
user_debug_thread_unscheduled(Thread* thread) user_debug_thread_unscheduled(Thread* thread)
{ {
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
// if running, cancel the profiling timer // if running, cancel the profiling timer
struct timer* timer = thread->debug_info.profile.installed_timer; struct timer* timer = thread->debug_info.profile.installed_timer;
if (timer != NULL) { if (timer != NULL) {
@@ -1470,14 +1475,23 @@ user_debug_thread_unscheduled(Thread* thread)
thread->debug_info.profile.installed_timer = NULL; thread->debug_info.profile.installed_timer = NULL;
// cancel timer // cancel timer
threadDebugInfoLocker.Unlock();
// not necessary, but doesn't harm and reduces contention
cancel_timer(timer); cancel_timer(timer);
// since invoked on the same CPU, this will not possibly wait for
// an already called timer hook
} }
} }
/*! Called by the scheduler when a debugged thread has been scheduled.
The scheduler lock is being held.
*/
void void
user_debug_thread_scheduled(Thread* thread) user_debug_thread_scheduled(Thread* thread)
{ {
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
if (thread->debug_info.profile.samples != NULL if (thread->debug_info.profile.samples != NULL
&& !thread->debug_info.profile.buffer_full) { && !thread->debug_info.profile.buffer_full) {
// install profiling timer // install profiling timer
@@ -1500,22 +1514,26 @@ broadcast_debugged_thread_message(Thread *nubThread, int32 code,
int32 cookie = 0; int32 cookie = 0;
while (get_next_thread_info(nubThread->team->id, &cookie, &threadInfo) while (get_next_thread_info(nubThread->team->id, &cookie, &threadInfo)
== B_OK) { == B_OK) {
// find the thread and get its debug port // get the thread and lock it
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadInfo.thread);
GRAB_THREAD_LOCK(); if (thread == NULL)
continue;
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
// get the thread's debug port
InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
port_id threadDebugPort = -1; port_id threadDebugPort = -1;
thread_id threadID = -1;
Thread *thread = thread_get_thread_struct_locked(threadInfo.thread);
if (thread && thread != nubThread && thread->team == nubThread->team if (thread && thread != nubThread && thread->team == nubThread->team
&& (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) != 0 && (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) != 0
&& (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) != 0) { && (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) != 0) {
threadDebugPort = thread->debug_info.debug_port; threadDebugPort = thread->debug_info.debug_port;
threadID = thread->id;
} }
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
restore_interrupts(state); threadLocker.Unlock();
// send the message to the thread // send the message to the thread
if (threadDebugPort >= 0) { if (threadDebugPort >= 0) {
@@ -1523,7 +1541,7 @@ broadcast_debugged_thread_message(Thread *nubThread, int32 code,
code, message, size); code, message, size);
if (error != B_OK) { if (error != B_OK) {
TRACE(("broadcast_debugged_thread_message(): Failed to send " TRACE(("broadcast_debugged_thread_message(): Failed to send "
"message to thread %ld: %lx\n", threadID, error)); "message to thread %ld: %lx\n", thread->id, error));
} }
} }
} }
@@ -1542,6 +1560,9 @@ nub_thread_cleanup(Thread *nubThread)
team_debug_info teamDebugInfo; team_debug_info teamDebugInfo;
bool destroyDebugInfo = false; bool destroyDebugInfo = false;
TeamLocker teamLocker(nubThread->team);
// required by update_threads_debugger_installed_flag()
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
@@ -1559,6 +1580,8 @@ nub_thread_cleanup(Thread *nubThread)
RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
restore_interrupts(state); restore_interrupts(state);
teamLocker.Unlock();
if (destroyDebugInfo) if (destroyDebugInfo)
teamDebugInfo.breakpoint_manager->RemoveAllBreakpoints(); teamDebugInfo.breakpoint_manager->RemoveAllBreakpoints();
@@ -1580,30 +1603,31 @@ static status_t
debug_nub_thread_get_thread_debug_port(Thread *nubThread, debug_nub_thread_get_thread_debug_port(Thread *nubThread,
thread_id threadID, port_id &threadDebugPort) thread_id threadID, port_id &threadDebugPort)
{ {
status_t result = B_OK;
threadDebugPort = -1; threadDebugPort = -1;
cpu_status state = disable_interrupts(); // get the thread
GRAB_THREAD_LOCK(); Thread* thread = Thread::GetAndLock(threadID);
if (thread == NULL)
return B_BAD_THREAD_ID;
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
// get the debug port
InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
Thread *thread = thread_get_thread_struct_locked(threadID);
if (thread) {
if (thread->team != nubThread->team) if (thread->team != nubThread->team)
result = B_BAD_VALUE; return B_BAD_VALUE;
else if (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) if ((thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) == 0)
return B_BAD_THREAD_STATE;
threadDebugPort = thread->debug_info.debug_port; threadDebugPort = thread->debug_info.debug_port;
else
result = B_BAD_THREAD_STATE;
} else
result = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK(); threadDebugInfoLocker.Unlock();
restore_interrupts(state);
if (result == B_OK && threadDebugPort < 0) if (threadDebugPort < 0)
result = B_ERROR; return B_ERROR;
return result; return B_OK;
} }
@@ -1614,7 +1638,6 @@ debug_nub_thread(void *)
// check, if we're still the current nub thread and get our port // check, if we're still the current nub thread and get our port
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
if (nubThread->team->debug_info.nub_thread != nubThread->id) { if (nubThread->team->debug_info.nub_thread != nubThread->id) {
@@ -1779,20 +1802,21 @@ debug_nub_thread(void *)
flags)); flags));
// set the flags // set the flags
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadID);
GRAB_THREAD_LOCK(); if (thread == NULL)
break;
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
Thread *thread = thread_get_thread_struct_locked(threadID); InterruptsSpinLocker threadDebugInfoLocker(
if (thread thread->debug_info.lock);
&& thread->team == thread_get_current_thread()->team) {
if (thread->team == thread_get_current_thread()->team) {
flags |= thread->debug_info.flags flags |= thread->debug_info.flags
& B_THREAD_DEBUG_KERNEL_FLAG_MASK; & B_THREAD_DEBUG_KERNEL_FLAG_MASK;
atomic_set(&thread->debug_info.flags, flags); atomic_set(&thread->debug_info.flags, flags);
} }
RELEASE_THREAD_LOCK();
restore_interrupts(state);
break; break;
} }
@@ -2025,12 +2049,16 @@ debug_nub_thread(void *)
ignoreOp, ignoreOnce, ignoreOnceOp)); ignoreOp, ignoreOnce, ignoreOnceOp));
// set the masks // set the masks
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadID);
GRAB_THREAD_LOCK(); if (thread == NULL)
break;
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
Thread *thread = thread_get_thread_struct_locked(threadID); InterruptsSpinLocker threadDebugInfoLocker(
if (thread thread->debug_info.lock);
&& thread->team == thread_get_current_thread()->team) {
if (thread->team == thread_get_current_thread()->team) {
thread_debug_info &threadDebugInfo = thread->debug_info; thread_debug_info &threadDebugInfo = thread->debug_info;
// set ignore mask // set ignore mask
switch (ignoreOp) { switch (ignoreOp) {
@@ -2059,9 +2087,6 @@ debug_nub_thread(void *)
} }
} }
RELEASE_THREAD_LOCK();
restore_interrupts(state);
break; break;
} }
@@ -2076,19 +2101,19 @@ debug_nub_thread(void *)
uint64 ignore = 0; uint64 ignore = 0;
uint64 ignoreOnce = 0; uint64 ignoreOnce = 0;
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadID);
GRAB_THREAD_LOCK(); if (thread != NULL) {
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
InterruptsSpinLocker threadDebugInfoLocker(
thread->debug_info.lock);
Thread *thread = thread_get_thread_struct_locked(threadID);
if (thread) {
ignore = thread->debug_info.ignore_signals; ignore = thread->debug_info.ignore_signals;
ignoreOnce = thread->debug_info.ignore_signals_once; ignoreOnce = thread->debug_info.ignore_signals_once;
} else } else
result = B_BAD_THREAD_ID; result = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK();
restore_interrupts(state);
TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_MASKS: " TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_MASKS: "
"reply port: %ld, thread: %ld, ignore: %llx, " "reply port: %ld, thread: %ld, ignore: %llx, "
"ignore once: %llx, result: %lx\n", nubThread->id, "ignore once: %llx, result: %lx\n", nubThread->id,
@@ -2106,30 +2131,15 @@ debug_nub_thread(void *)
case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER:
{ {
// get the parameters // get the parameters
thread_id threadID = message.set_signal_handler.thread;
int signal = message.set_signal_handler.signal; int signal = message.set_signal_handler.signal;
struct sigaction &handler = message.set_signal_handler.handler; struct sigaction &handler = message.set_signal_handler.handler;
TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: " TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: "
"thread: %ld, signal: %d, handler: %p\n", nubThread->id, "signal: %d, handler: %p\n", nubThread->id,
threadID, signal, handler.sa_handler)); signal, handler.sa_handler));
// check, if the thread exists and is ours
cpu_status state = disable_interrupts();
GRAB_THREAD_LOCK();
Thread *thread = thread_get_thread_struct_locked(threadID);
if (thread
&& thread->team != thread_get_current_thread()->team) {
thread = NULL;
}
RELEASE_THREAD_LOCK();
restore_interrupts(state);
// set the handler // set the handler
if (thread) sigaction(signal, &handler, NULL);
sigaction_etc(threadID, signal, &handler, NULL);
break; break;
} }
@@ -2138,35 +2148,18 @@ debug_nub_thread(void *)
{ {
// get the parameters // get the parameters
replyPort = message.get_signal_handler.reply_port; replyPort = message.get_signal_handler.reply_port;
thread_id threadID = message.get_signal_handler.thread;
int signal = message.get_signal_handler.signal; int signal = message.get_signal_handler.signal;
status_t result = B_OK; status_t result = B_OK;
// check, if the thread exists and is ours
cpu_status state = disable_interrupts();
GRAB_THREAD_LOCK();
Thread *thread = thread_get_thread_struct_locked(threadID);
if (thread) {
if (thread->team != thread_get_current_thread()->team)
result = B_BAD_VALUE;
} else
result = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK();
restore_interrupts(state);
// get the handler // get the handler
if (result == B_OK if (sigaction(signal, NULL, &reply.get_signal_handler.handler)
&& sigaction_etc(threadID, signal, NULL, != 0) {
&reply.get_signal_handler.handler) != 0) {
result = errno; result = errno;
} }
TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: " TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: "
"reply port: %ld, thread: %ld, signal: %d, " "reply port: %ld, signal: %d, handler: %p\n", nubThread->id,
"handler: %p\n", nubThread->id, replyPort, replyPort, signal,
threadID, signal,
reply.get_signal_handler.handler.sa_handler)); reply.get_signal_handler.handler.sa_handler));
// prepare the message // prepare the message
@@ -2275,12 +2268,16 @@ debug_nub_thread(void *)
// get the thread and set the profile info // get the thread and set the profile info
int32 imageEvent = nubThread->team->debug_info.image_event; int32 imageEvent = nubThread->team->debug_info.image_event;
if (result == B_OK) { if (result == B_OK) {
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadID);
GRAB_THREAD_LOCK(); BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
Thread *thread = thread_get_thread_struct_locked(threadID); if (thread != NULL && thread->team == nubThread->team) {
if (thread && thread->team == nubThread->team) {
thread_debug_info &threadDebugInfo = thread->debug_info; thread_debug_info &threadDebugInfo = thread->debug_info;
InterruptsSpinLocker threadDebugInfoLocker(
threadDebugInfo.lock);
if (threadDebugInfo.profile.samples == NULL) { if (threadDebugInfo.profile.samples == NULL) {
threadDebugInfo.profile.interval = interval; threadDebugInfo.profile.interval = interval;
threadDebugInfo.profile.sample_area threadDebugInfo.profile.sample_area
@@ -2307,9 +2304,6 @@ debug_nub_thread(void *)
result = B_BAD_VALUE; result = B_BAD_VALUE;
} else } else
result = B_BAD_THREAD_ID; result = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK();
restore_interrupts(state);
} }
// on error unlock and delete the sample area // on error unlock and delete the sample area
@@ -2349,12 +2343,16 @@ debug_nub_thread(void *)
int32 droppedTicks = 0; int32 droppedTicks = 0;
// get the thread and detach the profile info // get the thread and detach the profile info
cpu_status state = disable_interrupts(); Thread* thread = Thread::GetAndLock(threadID);
GRAB_THREAD_LOCK(); BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
Thread *thread = thread_get_thread_struct_locked(threadID);
if (thread && thread->team == nubThread->team) { if (thread && thread->team == nubThread->team) {
thread_debug_info &threadDebugInfo = thread->debug_info; thread_debug_info &threadDebugInfo = thread->debug_info;
InterruptsSpinLocker threadDebugInfoLocker(
threadDebugInfo.lock);
if (threadDebugInfo.profile.samples != NULL) { if (threadDebugInfo.profile.samples != NULL) {
sampleArea = threadDebugInfo.profile.sample_area; sampleArea = threadDebugInfo.profile.sample_area;
samples = threadDebugInfo.profile.samples; samples = threadDebugInfo.profile.samples;
@@ -2373,8 +2371,7 @@ debug_nub_thread(void *)
} else } else
result = B_BAD_THREAD_ID; result = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK(); threadLocker.Unlock();
restore_interrupts(state);
// prepare the reply // prepare the reply
if (result == B_OK) { if (result == B_OK) {
@@ -2424,9 +2421,7 @@ debug_nub_thread(void *)
/** \brief Helper function for install_team_debugger(), that sets up the team /** \brief Helper function for install_team_debugger(), that sets up the team
and thread debug infos. and thread debug infos.
Interrupts must be disabled and the team debug info lock of the team to be The caller must hold the team's lock as well as the team debug info lock.
debugged must be held. The function will release the lock, but leave
interrupts disabled.
The function also clears the arch specific team and thread debug infos The function also clears the arch specific team and thread debug infos
(including among other things formerly set break/watchpoints). (including among other things formerly set break/watchpoints).
@@ -2447,14 +2442,11 @@ install_team_debugger_init_debug_infos(Team *team, team_id debuggerTeam,
arch_clear_team_debug_info(&team->debug_info.arch_info); arch_clear_team_debug_info(&team->debug_info.arch_info);
RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
// set the user debug flags and signal masks of all threads to the default // set the user debug flags and signal masks of all threads to the default
GRAB_THREAD_LOCK(); for (Thread *thread = team->thread_list; thread;
for (Thread *thread = team->thread_list;
thread;
thread = thread->team_next) { thread = thread->team_next) {
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
if (thread->id == nubThread) { if (thread->id == nubThread) {
atomic_set(&thread->debug_info.flags, B_THREAD_DEBUG_NUB_THREAD); atomic_set(&thread->debug_info.flags, B_THREAD_DEBUG_NUB_THREAD);
} else { } else {
@@ -2469,8 +2461,6 @@ install_team_debugger_init_debug_infos(Team *team, team_id debuggerTeam,
} }
} }
RELEASE_THREAD_LOCK();
// update the thread::flags fields // update the thread::flags fields
update_threads_debugger_installed_flag(team); update_threads_debugger_installed_flag(team);
} }
@@ -2519,10 +2509,10 @@ install_team_debugger(team_id teamID, port_id debuggerPort,
bool done = false; bool done = false;
port_id result = B_ERROR; port_id result = B_ERROR;
bool handOver = false; bool handOver = false;
bool releaseDebugInfoLock = true;
port_id oldDebuggerPort = -1; port_id oldDebuggerPort = -1;
port_id nubPort = -1; port_id nubPort = -1;
TeamLocker teamLocker(team);
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
@@ -2553,7 +2543,6 @@ install_team_debugger(team_id teamID, port_id debuggerPort,
debuggerPort, nubPort, team->debug_info.nub_thread, debuggerPort, nubPort, team->debug_info.nub_thread,
team->debug_info.debugger_write_lock, causingThread); team->debug_info.debugger_write_lock, causingThread);
releaseDebugInfoLock = false;
handOver = true; handOver = true;
done = true; done = true;
} }
@@ -2570,11 +2559,9 @@ install_team_debugger(team_id teamID, port_id debuggerPort,
error = B_BAD_VALUE; error = B_BAD_VALUE;
} }
// in case of a handover the lock has already been released
if (releaseDebugInfoLock)
RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
restore_interrupts(state); restore_interrupts(state);
teamLocker.Unlock();
if (handOver && set_port_owner(nubPort, debuggerTeam) != B_OK) { if (handOver && set_port_owner(nubPort, debuggerTeam) != B_OK) {
// The old debugger must just have died. Just proceed as // The old debugger must just have died. Just proceed as
@@ -2681,13 +2668,14 @@ install_team_debugger(team_id teamID, port_id debuggerPort,
if (error == B_OK) { if (error == B_OK) {
snprintf(nameBuffer, sizeof(nameBuffer), "team %ld debug task", teamID); snprintf(nameBuffer, sizeof(nameBuffer), "team %ld debug task", teamID);
nubThread = spawn_kernel_thread_etc(debug_nub_thread, nameBuffer, nubThread = spawn_kernel_thread_etc(debug_nub_thread, nameBuffer,
B_NORMAL_PRIORITY, NULL, teamID, -1); B_NORMAL_PRIORITY, NULL, teamID);
if (nubThread < 0) if (nubThread < 0)
error = nubThread; error = nubThread;
} }
// now adjust the debug info accordingly // now adjust the debug info accordingly
if (error == B_OK) { if (error == B_OK) {
TeamLocker teamLocker(team);
state = disable_interrupts(); state = disable_interrupts();
GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
@@ -2696,6 +2684,7 @@ install_team_debugger(team_id teamID, port_id debuggerPort,
debuggerPort, nubPort, nubThread, debuggerWriteLock, debuggerPort, nubPort, nubThread, debuggerWriteLock,
causingThread); causingThread);
RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
restore_interrupts(state); restore_interrupts(state);
} }
@@ -2865,30 +2854,41 @@ _user_debug_thread(thread_id threadID)
{ {
TRACE(("[%ld] _user_debug_thread(%ld)\n", find_thread(NULL), threadID)); TRACE(("[%ld] _user_debug_thread(%ld)\n", find_thread(NULL), threadID));
// tell the thread to stop as soon as possible // get the thread
status_t error = B_OK; Thread* thread = Thread::GetAndLock(threadID);
cpu_status state = disable_interrupts(); if (thread == NULL)
GRAB_THREAD_LOCK(); return B_BAD_THREAD_ID;
BReference<Thread> threadReference(thread, true);
ThreadLocker threadLocker(thread, true);
Thread *thread = thread_get_thread_struct_locked(threadID);
if (!thread) {
// thread doesn't exist any longer
error = B_BAD_THREAD_ID;
} else if (thread->team == team_get_kernel_team()) {
// we can't debug the kernel team // we can't debug the kernel team
error = B_NOT_ALLOWED; if (thread->team == team_get_kernel_team())
} else if (thread->debug_info.flags & B_THREAD_DEBUG_DYING) { return B_NOT_ALLOWED;
// the thread is already dying -- too late to debug it
error = B_BAD_THREAD_ID; InterruptsLocker interruptsLocker;
} else if (thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) { SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
// If the thread is already dying, it's too late to debug it.
if ((thread->debug_info.flags & B_THREAD_DEBUG_DYING) != 0)
return B_BAD_THREAD_ID;
// don't debug the nub thread // don't debug the nub thread
error = B_NOT_ALLOWED; if ((thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) != 0)
} else if (!(thread->debug_info.flags & B_THREAD_DEBUG_STOPPED)) { return B_NOT_ALLOWED;
// already marked stopped?
if ((thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) != 0)
return B_OK;
// set the flag that tells the thread to stop as soon as possible // set the flag that tells the thread to stop as soon as possible
atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP); atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP);
update_thread_user_debug_flag(thread); update_thread_user_debug_flag(thread);
// resume/interrupt the thread, if necessary
threadDebugInfoLocker.Unlock();
SpinLocker schedulerLocker(gSchedulerLock);
switch (thread->state) { switch (thread->state) {
case B_THREAD_SUSPENDED: case B_THREAD_SUSPENDED:
// thread suspended: wake it up // thread suspended: wake it up
@@ -2905,12 +2905,8 @@ _user_debug_thread(thread_id threadID)
scheduler_reschedule_if_necessary_locked(); scheduler_reschedule_if_necessary_locked();
break; break;
} }
}
RELEASE_THREAD_LOCK(); return B_OK;
restore_interrupts(state);
return error;
} }
@@ -810,8 +810,7 @@ IOSchedulerSimple::_GetRequestOwner(team_id team, thread_id thread,
RequestOwnerList existingOwners; RequestOwnerList existingOwners;
while ((owner = fUnusedRequestOwners.RemoveHead()) != NULL) { while ((owner = fUnusedRequestOwners.RemoveHead()) != NULL) {
if (owner->thread < 0 if (owner->thread < 0 || !Thread::IsAlive(owner->thread)) {
|| thread_get_thread_struct(owner->thread) == NULL) {
if (owner->thread >= 0) if (owner->thread >= 0)
fRequestOwners->RemoveUnchecked(owner); fRequestOwners->RemoveUnchecked(owner);
owner->team = team; owner->team = team;
+14
View File
@@ -1772,6 +1772,20 @@ elf_debug_lookup_symbol(const char* searchName)
} }
status_t
elf_lookup_kernel_symbol(const char* name, elf_symbol_info* info)
{
// find the symbol
Elf32_Sym* foundSymbol = elf_find_symbol(sKernelImage, name, NULL, false);
if (foundSymbol == NULL)
return B_MISSING_SYMBOL;
info->address = foundSymbol->st_value + sKernelImage->text_region.delta;
info->size = foundSymbol->st_size;
return B_OK;
}
status_t status_t
elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry) elf_load_user_image(const char *path, Team *team, int flags, addr_t *entry)
{ {
+2 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -88,6 +88,6 @@ vnode::_WakeUpLocker()
atomic_and(&fFlags, ~kFlagsWaitingLocker); atomic_and(&fFlags, ~kFlagsWaitingLocker);
// and wake it up // and wake it up
InterruptsSpinLocker threadLocker(gThreadSpinlock); InterruptsSpinLocker threadLocker(gSchedulerLock);
thread_unblock_locked(waiter->thread, B_OK); thread_unblock_locked(waiter->thread, B_OK);
} }
+2 -7
View File
@@ -476,17 +476,12 @@ int
dup_foreign_fd(team_id fromTeam, int fd, bool kernel) dup_foreign_fd(team_id fromTeam, int fd, bool kernel)
{ {
// get the I/O context for the team in question // get the I/O context for the team in question
InterruptsSpinLocker teamsLocker(gTeamSpinlock); Team* team = Team::Get(fromTeam);
Team* team = team_get_team_struct_locked(fromTeam);
if (team == NULL) if (team == NULL)
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
BReference<Team> teamReference(team, true);
io_context* fromContext = team->io_context; io_context* fromContext = team->io_context;
vfs_get_io_context(fromContext);
teamsLocker.Unlock();
CObjectDeleter<io_context> _(fromContext, vfs_put_io_context);
// get the file descriptor // get the file descriptor
file_descriptor* descriptor = get_fd(fromContext, fd); file_descriptor* descriptor = get_fd(fromContext, fd);
+1 -1
View File
@@ -100,7 +100,7 @@ public:
TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified); TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified);
if (!fNotified) { if (!fNotified) {
SpinLocker threadLocker(gThreadSpinlock); SpinLocker schedulerLocker(gSchedulerLock);
thread_unblock_locked(fThread, status); thread_unblock_locked(fThread, status);
fNotified = true; fNotified = true;
} }
+15 -88
View File
@@ -1764,62 +1764,18 @@ replace_vnode_if_disconnected(struct fs_mount* mount,
This is not a cheap function and should be used with care and rarely. This is not a cheap function and should be used with care and rarely.
TODO: there is currently no means to stop a blocking read/write! TODO: there is currently no means to stop a blocking read/write!
*/ */
void static void
disconnect_mount_or_vnode_fds(struct fs_mount* mount, disconnect_mount_or_vnode_fds(struct fs_mount* mount,
struct vnode* vnodeToDisconnect) struct vnode* vnodeToDisconnect)
{ {
// iterate over all teams and peek into their file descriptors // iterate over all teams and peek into their file descriptors
int32 nextTeamID = 0; TeamListIterator teamIterator;
while (Team* team = teamIterator.Next()) {
BReference<Team> teamReference(team, true);
while (true) { // lock the I/O context
struct io_context* context = NULL; io_context* context = team->io_context;
bool contextLocked = false; MutexLocker contextLocker(context->io_mutex);
Team* team = NULL;
team_id lastTeamID;
cpu_status state = disable_interrupts();
SpinLocker teamsLock(gTeamSpinlock);
lastTeamID = peek_next_thread_id();
if (nextTeamID < lastTeamID) {
// get next valid team
while (nextTeamID < lastTeamID
&& !(team = team_get_team_struct_locked(nextTeamID))) {
nextTeamID++;
}
if (team) {
context = (io_context*)team->io_context;
// Some acrobatics to lock the context in a safe way
// (cf. _kern_get_next_fd_info() for details).
GRAB_THREAD_LOCK();
teamsLock.Unlock();
contextLocked = mutex_lock_threads_locked(&context->io_mutex)
== B_OK;
RELEASE_THREAD_LOCK();
nextTeamID++;
}
}
teamsLock.Unlock();
restore_interrupts(state);
if (context == NULL)
break;
// we now have a context - since we couldn't lock it while having
// safe access to the team structure, we now need to lock the mutex
// manually
if (!contextLocked) {
// team seems to be gone, go over to the next team
continue;
}
// the team cannot be deleted completely while we're owning its
// io_context mutex, so we can safely play with it now
replace_vnode_if_disconnected(mount, vnodeToDisconnect, context->root, replace_vnode_if_disconnected(mount, vnodeToDisconnect, context->root,
sRoot, true); sRoot, true);
@@ -1843,8 +1799,6 @@ disconnect_mount_or_vnode_fds(struct fs_mount* mount,
put_fd(descriptor); put_fd(descriptor);
} }
} }
mutex_unlock(&context->io_mutex);
} }
} }
@@ -7828,38 +7782,15 @@ _kern_get_next_fd_info(team_id teamID, uint32* _cookie, fd_info* info,
if (infoSize != sizeof(fd_info)) if (infoSize != sizeof(fd_info))
return B_BAD_VALUE; return B_BAD_VALUE;
struct io_context* context = NULL; // get the team
Team* team = NULL; Team* team = Team::Get(teamID);
if (team == NULL)
cpu_status state = disable_interrupts();
GRAB_TEAM_LOCK();
bool contextLocked = false;
team = team_get_team_struct_locked(teamID);
if (team) {
// We cannot lock the IO context while holding the team lock, nor can
// we just drop the team lock, since it might be deleted in the
// meantime. team_remove_team() acquires the thread lock when removing
// the team from the team hash table, though. Hence we switch to the
// thread lock and use mutex_lock_threads_locked().
context = (io_context*)team->io_context;
GRAB_THREAD_LOCK();
RELEASE_TEAM_LOCK();
contextLocked = mutex_lock_threads_locked(&context->io_mutex) == B_OK;
RELEASE_THREAD_LOCK();
} else
RELEASE_TEAM_LOCK();
restore_interrupts(state);
if (!contextLocked) {
// team doesn't exit or seems to be gone
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
} BReference<Team> teamReference(team, true);
// the team cannot be deleted completely while we're owning its // now that we have a team reference, its I/O context won't go away
// io_context mutex, so we can safely play with it now io_context* context = team->io_context;
MutexLocker contextLocker(context->io_mutex);
uint32 slot = *_cookie; uint32 slot = *_cookie;
@@ -7869,10 +7800,8 @@ _kern_get_next_fd_info(team_id teamID, uint32* _cookie, fd_info* info,
slot++; slot++;
} }
if (slot >= context->table_size) { if (slot >= context->table_size)
mutex_unlock(&context->io_mutex);
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
}
info->number = slot; info->number = slot;
info->open_mode = descriptor->open_mode; info->open_mode = descriptor->open_mode;
@@ -7886,8 +7815,6 @@ _kern_get_next_fd_info(team_id teamID, uint32* _cookie, fd_info* info,
info->node = -1; info->node = -1;
} }
mutex_unlock(&context->io_mutex);
*_cookie = slot + 1; *_cookie = slot + 1;
return B_OK; return B_OK;
} }
+19 -43
View File
@@ -145,7 +145,7 @@ unregister_image(Team *team, image_id id)
/*! Counts the registered images from the specified team. /*! Counts the registered images from the specified team.
The team lock must be held when you call this function. Interrupts must be enabled.
*/ */
int32 int32
count_images(Team *team) count_images(Team *team)
@@ -153,6 +153,8 @@ count_images(Team *team)
struct image *image = NULL; struct image *image = NULL;
int32 count = 0; int32 count = 0;
MutexLocker locker(sImageMutex);
while ((image = (struct image*)list_get_next_item(&team->image_list, image)) while ((image = (struct image*)list_get_next_item(&team->image_list, image))
!= NULL) { != NULL) {
count++; count++;
@@ -215,45 +217,29 @@ _get_next_image_info(team_id teamID, int32 *cookie, image_info *info,
if (size > sizeof(image_info)) if (size > sizeof(image_info))
return B_BAD_VALUE; return B_BAD_VALUE;
status_t status = B_ENTRY_NOT_FOUND; // get the team
Team *team; Team* team = Team::Get(teamID);
cpu_status state; if (team == NULL)
return B_BAD_TEAM_ID;
BReference<Team> teamReference(team, true);
mutex_lock(&sImageMutex); // iterate through the team's images
MutexLocker imageLocker(sImageMutex);
state = disable_interrupts(); struct image* image = NULL;
GRAB_TEAM_LOCK();
if (teamID == B_CURRENT_TEAM)
team = thread_get_current_thread()->team;
else if (teamID == B_SYSTEM_TEAM)
team = team_get_kernel_team();
else
team = team_get_team_struct_locked(teamID);
if (team) {
struct image *image = NULL;
int32 count = 0; int32 count = 0;
while ((image = (struct image*)list_get_next_item(&team->image_list, while ((image = (struct image*)list_get_next_item(&team->image_list,
image)) != NULL) { image)) != NULL) {
if (count == *cookie) { if (count == *cookie) {
memcpy(info, &image->info, size); memcpy(info, &image->info, size);
status = B_OK;
(*cookie)++; (*cookie)++;
break; return B_OK;
} }
count++; count++;
} }
} else
status = B_BAD_TEAM_ID;
RELEASE_TEAM_LOCK(); return B_ENTRY_NOT_FOUND;
restore_interrupts(state);
mutex_unlock(&sImageMutex);
return status;
} }
@@ -366,24 +352,21 @@ image_init(void)
static void static void
notify_loading_app(status_t result, bool suspend) notify_loading_app(status_t result, bool suspend)
{ {
cpu_status state; Team* team = thread_get_current_thread()->team;
Team *team;
state = disable_interrupts(); TeamLocker teamLocker(team);
GRAB_TEAM_LOCK();
team = thread_get_current_thread()->team;
if (team->loading_info) { if (team->loading_info) {
// there's indeed someone waiting // there's indeed someone waiting
struct team_loading_info *loadingInfo = team->loading_info; struct team_loading_info* loadingInfo = team->loading_info;
team->loading_info = NULL; team->loading_info = NULL;
loadingInfo->result = result; loadingInfo->result = result;
loadingInfo->done = true; loadingInfo->done = true;
// we're done with the team stuff, get the thread lock instead // we're done with the team stuff, get the scheduler lock instead
RELEASE_TEAM_LOCK(); teamLocker.Unlock();
GRAB_THREAD_LOCK(); InterruptsSpinLocker schedulerLocker(gSchedulerLock);
// wake up the waiting thread // wake up the waiting thread
if (loadingInfo->thread->state == B_THREAD_SUSPENDED) if (loadingInfo->thread->state == B_THREAD_SUSPENDED)
@@ -394,14 +377,7 @@ notify_loading_app(status_t result, bool suspend)
thread_get_current_thread()->next_state = B_THREAD_SUSPENDED; thread_get_current_thread()->next_state = B_THREAD_SUSPENDED;
scheduler_reschedule(); scheduler_reschedule();
} }
RELEASE_THREAD_LOCK();
} else {
// no-one is waiting
RELEASE_TEAM_LOCK();
} }
restore_interrupts(state);
} }

Some files were not shown because too many files have changed in this diff Show More