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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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_ */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user