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

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


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42116 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2011-06-12 00:00:23 +00:00
parent ccd31b93f1
commit 24df65921b
235 changed files with 14975 additions and 6594 deletions
+7
View File
@@ -311,6 +311,8 @@ typedef struct {
#define B_REAL_TIME_PRIORITY 120
#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
@@ -739,6 +741,11 @@ extern int32 is_computer_on(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! */
enum {
+1 -3
View File
@@ -151,7 +151,7 @@ typedef enum {
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_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_PREPARE_HANDOVER, // prepares the debugged team for being
@@ -356,7 +356,6 @@ typedef struct {
// B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER
typedef struct {
thread_id thread; // the thread
int signal; // the signal
struct sigaction handler; // the new signal handler
} debug_nub_set_signal_handler;
@@ -365,7 +364,6 @@ typedef struct {
typedef struct {
port_id reply_port; // port to send the reply to
thread_id thread; // the thread
int signal; // the signal
} debug_nub_get_signal_handler;
+7 -5
View File
@@ -90,7 +90,7 @@ typedef struct mmx_regs {
unsigned char mm7[10];
unsigned char _reserved_154_159[6];
} mmx_regs;
typedef struct xmmx_regs {
unsigned char xmm0[16];
unsigned char xmm1[16];
@@ -105,7 +105,7 @@ typedef struct xmmx_regs {
typedef struct new_extended_regs {
unsigned short fp_control;
unsigned short fp_status;
unsigned short fp_tag;
unsigned short fp_tag;
unsigned short fp_opcode;
unsigned long fp_eip;
unsigned short fp_cs;
@@ -128,7 +128,7 @@ typedef struct extended_regs {
old_extended_regs old_format;
new_extended_regs new_format;
} state;
unsigned long format;
unsigned long format;
} extended_regs;
struct vregs {
@@ -141,9 +141,11 @@ struct vregs {
unsigned long ebp;
unsigned long _reserved_1;
extended_regs xregs;
unsigned long _reserved_2[3];
unsigned long edi;
unsigned long esi;
unsigned long ebx;
};
#endif /* __INTEL__ */
#endif /* _ARCH_SIGNAL_H_ */
+6
View File
@@ -71,6 +71,12 @@
#define _POSIX_STREAM_MAX (8)
#define _POSIX_TTY_NAME_MAX (256)
#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)
+2 -59
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2010 Haiku Inc. All Rights Reserved.
* Copyright 2001-2011 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the Haiku License.
*/
#ifndef _PTHREAD_H_
@@ -8,66 +8,10 @@
#include <sched.h>
#include <stdint.h>
#include <sys/types.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_NORMAL 1
#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 int pthread_join(pthread_t thread, void **_value);
extern pthread_t pthread_self(void);
extern int pthread_kill(pthread_t thread, int sig);
extern int pthread_getconcurrency(void);
extern int pthread_setconcurrency(int newLevel);
+1 -2
View File
@@ -15,8 +15,7 @@
typedef struct __jmp_buf_tag {
__jmp_buf regs; /* saved registers, stack & program pointer */
int mask_was_saved;
sigset_t saved_mask;
sigset_t inverted_signal_mask;
} jmp_buf[1];
typedef jmp_buf sigjmp_buf;
+229 -120
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 Haiku Inc. All Rights Reserved.
* Copyright 2002-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SIGNAL_H_
@@ -10,48 +10,73 @@
typedef int sig_atomic_t;
typedef __haiku_int32 sigset_t;
typedef void (*sighandler_t)(int);
/* GNU-like signal handler typedef */
typedef void (*__signal_func_ptr)(int);
/* deprecated, for compatibility with BeOS only */
typedef __haiku_uint64 sigset_t;
/* macros defining the standard signal handling behavior */
#define SIG_DFL ((sighandler_t)0) /* "default" signal behaviour */
#define SIG_IGN ((sighandler_t)1) /* ignore signal */
#define SIG_ERR ((sighandler_t)-1) /* an error occurred during signal processing */
#define SIG_HOLD ((sighandler_t)3) /* the signal was hold */
#define SIG_DFL ((__sighandler_t)0) /* "default" signal behaviour */
#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__sighandler_t)-1) /* an error occurred during signal
processing */
#define SIG_HOLD ((__sighandler_t)3) /* the signal was hold */
/* TODO: Support this structure, or more precisely the SA_SIGINFO flag. To do
* this properly we need real-time signal support. Both are commented out for
* the time being to not make "configure" scripts think we do support them. */
#if 0
typedef struct {
int si_signo; /* signal number */
int si_code; /* signal code */
int si_errno; /* if non zero, an error number associated with this signal */
pid_t si_pid; /* sending process ID */
uid_t si_uid; /* real user ID of sending process */
void *si_addr; /* address of faulting instruction */
int si_status; /* exit value or signal */
long si_band; /* band event for SIGPOLL */
/* macros specifying the event notification type (sigevent::sigev_notify) */
#define SIGEV_NONE 0 /* no notification */
#define SIGEV_SIGNAL 1 /* notify via queued signal */
#define SIGEV_THREAD 2 /* notify via function called in new thread */
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_code; /* signal code */
int si_errno; /* if non zero, an error number associated with
this signal */
pid_t si_pid; /* sending process ID */
uid_t si_uid; /* real user ID of sending process */
void* si_addr; /* address of faulting instruction */
int si_status; /* exit value or signal */
long si_band; /* band event for SIGPOLL */
union sigval si_value; /* signal value */
} siginfo_t;
#endif /* 0 */
/*
* structure used by sigaction()
*
* Note: the 'sa_userdata' field is a non-POSIX extension.
* See the documentation for more info on this.
*/
/* signal handler function types */
typedef void (*__sighandler_t)(int);
typedef void (*__siginfo_handler_t)(int, siginfo_t*, void*);
#ifdef __USE_GNU
typedef __sighandler_t sighandler_t;
/* GNU-like signal handler typedef */
#endif
/* structure used by sigaction() */
struct sigaction {
sighandler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
void *sa_userdata; /* will be passed to the signal handler */
union {
__sighandler_t sa_handler;
__siginfo_handler_t sa_sigaction;
};
sigset_t sa_mask;
int sa_flags;
void* sa_userdata; /* will be passed to the signal
handler, BeOS extension */
};
/* values for sa_flags */
@@ -61,7 +86,7 @@ struct sigaction {
#define SA_NODEFER 0x08
#define SA_RESTART 0x10
#define SA_ONSTACK 0x20
/* #define SA_SIGINFO 0x40 */
#define SA_SIGINFO 0x40
#define SA_NOMASK SA_NODEFER
#define SA_STACK SA_ONSTACK
#define SA_ONESHOT SA_RESETHAND
@@ -73,20 +98,13 @@ struct sigaction {
#define MINSIGSTKSZ 4096
#define SIGSTKSZ 16384
/*
* for signals using an alternate stack
*/
/* for signals using an alternate stack */
typedef struct stack_t {
void *ss_sp;
void* ss_sp;
size_t ss_size;
int ss_flags;
} stack_t;
typedef struct sigstack {
int ss_onstack;
void *ss_sp;
} sigstack;
/* for the 'how' arg of sigprocmask() */
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
@@ -99,91 +117,166 @@ typedef struct sigstack {
* some consistency with UN*X conventions so that things
* like "kill -9" do what you expect.
*/
#define SIGHUP 1 /* hangup -- tty is gone! */
#define SIGINT 2 /* interrupt */
#define SIGQUIT 3 /* `quit' special character typed in tty */
#define SIGILL 4 /* illegal instruction */
#define SIGCHLD 5 /* child process exited */
#define SIGABRT 6 /* abort() called, dont' catch */
#define SIGPIPE 7 /* write to a pipe w/no readers */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill a team (not catchable) */
#define SIGSTOP 10 /* suspend a thread (not catchable) */
#define SIGSEGV 11 /* segmentation violation (read: invalid pointer) */
#define SIGCONT 12 /* continue execution if suspended */
#define SIGTSTP 13 /* `stop' special character typed in tty */
#define SIGALRM 14 /* an alarm has gone off (see alarm()) */
#define SIGTERM 15 /* termination requested */
#define SIGTTIN 16 /* read of tty from bg process */
#define SIGTTOU 17 /* write to tty from bg process */
#define SIGUSR1 18 /* app defined signal 1 */
#define SIGUSR2 19 /* app defined signal 2 */
#define SIGWINCH 20 /* tty window size changed */
#define SIGKILLTHR 21 /* be specific: kill just the thread, not team */
#define SIGTRAP 22 /* Trace/breakpoint trap */
#define SIGPOLL 23 /* Pollable event */
#define SIGPROF 24 /* Profiling timer expired */
#define SIGSYS 25 /* Bad system call */
#define SIGURG 26 /* High bandwidth data is available at socket */
#define SIGVTALRM 27 /* Virtual timer expired */
#define SIGXCPU 28 /* CPU time limit exceeded */
#define SIGXFSZ 29 /* File size limit exceeded */
#define SIGHUP 1 /* hangup -- tty is gone! */
#define SIGINT 2 /* interrupt */
#define SIGQUIT 3 /* `quit' special character typed in tty */
#define SIGILL 4 /* illegal instruction */
#define SIGCHLD 5 /* child process exited */
#define SIGABRT 6 /* abort() called, dont' catch */
#define SIGPIPE 7 /* write to a pipe w/no readers */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill a team (not catchable) */
#define SIGSTOP 10 /* suspend a thread (not catchable) */
#define SIGSEGV 11 /* segmentation violation (read: invalid pointer) */
#define SIGCONT 12 /* continue execution if suspended */
#define SIGTSTP 13 /* `stop' special character typed in tty */
#define SIGALRM 14 /* an alarm has gone off (see alarm()) */
#define SIGTERM 15 /* termination requested */
#define SIGTTIN 16 /* read of tty from bg process */
#define SIGTTOU 17 /* write to tty from bg process */
#define SIGUSR1 18 /* app defined signal 1 */
#define SIGUSR2 19 /* app defined signal 2 */
#define SIGWINCH 20 /* tty window size changed */
#define SIGKILLTHR 21 /* be specific: kill just the thread, not team */
#define SIGTRAP 22 /* Trace/breakpoint trap */
#define SIGPOLL 23 /* Pollable event */
#define SIGPROF 24 /* Profiling timer expired */
#define SIGSYS 25 /* Bad system call */
#define SIGURG 26 /* High bandwidth data is available at socket */
#define SIGVTALRM 27 /* Virtual timer expired */
#define SIGXCPU 28 /* CPU time 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 */
/*
* Signal numbers 30-32 are currently free but may be used in future
* releases. Use them at your own peril (if you do use them, at least
* be smart and use them backwards from signal 32).
*/
#define 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)
/* the number of defined signals */
#define __MAX_SIGNO 64 /* greatest possible signal number, can be used (+1)
as size of static arrays */
#define NSIG (__MAX_SIGNO + 1)
/* BSD extension, size of the sys_siglist table,
obsolete */
/* Signal code values appropriate for siginfo_t::si_code: */
/* 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 */
extern const char * const sys_siglist[NSIG];
extern const char* const sys_siglist[NSIG];
/* BSD extension, obsolete, use strsignal() instead */
#ifdef __cplusplus
extern "C" {
#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);
int siginterrupt(int sig, int flag);
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);
int sigwait(const sigset_t *set, int *sig);
/* signal management (actions and block masks) */
__sighandler_t signal(int signal, __sighandler_t signalHandler);
int sigaction(int signal, const struct sigaction* action,
struct sigaction* oldAction);
__sighandler_t sigset(int signal, __sighandler_t signalHandler);
int sigignore(int signal);
int siginterrupt(int signal, int flag);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
int sigignore(int signo);
int sighold(int signo);
int sigrelse(int signo);
int sigpause(int signo);
int sigprocmask(int how, const sigset_t* set, sigset_t* oldSet);
int pthread_sigmask(int how, const sigset_t* set, sigset_t* oldSet);
int sighold(int signal);
int sigrelse(int signal);
void set_signal_stack(void *ptr, size_t size);
int sigaltstack(const stack_t *ss, stack_t *oss);
/* sending signals */
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
}
#endif
/* TODO: move this into the documentation!
* ==================================================
* !!! 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
* enable additional data to be passed to the handler. For example:
* 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;
* char data_buffer[32];
*
* sa.sa_handler = (sighandler_t)my_signal_handler;
* sa.sa_handler = (__sighandler_t)my_signal_handler;
* sigemptyset(&sa.sa_mask);
* 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
* 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
* of the sa_handler field is defined as 'sighandler_t'. This requires the handler
* to be cast when assigned to the sa_handler field, as in the example above.
* of the sa_handler field is defined as '__sighandler_t'. This requires the
* 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:
* 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).
* The vregs struct contains the contents of the volatile registers at
* the time the signal was delivered to your thread. You can change the fields
* of the structure. After your signal handler completes, the OS uses this struct
* to reload the registers for your thread (privileged registers are not loaded
* of course). The vregs struct is of course terribly machine dependent.
* the time the signal was delivered to your thread. You can change the
* fields of the structure. After your signal handler completes, the OS uses
* this struct to reload the registers for your thread (privileged registers
* are not loaded of course). The vregs struct is of course terribly machine
* dependent.
* 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
*/
typedef struct vregs vregs;
/* BeOS extension */
/* include architecture specific definitions */
#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_ */
+64
View File
@@ -52,6 +52,70 @@ typedef char* caddr_t;
typedef __haiku_addr_t addr_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 <size_t.h>
#include <time.h>
+2 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 Haiku Inc. All Rights Reserved.
* Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYS_WAIT_H
@@ -28,16 +28,12 @@
#define WIFCORED(value) ((value) & 0x10000)
#define WIFCONTINUED(value) ((value) & 0x20000)
/* TODO: waitid() is part of the real-time signal extension. Uncomment when
* implemented! */
#if 0
/* ID types for waitid() */
typedef enum {
P_ALL, /* wait for any children, ignore ID */
P_PID, /* wait for the child whose process ID matches */
P_PGID /* wait for any child whose process group ID matches */
} idtype_t;
#endif /* 0 */
#ifdef __cplusplus
@@ -46,7 +42,7 @@ extern "C" {
extern pid_t wait(int *_status);
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
}
+35 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 Haiku Inc. All Rights Reserved.
* Copyright 2005-2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _TIME_H_
@@ -9,17 +9,33 @@
#include <sys/types.h>
struct sigevent; /* defined in <signal.h> */
typedef __haiku_int32 clock_t;
typedef __haiku_int32 time_t;
typedef __haiku_int32 suseconds_t;
typedef __haiku_uint32 useconds_t;
#define CLOCKS_PER_SEC 1000
#define CLOCKS_PER_SEC 1000000
#define CLK_TCK CLOCKS_PER_SEC
#define MAX_TIMESTR 70
/* 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 {
time_t tv_sec; /* seconds */
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);
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 */
extern void tzset(void);
+15 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 Haiku Inc. All Rights Reserved.
* Copyright 2004-2011 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _UNISTD_H_
@@ -45,9 +45,13 @@
#define _POSIX_THREAD_ATTR_STACKADDR (-1) /* currently unsupported */
#define _POSIX_THREAD_ATTR_STACKSIZE (200809L)
#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_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 */
/* BeOS supported values, do not touch */
@@ -119,6 +123,14 @@
#define _SC_THREAD_PRIORITY_SCHEDULING 50
#define _SC_REALTIME_SIGNALS 51
#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 */
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_DPC_H
#define _KERNEL_DPC_H
#include <sys/cdefs.h>
#include <KernelExport.h>
#include <util/DoublyLinkedList.h>
#include <condition_variable.h>
namespace BKernel {
class DPCQueue;
class DPCCallback : public DoublyLinkedListLinkImpl<DPCCallback> {
public:
DPCCallback();
virtual ~DPCCallback();
virtual void DoDPC(DPCQueue* queue) = 0;
private:
friend class DPCQueue;
private:
DPCQueue* fInQueue;
};
class FunctionDPCCallback : public DPCCallback {
public:
FunctionDPCCallback(DPCQueue* owner);
void SetTo(void (*function)(void*), void* argument);
virtual void DoDPC(DPCQueue* queue);
private:
DPCQueue* fOwner;
void (*fFunction)(void*);
void* fArgument;
};
class DPCQueue {
public:
DPCQueue();
~DPCQueue();
static DPCQueue* DefaultQueue(int priority);
status_t Init(const char* name, int32 priority,
uint32 reservedSlots);
void Close(bool cancelPending);
status_t Add(DPCCallback* callback,
bool schedulerLocked);
status_t Add(void (*function)(void*), void* argument,
bool schedulerLocked);
bool Cancel(DPCCallback* callback);
thread_id Thread() const
{ return fThreadID; }
public:
// conceptually package private
void Recycle(FunctionDPCCallback* callback);
private:
typedef DoublyLinkedList<DPCCallback> CallbackList;
private:
static status_t _ThreadEntry(void* data);
status_t _Thread();
bool _IsClosed() const
{ return fThreadID < 0; }
private:
spinlock fLock;
thread_id fThreadID;
CallbackList fCallbacks;
CallbackList fUnusedFunctionCallbacks;
ConditionVariable fPendingCallbacksCondition;
DPCCallback* fCallbackInProgress;
ConditionVariable* fCallbackDoneCondition;
};
} // namespace BKernel
using BKernel::DPCCallback;
using BKernel::DPCQueue;
using BKernel::FunctionDPCCallback;
__BEGIN_DECLS
void dpc_init();
__END_DECLS
#endif // _KERNEL_DPC_H
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_USER_EVENT_H
#define _KERNEL_USER_EVENT_H
#include <signal.h>
#include <SupportDefs.h>
#include <DPC.h>
#include <thread.h>
namespace BKernel {
struct Team;
struct Thread;
struct UserEvent {
virtual ~UserEvent();
virtual status_t Fire() = 0;
};
struct SignalEvent : UserEvent {
virtual ~SignalEvent();
void SetUserValue(union sigval userValue);
protected:
struct EventSignal;
protected:
SignalEvent(EventSignal* signal);
protected:
EventSignal* fSignal;
};
struct TeamSignalEvent : SignalEvent {
static TeamSignalEvent* Create(Team* team, uint32 signalNumber,
int32 signalCode, int32 errorCode);
virtual status_t Fire();
private:
TeamSignalEvent(Team* team,
EventSignal* signal);
private:
Team* fTeam;
};
struct ThreadSignalEvent : SignalEvent {
static ThreadSignalEvent* Create(Thread* thread, uint32 signalNumber,
int32 signalCode, int32 errorCode,
pid_t sendingTeam);
virtual status_t Fire();
private:
ThreadSignalEvent(Thread* thread,
EventSignal* signal);
private:
Thread* fThread;
};
struct CreateThreadEvent : UserEvent, private DPCCallback {
~CreateThreadEvent();
static CreateThreadEvent* Create(
const ThreadCreationAttributes& attributes);
virtual status_t Fire();
private:
CreateThreadEvent(
const ThreadCreationAttributes& attributes);
virtual void DoDPC(DPCQueue* queue);
private:
ThreadCreationAttributes fCreationAttributes;
char fThreadName[B_OS_NAME_LENGTH];
bool fPendingDPC;
};
} // namespace BKernel
using BKernel::CreateThreadEvent;
using BKernel::SignalEvent;
using BKernel::TeamSignalEvent;
using BKernel::ThreadSignalEvent;
using BKernel::UserEvent;
#endif // _KERNEL_USER_EVENT_H
+273
View File
@@ -0,0 +1,273 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_USER_TIMER_H
#define _KERNEL_USER_TIMER_H
#include <sys/cdefs.h>
#include <time.h>
#include <util/DoublyLinkedList.h>
#include <ksignal.h>
#include <timer.h>
#include <user_timer_defs.h>
struct thread_creation_attributes;
namespace BKernel {
struct UserEvent;
struct Team;
struct UserTimer : DoublyLinkedListLinkImpl<UserTimer> {
UserTimer();
virtual ~UserTimer();
int32 ID() const
{ return fID; }
void SetID(int32 id)
{ fID = id; }
void SetEvent(UserEvent* event)
{ fEvent = event; }
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval) = 0;
void Cancel();
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount) = 0;
protected:
static int32 HandleTimerHook(struct timer* timer);
virtual void HandleTimer();
inline void UpdatePeriodicStartTime();
inline void CheckPeriodicOverrun(bigtime_t now);
protected:
int32 fID;
timer fTimer;
UserEvent* fEvent;
bigtime_t fNextTime;
bigtime_t fInterval;
uint32 fOverrunCount;
bool fScheduled; // fTimer scheduled
};
struct SystemTimeUserTimer : public UserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
protected:
virtual void HandleTimer();
void ScheduleKernelTimer(bigtime_t now,
bool checkPeriodicOverrun);
};
struct RealTimeUserTimer : public SystemTimeUserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
void TimeWarped();
private:
bigtime_t fRealTimeOffset;
bool fAbsolute;
protected:
virtual void HandleTimer();
public:
// conceptually package private
DoublyLinkedListLink<RealTimeUserTimer> fGlobalListLink;
};
struct TeamTimeUserTimer : public UserTimer {
TeamTimeUserTimer(team_id teamID);
~TeamTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Update(Thread* unscheduledThread);
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
void _Update(bool unscheduling);
private:
team_id fTeamID;
Team* fTeam;
int32 fRunningThreads;
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<TeamTimeUserTimer> fCPUTimeListLink;
};
struct TeamUserTimeUserTimer : public UserTimer {
TeamUserTimeUserTimer(team_id teamID);
~TeamUserTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Check();
private:
team_id fTeamID;
Team* fTeam;
public:
// conceptually package private
DoublyLinkedListLink<TeamUserTimeUserTimer> fCPUTimeListLink;
};
struct ThreadTimeUserTimer : public UserTimer {
ThreadTimeUserTimer(thread_id threadID);
~ThreadTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Start();
void Stop();
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
thread_id fThreadID;
Thread* fThread; // != NULL only when active
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<ThreadTimeUserTimer> fCPUTimeListLink;
};
struct UserTimerList {
UserTimerList();
~UserTimerList();
UserTimer* TimerFor(int32 id) const;
void AddTimer(UserTimer* timer);
void RemoveTimer(UserTimer* timer)
{ fTimers.Remove(timer); }
int32 DeleteTimers(bool userDefinedOnly);
private:
typedef DoublyLinkedList<UserTimer> TimerList;
private:
TimerList fTimers;
};
typedef DoublyLinkedList<RealTimeUserTimer,
DoublyLinkedListMemberGetLink<RealTimeUserTimer,
&RealTimeUserTimer::fGlobalListLink> > RealTimeUserTimerList;
typedef DoublyLinkedList<TeamTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamTimeUserTimer,
&TeamTimeUserTimer::fCPUTimeListLink> > TeamTimeUserTimerList;
typedef DoublyLinkedList<TeamUserTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamUserTimeUserTimer,
&TeamUserTimeUserTimer::fCPUTimeListLink> > TeamUserTimeUserTimerList;
typedef DoublyLinkedList<ThreadTimeUserTimer,
DoublyLinkedListMemberGetLink<ThreadTimeUserTimer,
&ThreadTimeUserTimer::fCPUTimeListLink> > ThreadTimeUserTimerList;
} // namespace BKernel
using BKernel::RealTimeUserTimer;
using BKernel::RealTimeUserTimerList;
using BKernel::SystemTimeUserTimer;
using BKernel::TeamUserTimeUserTimer;
using BKernel::TeamUserTimeUserTimerList;
using BKernel::TeamTimeUserTimer;
using BKernel::TeamTimeUserTimerList;
using BKernel::ThreadTimeUserTimer;
using BKernel::ThreadTimeUserTimerList;
using BKernel::UserTimer;
using BKernel::UserTimerList;
__BEGIN_DECLS
status_t user_timer_create_thread_timers(Team* team, Thread* thread);
status_t user_timer_create_team_timers(Team* team);
status_t user_timer_get_clock(clockid_t clockID, bigtime_t& _time);
void user_timer_real_time_clock_changed();
void user_timer_stop_cpu_timers(Thread* thread, Thread* nextThread);
void user_timer_continue_cpu_timers(Thread* thread,
Thread* previousThread);
void user_timer_check_team_user_timers(Team* team);
status_t _user_get_clock(clockid_t clockID, bigtime_t* _time);
status_t _user_set_clock(clockid_t clockID, bigtime_t time);
int32 _user_create_timer(clockid_t clockID, thread_id threadID,
uint32 flags, const struct sigevent* event,
const thread_creation_attributes* threadAttributes);
status_t _user_delete_timer(int32 timerID, thread_id threadID);
status_t _user_get_timer(int32 timerID, thread_id threadID,
struct user_timer_info* info);
status_t _user_set_timer(int32 timerID, thread_id threadID,
bigtime_t startTime, bigtime_t interval, uint32 flags,
struct user_timer_info* oldInfo);
__END_DECLS
#endif // _KERNEL_USER_TIMER_H
+5 -5
View File
@@ -21,16 +21,16 @@ status_t arch_team_init_team_struct(Team *t, bool kernel);
status_t arch_thread_init_thread_struct(Thread *t);
status_t arch_thread_init_tls(Thread *thread);
void arch_thread_context_switch(Thread *t_from, Thread *t_to);
status_t arch_thread_init_kthread_stack(Thread *t,
int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void));
void arch_thread_init_kthread_stack(Thread *thread, void *stack,
void *stackTop, void (*function)(void*), const void *data);
void arch_thread_dump_info(void *info);
status_t arch_thread_enter_userspace(Thread *t, addr_t entry,
void *args1, void *args2);
bool arch_on_signal_stack(Thread *thread);
status_t arch_setup_signal_frame(Thread *t, struct sigaction *sa,
int signal, int signalMask);
int64 arch_restore_signal_frame(void);
status_t arch_setup_signal_frame(Thread *thread, struct sigaction *action,
struct signal_frame_data *signalFrameData);
int64 arch_restore_signal_frame(struct signal_frame_data* signalFrameData);
void arch_store_fork_frame(struct arch_fork_arg *arg);
void arch_restore_fork_frame(struct arch_fork_arg *arg);
+26 -1
View File
@@ -95,6 +95,32 @@
#define IA32_MTR_WRITE_BACK 6
// 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
#define IFRAME_TYPE_SYSCALL 0x1
#define IFRAME_TYPE_OTHER 0x2
@@ -276,7 +302,6 @@ void x86_context_switch(struct arch_thread* oldState,
struct arch_thread* newState);
void x86_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 i386_set_tss_and_kstack(addr_t kstack);
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 i386_return_from_signal();
void i386_end_return_from_signal();
// override empty macro
#undef arch_syscall_64_bit_return_value
void arch_syscall_64_bit_return_value(void);
+10 -10
View File
@@ -56,18 +56,18 @@ public:
void Publish(const void* object,
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);
inline void NotifyAll(bool threadsLocked = false,
inline void NotifyAll(bool schedulerLocked = false,
status_t result = B_OK);
static void NotifyOne(const void* object,
bool threadsLocked = false,
bool schedulerLocked = false,
status_t result = B_OK);
static void NotifyAll(const void* object,
bool threadsLocked = false,
bool schedulerLocked = false,
status_t result = B_OK);
// (both methods) caller must ensure that
// the variable is not unpublished
@@ -86,7 +86,7 @@ public:
void Dump() const;
private:
void _Notify(bool all, bool threadsLocked,
void _Notify(bool all, bool schedulerLocked,
status_t result);
void _NotifyLocked(bool all, status_t result);
@@ -124,16 +124,16 @@ ConditionVariableEntry::~ConditionVariableEntry()
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
ConditionVariable::NotifyAll(bool threadsLocked, status_t result)
ConditionVariable::NotifyAll(bool schedulerLocked, status_t result)
{
_Notify(true, threadsLocked, result);
_Notify(true, schedulerLocked, result);
}
+1
View File
@@ -51,6 +51,7 @@ typedef struct cpu_ent {
jmp_buf fault_jump_buffer;
Thread* running_thread;
Thread* previous_thread;
bool invoke_scheduler;
bool invoke_scheduler_if_idle;
bool disabled;
+7
View File
@@ -16,6 +16,12 @@
struct kernel_args;
struct elf_symbol_info {
addr_t address;
size_t size;
};
#ifdef __cplusplus
extern "C" {
#endif
@@ -34,6 +40,7 @@ status_t elf_debug_lookup_user_symbol_address(Team* team, addr_t address,
addr_t *_baseAddress, const char **_symbolName,
const char **_imageName, bool *_exactMatch);
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();
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,
+50 -16
View File
@@ -18,27 +18,59 @@ struct SchedulerListener;
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);
/*! 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);
/*! 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);
bigtime_t (*estimate_max_scheduling_latency)(Thread* thread);
void (*on_thread_create)(Thread* thread);
// called when the thread structure is first created -
// initialization of per-thread housekeeping data structures should
// be done here
void (*on_thread_init)(Thread* thread);
// 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 the Thread structure is first created.
Per-thread housekeeping resources can be allocated.
Interrupts must be enabled.
*/
status_t (*on_thread_create)(Thread* thread, bool idleThread);
/*! 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);
};
extern struct scheduler_ops* gScheduler;
extern spinlock gSchedulerLock;
#define scheduler_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)
#define scheduler_reschedule() gScheduler->reschedule()
#define scheduler_start() gScheduler->start()
#define scheduler_on_thread_create(thread) \
gScheduler->on_thread_create(thread)
#define scheduler_on_thread_create(thread, idleThread) \
gScheduler->on_thread_create(thread, idleThread)
#define scheduler_on_thread_init(thread) \
gScheduler->on_thread_init(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.
The thread spinlock must be held.
The caller must hold the scheduler lock (with disabled interrupts).
*/
static inline void
scheduler_reschedule_if_necessary_locked()
@@ -91,9 +123,11 @@ scheduler_reschedule_if_necessary()
{
if (are_interrupts_enabled()) {
cpu_status state = disable_interrupts();
GRAB_THREAD_LOCK();
acquire_spinlock(&gSchedulerLock);
scheduler_reschedule_if_necessary_locked();
RELEASE_THREAD_LOCK();
release_spinlock(&gSchedulerLock);
restore_interrupts(state);
}
}
+207 -24
View File
@@ -1,57 +1,240 @@
/*
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de.
* All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_SIGNAL_H
#define _KERNEL_SIGNAL_H
#include <KernelExport.h>
#include <signal.h>
#include <KernelExport.h>
#include <signal_defs.h>
#include <heap.h>
#include <util/DoublyLinkedList.h>
#include <util/KernelReferenceable.h>
namespace BKernel {
struct ProcessGroup;
struct Team;
struct Thread;
}
using BKernel::ProcessGroup;
using BKernel::Team;
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
#define SIGNAL_FLAG_TEAMS_LOCKED (0x10000)
// interrupts are disabled and team lock is held
#define SIGNAL_FLAG_DONT_RESTART_SYSCALL (0x20000)
// kernel-internal signals
#define SIGNAL_CANCEL_THREAD 63
// Cancel a thread. Non-blockable.
#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
extern "C" {
#endif
extern bool handle_signals(Thread *thread);
extern bool is_kill_signal_pending(void);
extern int has_signals_pending(void *_thread);
extern bool is_signal_blocked(int signal);
void handle_signals(Thread* thread);
bool is_team_signal_blocked(Team* team, int signal);
void signal_get_user_stack(addr_t address, stack_t* stack);
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,
const struct sigaction *newAction, struct sigaction *oldAction);
status_t send_signal_to_team_locked(Team* team, uint32 signalNumber,
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);
extern status_t _user_sigprocmask(int how, const sigset_t *set,
sigset_t *oldSet);
extern status_t _user_sigaction(int sig, const struct sigaction *newAction,
status_t send_signal_to_process_group_locked(ProcessGroup* group,
const Signal& signal, uint32 flags);
status_t send_signal_to_process_group(pid_t groupID, const Signal& signal,
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);
extern bigtime_t _user_set_alarm(bigtime_t time, uint32 mode);
extern status_t _user_sigwait(const sigset_t *set, int *_signal);
extern status_t _user_sigsuspend(const sigset_t *mask);
extern status_t _user_sigpending(sigset_t *set);
extern status_t _user_set_signal_stack(const stack_t *newUserStack,
bigtime_t _user_set_alarm(bigtime_t time, uint32 mode);
status_t _user_sigwait(const sigset_t *set, siginfo_t *info, uint32 flags,
bigtime_t timeout);
status_t _user_sigsuspend(const sigset_t *mask);
status_t _user_sigpending(sigset_t *set);
status_t _user_set_signal_stack(const stack_t *newUserStack,
stack_t *oldUserStack);
int64 _user_restore_signal_frame(struct signal_frame_data* signalFrameData);
#ifdef __cplusplus
}
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
* 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_with_timeout(rw_lock* lock,
uint32 timeoutFlags, bigtime_t timeout);
extern void _rw_lock_read_unlock(rw_lock* lock, bool threadsLocked);
extern void _rw_lock_write_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 schedulerLocked);
extern status_t _mutex_lock(mutex* lock, bool threadsLocked);
extern void _mutex_unlock(mutex* lock, bool threadsLocked);
extern status_t _mutex_lock(mutex* lock, bool schedulerLocked);
extern void _mutex_unlock(mutex* lock, bool schedulerLocked);
extern status_t _mutex_trylock(mutex* lock);
extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
bigtime_t timeout);
+3 -1
View File
@@ -22,6 +22,8 @@ struct kernel_args;
extern "C" {
#endif
void set_real_time_clock_usecs(bigtime_t currentTime);
status_t rtc_init(struct kernel_args *args);
bigtime_t rtc_boot_time(void);
// 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);
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,
size_t nameLength);
status_t _user_get_timezone(int32 *_timezoneOffset, char* name,
+7 -13
View File
@@ -22,12 +22,11 @@ extern "C" {
status_t team_init(struct kernel_args *args);
status_t 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);
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_id team_get_kernel_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_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,
const char* const* env, int32 priority, team_id parentID, uint32 flags);
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);
int32 team_get_controlling_tty();
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);
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_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);
void _user_exit_team(status_t returnValue);
status_t _user_kill_team(thread_id thread);
thread_id _user_wait_for_child(thread_id child, uint32 flags, int32 *_reason,
status_t *_returnCode);
pid_t _user_wait_for_child(thread_id child, uint32 flags, siginfo_t* info);
status_t _user_exec(const char *path, const char* const* flatArgs,
size_t flatArgsSize, int32 argCount, int32 envCount, mode_t umask);
thread_id _user_fork(void);
+235 -23
View File
@@ -19,6 +19,7 @@
#include <ksignal.h>
struct arch_fork_arg;
struct kernel_args;
struct select_info;
struct thread_creation_attributes;
@@ -31,6 +32,43 @@ struct thread_creation_attributes;
#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
extern "C" {
#endif
@@ -61,9 +99,6 @@ void thread_set_io_priority(int32 priority);
#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 inline thread_id
thread_get_current_thread_id(void)
@@ -75,18 +110,21 @@ thread_get_current_thread_id(void)
static inline bool
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* thread_iterate_through_threads(thread_iterator_callback callback,
void* cookie);
thread_id allocate_thread_id();
thread_id peek_next_thread_id();
thread_id allocate_thread_id(void);
thread_id peek_next_thread_id(void);
status_t thread_enter_userspace_new_team(Thread* thread, addr_t entryFunction,
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,
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 *_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_locked(uint32 timeoutFlags,
bigtime_t timeout);
void thread_unblock(status_t threadID, status_t status);
// used in syscalls.c
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);
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_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_cancel_thread(thread_id threadID, void (*cancelFunction)(int));
void _user_thread_yield(void);
void _user_exit_thread(status_t return_value);
bool _user_has_data(thread_id thread);
@@ -135,20 +174,41 @@ int _user_setrlimit(int resource, const struct rlimit * rlp);
#endif
/*!
\a thread must be the current thread.
Thread lock can be, but doesn't need to be held.
/*! Checks whether the current thread would immediately be interrupted when
blocking it with the given wait/interrupt flags.
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
thread_is_interrupted(Thread* thread, uint32 flags)
{
return ((flags & B_CAN_INTERRUPT)
&& (thread->sig_pending & ~thread->sig_block_mask) != 0)
|| ((flags & B_KILL_CAN_INTERRUPT)
&& (thread->sig_pending & KILL_SIGNALS));
sigset_t pendingSignals = thread->AllPendingSignals();
return ((flags & B_CAN_INTERRUPT) != 0
&& (pendingSignals & ~thread->sig_block_mask) != 0)
|| ((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
thread_is_blocked(Thread* thread)
{
@@ -156,9 +216,109 @@ thread_is_blocked(Thread* thread)
}
/*!
\a thread must be the current thread.
Thread lock can be, but doesn't need to be locked.
/*! Prepares the current thread for waiting.
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
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
thread_block_locked(Thread* thread)
{
if (thread->wait.status == 1) {
// check for signals, if interruptable
// check for signals, if interruptible
if (thread_is_interrupted(thread, thread->wait.flags)) {
thread->wait.status = B_INTERRUPTED;
} 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
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
thread_interrupt(Thread* thread, bool kill)
{
+505 -104
View File
@@ -10,30 +10,23 @@
#ifndef _ASSEMBLER
#include <Referenceable.h>
#include <pthread.h>
#include <arch/thread_types.h>
#include <condition_variable.h>
#include <heap.h>
#include <ksignal.h>
#include <lock.h>
#include <signal.h>
#include <smp.h>
#include <thread_defs.h>
#include <timer.h>
#include <UserTimer.h>
#include <user_debugger.h>
#include <util/DoublyLinkedList.h>
#include <util/KernelReferenceable.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 {
THREAD_STATE_FREE_ON_RESCHED = 7, // free the thread structure upon reschedule
// THREAD_STATE_BIRTH // thread is being created
@@ -43,9 +36,11 @@ enum additional_thread_state {
#define THREAD_MAX_SET_PRIORITY B_REAL_TIME_PRIORITY
enum team_state {
TEAM_STATE_NORMAL, // normal state
TEAM_STATE_BIRTH, // being contructed
TEAM_STATE_DEATH // being killed
TEAM_STATE_NORMAL, // normal state
TEAM_STATE_BIRTH, // being constructed
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
@@ -71,33 +66,14 @@ struct xsi_sem_context; // defined in xsi_semaphore.cpp
namespace BKernel {
struct Team;
struct Thread;
struct ProcessGroup;
}
struct death_entry {
struct thread_death_entry {
struct list_link link;
pid_t group_id;
thread_id thread;
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 {
@@ -122,7 +98,9 @@ struct team_watcher {
struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> {
job_control_state state; // current team job control state
thread_id thread; // main thread ID == team ID
uint16 signal; // signal causing the current state
bool has_group_ref;
uid_t signaling_user;
// valid while state != JOB_CONTROL_STATE_DEAD
BKernel::Team* team;
@@ -130,8 +108,8 @@ struct job_control_entry : DoublyLinkedListLinkImpl<job_control_entry> {
// valid when state == JOB_CONTROL_STATE_DEAD
pid_t group_id;
status_t status;
uint16 reason;
uint16 signal;
uint16 reason; // reason for the team's demise, one of the
// CLD_* values defined in <signal.h>
job_control_entry();
~job_control_entry();
@@ -215,41 +193,67 @@ typedef bool (*page_fault_callback)(addr_t address, addr_t faultAddress,
namespace BKernel {
struct Team : AssociatedDataOwner {
Team *next; // next in hash
Team *siblings_next;
Team *parent;
Team *children;
Team *group_next;
team_id id;
template<typename IDType>
struct TeamThreadIteratorEntry
: DoublyLinkedListLinkImpl<TeamThreadIteratorEntry<IDType> > {
typedef IDType id_type;
typedef TeamThreadIteratorEntry<id_type> iterator_type;
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 session_id;
struct process_group *group;
char name[B_OS_NAME_LENGTH];
char args[64]; // contents for the team_info::args field
ProcessGroup *group;
int num_threads; // number of threads in this team
int state; // current team state, see above
int32 flags;
struct io_context *io_context;
struct realtime_sem_context *realtime_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;
int dead_threads_count;
// protected by the team's fLock
team_dead_children dead_children;
team_job_control_children stopped_children;
team_job_control_children continued_children;
// protected by the parent team's fLock
struct job_control_entry* job_control_entry;
VMAddressSpace *address_space;
Thread *main_thread;
Thread *thread_list;
struct team_loading_info *loading_info;
struct list image_list;
Thread *main_thread; // protected by fLock and the scheduler
// lock (and the thread's lock), immutable
// after first set
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 sem_list;
struct list port_list;
struct list sem_list; // protected by sSemsSpinlock
struct list port_list; // protected by sPortsLock
struct arch_team arch_info;
addr_t user_data;
@@ -260,9 +264,13 @@ struct Team : AssociatedDataOwner {
struct team_debug_info debug_info;
// protected by scheduler lock
bigtime_t dead_threads_kernel_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 real_uid;
uid_t effective_uid;
@@ -271,44 +279,181 @@ struct Team : AssociatedDataOwner {
gid_t effective_gid;
gid_t* supplementary_groups;
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
// handlers (signals pending, user debugging
// enabled, etc.)
Thread *all_next;
Thread *team_next;
Thread *queue_next; /* i.e. run queue, release queue, etc. */
timer alarm;
thread_id id;
char name[B_OS_NAME_LENGTH];
int32 priority;
int32 next_priority;
int32 io_priority;
int32 state;
int32 next_state;
struct cpu_ent *cpu;
struct cpu_ent *previous_cpu;
int32 pinned_to_cpu;
int64 serial_number; // immutable after adding thread to hash
Thread *hash_next; // protected by thread hash lock
Thread *team_next; // protected by team lock and fLock
Thread *queue_next; // protected by scheduler lock
timer alarm; // protected by scheduler lock
char name[B_OS_NAME_LENGTH]; // protected by fLock
int32 priority; // protected by scheduler lock
int32 next_priority; // protected by scheduler lock
int32 io_priority; // protected by fLock
int32 state; // protected by scheduler lock
int32 next_state; // protected by scheduler lock
struct cpu_ent *cpu; // protected by scheduler lock
struct cpu_ent *previous_cpu; // protected by scheduler lock
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;
sigset_t sig_temp_enabled;
struct sigaction sig_action[32];
addr_t signal_stack_base;
size_t signal_stack_size;
bool signal_stack_enabled;
sigset_t sig_block_mask; // protected by scheduler lock,
// only modified by the thread itself
sigset_t sigsuspend_original_unblocked_mask;
// non-0 after a return from _user_sigsuspend(), containing the inverted
// original signal mask, reset in handle_signals(); only accessed by
// this thread
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 was_yielded;
struct scheduler_thread_data* scheduler_data;
bool in_kernel; // protected by time_lock, only written by
// this thread
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 {
uint8 parameters[32];
uint8 parameters[SYSCALL_RESTART_PARAMETER_SIZE];
} syscall_restart;
struct {
@@ -322,13 +467,15 @@ struct Thread {
struct PrivateConditionVariableEntry *condition_variable_entry;
struct {
sem_id write_sem;
sem_id read_sem;
sem_id write_sem; // acquired by writers before writing
sem_id read_sem; // release by writers after writing, acquired
// by this thread when reading
thread_id sender;
int32 code;
size_t size;
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 {
addr_t fault_handler;
@@ -340,50 +487,304 @@ struct Thread {
int32 page_faults_allowed;
/* this field may only stay in debug builds in the future */
thread_entry_func entry;
void *args1, *args2;
BKernel::Team *team;
BKernel::Team *team; // protected by team lock, thread lock, scheduler
// lock
struct {
sem_id sem;
status_t status;
uint16 reason;
uint16 signal;
struct list waiters;
sem_id sem; // immutable after thread creation
status_t status; // accessed only by this thread
struct list waiters; // protected by fLock
} exit;
struct select_info *select_infos;
struct select_info *select_infos; // protected by fLock
struct thread_debug_info debug_info;
// stack
area_id kernel_stack_area;
addr_t kernel_stack_base;
addr_t kernel_stack_top;
area_id user_stack_area;
addr_t user_stack_base;
size_t user_stack_size;
area_id kernel_stack_area; // immutable after thread creation
addr_t kernel_stack_base; // immutable after thread creation
addr_t kernel_stack_top; // immutable after thread creation
area_id user_stack_area; // protected by thread lock
addr_t user_stack_base; // protected by thread lock
size_t user_stack_size; // protected by thread lock
addr_t user_local_storage;
// usually allocated at the safe side of the stack
int kernel_errno;
// kernel "errno" differs from its userspace alter ego
bigtime_t user_time;
bigtime_t kernel_time;
bigtime_t last_time;
// user_time, kernel_time, and last_time are only written by the thread
// itself, so they can be read by the thread without lock. Holding the
// 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_data;
// architecture dependant section
// architecture dependent section
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
using BKernel::Team;
using BKernel::TeamListIterator;
using BKernel::Thread;
using BKernel::ThreadListIterator;
using BKernel::ProcessSession;
using BKernel::ProcessGroup;
using BKernel::ProcessGroupList;
struct thread_queue {
+18 -3
View File
@@ -1,4 +1,4 @@
/*
/*
** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
@@ -15,8 +15,21 @@ extern "C" {
struct kernel_args;
#define B_TIMER_ACQUIRE_THREAD_LOCK 0x8000
#define B_TIMER_FLAGS B_TIMER_ACQUIRE_THREAD_LOCK
#define B_TIMER_REAL_TIME_BASE 0x2000
// 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 */
struct timer_info {
@@ -32,6 +45,8 @@ typedef struct timer_info timer_info;
/* kernel functions */
status_t timer_init(struct kernel_args *);
void timer_init_post_rtc(void);
void timer_real_time_clock_changed();
int32 timer_interrupt(void);
#ifdef __cplusplus
+41 -19
View File
@@ -36,25 +36,26 @@ using BKernel::Thread;
//
// Locking policy:
// 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
// acquire the global team lock, or one accesses the structure from a thread
// of that team.
// (i.e. the struct Team it lives in) isn't deleted. Thus one either needs to
// get a team reference, lock the team, or one accesses the structure from a
// thread of that team.
// 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' 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
// 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 {
spinlock 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;
// Set atomically. So reading atomically is OK, even when the team
// lock is not held (at least if it is certain, that the team struct
// won't go).
// Set atomically. So reading atomically is OK, even when the lock is
// not held (at least if it is certain, that the team struct won't go).
team_id debugger_team;
port_id debugger_port;
@@ -71,12 +72,13 @@ struct team_debug_info {
// counter incremented whenever an image is created/deleted
struct ConditionVariable* debugger_changed_condition;
// Set whenever someone is going (or planning) to change the debugger.
// If one wants to do the same, one has to wait for this condition.
// Both threads lock (outer) and team debug info lock (inner) have to
// be held when accessing this field. After setting to a condition
// variable the thread won't be deleted (until unsetting it) -- it might
// be removed from the team hash table, though.
// Set to a condition variable when going to change the debugger. Anyone
// who wants to change the debugger as well, needs to wait until the
// condition variable is unset again (waiting for the condition and
// rechecking again). The field and the condition variable is protected
// by 'lock'. After setting the a condition variable the team is
// guaranteed not to be deleted (until it is unset) it might be removed
// from the team hash table, though.
struct BreakpointManager* breakpoint_manager;
// manages hard- and software breakpoints
@@ -84,11 +86,31 @@ struct team_debug_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 {
spinlock lock;
// Guards the remaining fields. Should always be the innermost lock
// to be acquired/released.
int32 flags;
// Set atomically. So reading atomically is OK, even when the thread
// lock is not held (at least if it is certain, that the thread struct
// won't go).
// Set atomically. So reading atomically is OK, even when the lock is
// not held (at least if it is certain, that the thread struct won't
// go).
port_id debug_port;
// 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_deleted(team_id teamID, port_id debuggerPort);
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_deleted(team_id teamID, thread_id threadID);
void user_debug_thread_exiting(Thread* thread);
-1
View File
@@ -25,7 +25,6 @@ extern "C" {
// kernel private functions
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);
// syscalls
+7
View File
@@ -177,6 +177,10 @@ public:
typedef AutoLocker<Thread, ThreadCPUPinLocking> ThreadCPUPinner;
typedef AutoLocker<Team> TeamLocker;
typedef AutoLocker<Thread> ThreadLocker;
} // namespace BPrivate
using BPrivate::AutoLocker;
@@ -188,5 +192,8 @@ using BPrivate::InterruptsLocker;
using BPrivate::SpinLocker;
using BPrivate::InterruptsSpinLocker;
using BPrivate::ThreadCPUPinner;
using BPrivate::TeamLocker;
using BPrivate::ThreadLocker;
#endif // KERNEL_UTIL_AUTO_LOCKER_H
@@ -0,0 +1,29 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_UTIL_KERNEL_REFERENCEABLE_H
#define _KERNEL_UTIL_KERNEL_REFERENCEABLE_H
#include <Referenceable.h>
#include <heap.h>
namespace BKernel {
struct KernelReferenceable : BReferenceable, DeferredDeletable {
protected:
virtual void LastReferenceReleased();
};
} // namespace BKernel
using BKernel::KernelReferenceable;
#endif /* _KERNEL_UTIL_KERNEL_REFERENCEABLE_H */
+1 -2
View File
@@ -37,12 +37,11 @@ void __init_heap_post_env(void);
void __init_time(void);
void __arch_init_time(struct real_time_data *data, bool setDefaults);
bigtime_t __arch_get_system_time_offset(struct real_time_data *data);
bigtime_t __get_system_time_offset();
void __init_pwd_backend(void);
void __reinit_pwd_backend_after_fork(void);
void* __arch_get_caller(void);
void __init_pthread(void);
#ifdef __cplusplus
}
+18 -4
View File
@@ -11,6 +11,17 @@
#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
// This way, we are completely free to change them, which might be
// necessary in the future (not only due to the incomplete implementation
@@ -55,9 +66,6 @@ typedef struct _pthread_thread {
void *(*entry)(void*);
void *entry_argument;
void *exit_value;
int cancel_state;
int cancel_type;
bool cancelled;
struct pthread_key_data specific[PTHREAD_KEYS_MAX];
struct __pthread_cleanup_handler *cleanup_handlers;
} pthread_thread;
@@ -69,7 +77,13 @@ extern "C" {
void __pthread_key_call_destructors(pthread_thread *thread);
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
}
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_SIGNAL_PRIVATE_H
#define _LIBROOT_SIGNAL_PRIVATE_H
#include <signal.h>
#include <sys/cdefs.h>
#include <signal_defs.h>
#define MAX_SIGNAL_NUMBER_BEOS 29
typedef __haiku_int32 sigset_t_beos;
struct sigaction_beos {
__sighandler_t sa_handler;
sigset_t_beos sa_mask;
int sa_flags;
void* sa_userdata;
};
static inline sigset_t_beos
to_beos_sigset(sigset_t set)
{
// restrict to BeOS signals
sigset_t_beos beosSet = (sigset_t_beos)(set
& SIGNAL_RANGE_TO_MASK(1, MAX_SIGNAL_NUMBER_BEOS));
// if SIGBUS is set, set SIGSEGV, since they have the same number in BeOS
if ((set & SIGNAL_TO_MASK(SIGBUS)) != 0)
beosSet |= SIGNAL_TO_MASK(SIGSEGV);
return beosSet;
}
static inline sigset_t
from_beos_sigset(sigset_t_beos beosSet)
{
sigset_t set = beosSet;
// if SIGSEGV is set, set SIGBUS, since they have the same number in BeOS
if ((set & SIGNAL_TO_MASK(SIGSEGV)) != 0)
set |= SIGNAL_TO_MASK(SIGBUS);
return set;
}
__BEGIN_DECLS
__sighandler_t __signal_beos(int signal, __sighandler_t signalHandler);
__sighandler_t __signal(int signal, __sighandler_t signalHandler);
int __sigaction_beos(int signal, const struct sigaction_beos* beosAction,
struct sigaction_beos* beosOldAction);
int __sigaction(int signal, const struct sigaction* action,
struct sigaction* oldAction);
__sighandler_t __sigset_beos(int signal, __sighandler_t signalHandler);
__sighandler_t __sigset(int signal, __sighandler_t signalHandler);
int __sigignore_beos(int signal);
int __sigignore(int signal);
int __sighold_beos(int signal);
int __sighold(int signal);
int __sigrelse_beos(int signal);
int __sigrelse(int signal);
int __sigpause_beos(int signal);
int __sigpause(int signal);
int __siginterrupt_beos(int signal, int flag);
int __siginterrupt(int signal, int flag);
int __pthread_sigmask_beos(int how, const sigset_t_beos* beosSet,
sigset_t_beos* beosOldSet);
int __sigprocmask_beos(int how, const sigset_t_beos* beosSet,
sigset_t_beos* beosOldSet);
int __pthread_sigmask(int how, const sigset_t* set, sigset_t* oldSet);
int __sigprocmask(int how, const sigset_t* set, sigset_t* oldSet);
int __sigpending_beos(sigset_t_beos* beosSet);
int __sigpending(sigset_t* set);
int __sigsuspend_beos(const sigset_t_beos* beosMask);
int __sigsuspend(const sigset_t* mask);
int __sigwait_beos(const sigset_t_beos* beosSet, int* _signal);
int __sigwait(const sigset_t* set, int* _signal);
int __sigemptyset_beos(sigset_t_beos* set);
int __sigfillset_beos(sigset_t_beos* set);
int __sigismember_beos(const sigset_t_beos* set, int signal);
int __sigaddset_beos(sigset_t_beos* set, int signal);
int __sigdelset_beos(sigset_t_beos* set, int signal);
int __sigemptyset(sigset_t* set);
int __sigfillset(sigset_t* set);
int __sigismember(const sigset_t* set, int signal);
int __sigaddset(sigset_t* set, int signal);
int __sigdelset(sigset_t* set, int signal);
__END_DECLS
#endif // _LIBROOT_SIGNAL_PRIVATE_H
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_TIME_PRIVATE_H
#define _LIBROOT_TIME_PRIVATE_H
#include <errno.h>
#include <sys/cdefs.h>
#include <sys/time.h>
#include <time.h>
#include <SupportDefs.h>
#include <new>
#define CLOCKS_PER_SEC_BEOS 1000
#define CLK_TCK_BEOS CLOCKS_PER_SEC_BEOS
#define MICROSECONDS_PER_CLOCK_TICK (1000000 / CLOCKS_PER_SEC)
#define MICROSECONDS_PER_CLOCK_TICK_BEOS (1000000 / CLOCKS_PER_SEC_BEOS)
struct __timer_t {
int32 id;
thread_id thread;
void SetTo(int32 id, thread_id thread)
{
this->id = id;
this->thread = thread;
}
};
static inline void
bigtime_to_timespec(bigtime_t time, timespec& spec)
{
spec.tv_sec = time / 1000000;
spec.tv_nsec = (time % 1000000) * 1000;
}
static inline bool
timespec_to_bigtime(const timespec& spec, bigtime_t& _time)
{
if (spec.tv_sec < 0 || spec.tv_nsec < 0 || spec.tv_nsec >= 1000000000)
return false;
_time = (bigtime_t)spec.tv_sec * 1000000 + (spec.tv_nsec + 999) / 1000;
return true;
}
static inline bool
timeval_to_timespec(const timeval& val, timespec& spec)
{
if (val.tv_sec < 0 || val.tv_usec < 0 || val.tv_usec >= 1000000)
return false;
spec.tv_sec = val.tv_sec;
spec.tv_nsec = val.tv_usec * 1000;
return true;
}
static inline void
timespec_to_timeval(const timespec& spec, timeval& val)
{
val.tv_sec = spec.tv_sec;
val.tv_usec = spec.tv_nsec / 1000;
}
__BEGIN_DECLS
clock_t __clock_beos(void);
clock_t __clock(void);
__END_DECLS
#endif // _LIBROOT_TIME_PRIVATE_H
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_TIMES_PRIVATE_H
#define _LIBROOT_TIMES_PRIVATE_H
#include <sys/cdefs.h>
#include <sys/times.h>
__BEGIN_DECLS
clock_t __times_beos(struct tms* tms);
clock_t __times(struct tms* tms);
__END_DECLS
#endif // _LIBROOT_TIMES_PRIVATE_H
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _LIBROOT_UNISTD_PRIVATE_H
#define _LIBROOT_UNISTD_PRIVATE_H
#include <sys/cdefs.h>
#include <sys/times.h>
__BEGIN_DECLS
long __sysconf_beos(int name);
long __sysconf(int name);
__END_DECLS
#endif // _LIBROOT_UNISTD_PRIVATE_H
+26 -6
View File
@@ -1,18 +1,38 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSCALL_UTILS_H
#define _SYSCALL_UTILS_H
#define RETURN_AND_SET_ERRNO(err) \
do { \
__typeof(err) raseResult = (err); \
if (raseResult < 0) { \
errno = raseResult; \
__typeof(err) __result = (err); \
if (__result < 0) { \
errno = __result; \
return -1; \
} \
return raseResult; \
} while (false)
return __result; \
} 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
@@ -12,6 +12,10 @@
#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_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)
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_SIGNAL_DEFS_H
#define _SYSTEM_SIGNAL_DEFS_H
#include <signal.h>
#include <unistd.h>
// The total number of signals a process may have queued at receivers at any
// time.
#define MAX_QUEUED_SIGNALS _POSIX_SIGQUEUE_MAX
// realtime signal number range
#define SIGNAL_REALTIME_MIN 33
#define SIGNAL_REALTIME_MAX 40
// greatest actually supported signal number
#define MAX_SIGNAL_NUMBER SIGNAL_REALTIME_MAX
// additional send_signal_etc() flags
#define SIGNAL_FLAG_QUEUING_REQUIRED (0x10000)
// force signal queuing, i.e. fail instead of falling back to unqueued
// signals, when queuing isn't possible
#define SIGNAL_FLAG_SEND_TO_THREAD (0x20000)
// interpret the the given ID as a thread_id rather than a team_id (syscall
// use only)
// additional sigaction::sa_flags flag
#define SA_BEOS_COMPATIBLE_HANDLER 0x80000000
// BeOS compatible signal handler, i.e. the vregs argument is passed
// per-value, not per-pointer
#define SIGNAL_TO_MASK(signal) ((sigset_t)1 << ((signal) - 1))
#define SIGNAL_RANGE_TO_MASK(first, last) \
((((SIGNAL_TO_MASK(last) - 1) << 1) | 1) & ~(SIGNAL_TO_MASK(first) - 1))
// Note: The last mask computation looks that way to avoid an overflow for
// last == 64.
#endif /* _SYSTEM_SIGNAL_DEFS_H */
+31 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010, Haiku Inc. All rights reserved.
* Copyright 2004-2011, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_SYSCALLS_H
@@ -35,8 +35,10 @@ struct _sem_t;
struct sembuf;
union semun;
struct sigaction;
struct signal_frame_data;
struct stat;
struct system_profiler_parameters;
struct user_timer_info;
struct disk_device_job_progress_info;
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 team_id _kern_get_current_team();
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,
int32 *_reason, status_t *_returnCode);
extern pid_t _kern_wait_for_child(thread_id child, uint32 flags,
siginfo_t* info);
extern status_t _kern_exec(const char *path, const char* const* flatArgs,
size_t flatArgsSize, int32 argCount, int32 envCount,
mode_t umask);
@@ -155,6 +157,8 @@ extern status_t _kern_set_thread_priority(thread_id thread,
int32 newPriority);
extern status_t _kern_kill_thread(thread_id thread);
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 status_t _kern_wait_for_thread(thread_id thread,
status_t *_returnCode);
@@ -163,7 +167,8 @@ extern status_t _kern_send_data(thread_id thread, int32 code,
const void *buffer, size_t bufferSize);
extern int32 _kern_receive_data(thread_id *_sender, void *buffer,
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_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);
// signal functions
extern status_t _kern_send_signal(pid_t tid, uint sig);
extern status_t _kern_sigprocmask(int how, const sigset_t *set,
extern status_t _kern_send_signal(int32 id, uint32 signal,
const union sigval* userValue, uint32 flags);
extern status_t _kern_set_signal_mask(int how, const sigset_t *set,
sigset_t *oldSet);
extern status_t _kern_sigaction(int sig, const struct sigaction *action,
struct sigaction *oldAction);
extern bigtime_t _kern_set_alarm(bigtime_t time, uint32 mode);
extern status_t _kern_sigwait(const sigset_t *set, int *_signal);
extern status_t _kern_sigwait(const sigset_t *set, siginfo_t *info,
uint32 flags, bigtime_t timeout);
extern status_t _kern_sigsuspend(const sigset_t *mask);
extern status_t _kern_sigpending(sigset_t *set);
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);
// 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,
size_t nameLength);
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_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 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
extern area_id _kern_create_area(const char *name, void **address,
+12 -11
View File
@@ -1,18 +1,16 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_THREAD_DEFS_H
#define _SYSTEM_THREAD_DEFS_H
#include <pthread.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 */
#define USER_STACK_GUARD_PAGES 4 // 16 kB
#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 {
int32 (*entry)(thread_func, void *);
int32 (*entry)(void*, void*);
const char* name;
int32 priority;
void* args1;
void* args2;
void* stack_address;
size_t stack_size;
// when calling from kernel only
team_id team;
thread_id thread;
pthread_t pthread;
uint32 flags;
};
#endif /* _SYSTEM_THREAD_DEFS_H */
-1
View File
@@ -19,7 +19,6 @@ enum {
TLS_ERRNO_SLOT,
TLS_ON_EXIT_THREAD_SLOT,
TLS_USER_THREAD_SLOT,
TLS_PTHREAD_SLOT,
// Note: these entries can safely be changed between
// releases; 3rd party code always calls tls_allocate()
+9 -3
View File
@@ -1,18 +1,24 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_USER_THREAD_DEFS_H
#define _SYSTEM_USER_THREAD_DEFS_H
#include <pthread.h>
#include <signal.h>
#include <SupportDefs.h>
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
uint32 pending_signals; // signals that are pending, when
sigset_t pending_signals; // signals that are pending, when
// signals are deferred
status_t wait_status;
};
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_USER_TIMER_DEFS_H
#define _SYSTEM_USER_TIMER_DEFS_H
#include <limits.h>
#include <time.h>
#include <SupportDefs.h>
#define CLOCK_PROCESS_USER_CPUTIME_ID ((clockid_t)-4)
/* clock measuring the used user CPU time of the current process */
// limits
#define MAX_USER_TIMERS_PER_TEAM _POSIX_TIMER_MAX
// maximum numbers of user-defined user timers (timer_create())
#define MAX_USER_TIMER_OVERRUN_COUNT INT_MAX
// cap value of a timer's overrun counter
#if MAX_USER_TIMER_OVERRUN_COUNT < _POSIX_DELAYTIMER_MAX
# error "MAX_USER_TIMER_OVERRUN_COUNT < _POSIX_DELAYTIMER_MAX"
#endif
#define USER_TIMER_REAL_TIME_ID 0
// predefined ID for the real time timer
#define USER_TIMER_TEAM_TOTAL_TIME_ID 1
// predefined ID for the team's total (kernel + user) time timer
#define USER_TIMER_TEAM_USER_TIME_ID 2
// predefined ID for the team's user time timer
#define USER_TIMER_FIRST_USER_DEFINED_ID 3
// first ID assigned to a user-defined timer (timer_create())
// _kern_create_user_timer() flag:
#define USER_TIMER_SIGNAL_THREAD 0x01
// send the signal to the thread instead of the team (valid only for thread
// timers)
struct user_timer_info {
bigtime_t remaining_time;
bigtime_t interval;
uint32 overrun_count;
};
#endif /* _SYSTEM_USER_TIMER_DEFS_H */