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:
@@ -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) ;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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__ */
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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_ */
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 */
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
)
|
||||||
|
|||||||
@@ -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));
|
||||||
|
)
|
||||||
@@ -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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) */
|
||||||
|
|||||||
@@ -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 *)(®s.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, ®s, 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(®sPointer, &userStack[1], 4) < B_OK
|
= (uint32)(signalFrameData->syscall_restart_return_value >> 32);
|
||||||
|| user_memcpy(®s, 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 *)(®s.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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 = {};
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
Reference in New Issue
Block a user