Source to osfmk/kern/thread.h
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* @OSF_FREE_COPYRIGHT@
*/
/*
* Mach Operating System
* Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or [email protected]
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
*/
/*
* File: thread.h
* Author: Avadis Tevanian, Jr.
*
* This file contains the structure definitions for threads.
*
*/
/*
* Copyright (c) 1993 The University of Utah and
* the Computer Systems Laboratory (CSL). All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
* IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
* ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* CSL requests users of this software to return to [email protected] any
* improvements that they make and grant CSL redistribution rights.
*
*/
#ifndef _KERN_THREAD_H_
#define _KERN_THREAD_H_
#include <mach/kern_return.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/boolean.h>
#include <mach/vm_types.h>
#include <mach/vm_prot.h>
#include <mach/thread_info.h>
#include <mach/thread_status.h>
#include <kern/cpu_data.h> /* for current_thread */
#include <kern/kern_types.h>
/*
* Logically, a thread of control consists of two parts:
* a thread_shuttle, which may migrate during an RPC, and
* a thread_activation, which remains attached to a task.
* The thread_shuttle is the larger portion of the two-part thread,
* and contains scheduling info, messaging support, accounting info,
* and links to the thread_activation within which the shuttle is
* currently operating.
*
* It might make sense to have the thread_shuttle be a proper sub-structure
* of the thread, with the thread containing links to both the shuttle and
* activation. In order to reduce the scope and complexity of source
* changes and the overhead of maintaining these linkages, we have subsumed
* the shuttle into the thread, calling it a thread_shuttle.
*
* User accesses to threads always come in via the user's thread port,
* which gets translated to a pointer to the target thread_activation.
* Kernel accesses intended to effect the entire thread, typically use
* a pointer to the thread_shuttle (current_thread()) as the target of
* their operations. This makes sense given that we have subsumed the
* shuttle into the thread_shuttle, eliminating one set of linkages.
* Operations effecting only the shuttle may use a thread_shuttle_t
* to indicate this.
*
* The current_act() macro returns a pointer to the current thread_act, while
* the current_thread() macro returns a pointer to the currently active
* thread_shuttle (representing the thread in its entirety).
*/
/*
* Possible results of thread_block - returned in
* current_thread()->wait_result.
*/
#define THREAD_AWAKENED 0 /* normal wakeup */
#define THREAD_TIMED_OUT 1 /* timeout expired */
#define THREAD_INTERRUPTED 2 /* interrupted by clear_wait */
#define THREAD_RESTART 3 /* restart operation entirely */
/*
* Interruptible flags for assert_wait
*
*/
#define THREAD_UNINT 0 /* not interruptible */
#define THREAD_INTERRUPTIBLE 1 /* may not be restartable */
#define THREAD_ABORTSAFE 2 /* abortable safely */
#ifdef MACH_KERNEL_PRIVATE
#include <cpus.h>
#include <hw_footprint.h>
#include <mach_host.h>
#include <mach_prof.h>
#include <dipc.h>
#include <xkmachkernel.h>
#include <mach_lock_mon.h>
#include <mach_ldebug.h>
#include <mach/port.h>
#include <kern/ast.h>
#include <kern/cpu_number.h>
#include <kern/queue.h>
#include <kern/time_out.h>
#include <kern/timer.h>
#include <kern/lock.h>
#include <kern/sched.h>
#include <kern/sched_prim.h>
#include <kern/thread_pool.h>
#include <kern/thread_call.h>
#include <kern/thread_call_private.h>
#include <kern/task.h>
#include <ipc/ipc_kmsg.h>
#include <machine/thread.h>
typedef struct thread_shuttle {
/*
* Beginning of thread_shuttle proper. When the thread is on
* a wait queue, these three fields are in treated as an un-
* official union with a wait_queue_element. If you change
* these, you must change that definition as well.
*/
queue_chain_t links; /* current run/wait queue links */
run_queue_t runq; /* run queue p is on SEE BELOW */
int whichq; /* which queue level p is on */
/*
* NOTE: The runq field in the thread structure has an unusual
* locking protocol. If its value is RUN_QUEUE_NULL, then it is
* locked by the thread_lock, but if its value is something else
* (i.e. a run_queue) then it is locked by that run_queue's lock.
*/
/* Thread bookkeeping */
queue_chain_t pset_threads; /* list of all shuttles in proc set */
/* Self-preservation */
decl_simple_lock_data(,lock) /* scheduling lock (thread_lock()) */
decl_simple_lock_data(,wake_lock) /* covers wake_active (wake_lock())*/
decl_mutex_data(,rpc_lock) /* RPC lock (rpc_lock()) */
int ref_count; /* number of references to me */
vm_offset_t kernel_stack; /* accurate only if the thread is
not swapped and not executing */
vm_offset_t stack_privilege;/* reserved kernel stack */
/* Blocking information */
int reason; /* why we blocked */
event_t wait_event; /* event we are waiting on */
kern_return_t wait_result; /* outcome of wait -
may be examined by this thread
WITHOUT locking */
wait_queue_t wait_queue; /* wait queue we are currently on */
queue_chain_t wait_link; /* event's wait queue link */
boolean_t wake_active; /* Someone is waiting for this
thread to become suspended */
int state; /* Thread state: */
boolean_t preempt; /* Thread is undergoing preemption */
#if ETAP_EVENT_MONITOR
int etap_reason; /* real reason why we blocked */
boolean_t etap_trace; /* ETAP trace status */
#endif /* ETAP_EVENT_MONITOR */
/*
* Thread states [bits or'ed]
*/
#define TH_WAIT 0x01 /* thread is queued for waiting */
#define TH_SUSP 0x02 /* thread has been asked to stop */
#define TH_RUN 0x04 /* thread is running or on runq */
#define TH_UNINT 0x08 /* thread is waiting uninteruptibly */
#define TH_HALTED 0x10 /* thread is halted at clean point ? */
#define TH_ABORT 0x20 /* abort interruptible waits */
#define TH_SWAPPED_OUT 0x40 /* thread is swapped out */
#define TH_IDLE 0x80 /* thread is an idle thread */
#define TH_SCHED_STATE (TH_WAIT|TH_SUSP|TH_RUN|TH_UNINT)
#define TH_STACK_HANDOFF 0x0100 /* thread has no kernel stack */
#define TH_STACK_COMING_IN 0x0200 /* thread is waiting for kernel stack */
#define TH_STACK_STATE (TH_STACK_HANDOFF | TH_STACK_COMING_IN)
#define TH_TERMINATE 0x400 /* thread is terminating */
#if 0 /* Grenoble version */
int preempt; /* Thread preemption status */
#define TH_PREEMPTABLE 0 /* Thread is preemptable */
#define TH_NOT_PREEMPTABLE 1 /* Thread is not preemptable */
#define TH_PREEMPTED 2 /* Thread has been preempted */
#if ETAP_EVENT_MONITOR
int etap_reason; /* real reason why we blocked */
boolean_t etap_trace; /* ETAP trace status */
#endif /* ETAP_EVENT_MONITOR */
#endif
/* Stack handoff information */
void (*continuation)(/* start here next time runnable */
void);
int cont_arg; /* continuation argument */
/* Scheduling information */
int policy; /* scheduling policy */
sp_info_t sp_info; /* policy-specific information */
int pending_policy; /* pending scheduling policy */
sp_attributes_t pending_sched_attr;
/* policy-specific information */
kern_return_t change_sfr; /* return value for pending change */
int sched_pri; /* scheduled (computed) priority */
unsigned int sleep_stamp; /* last time in TH_WAIT state */
#if 0 /* Grenoble */
unsigned int sched_change_stamp;
/* last time priority or policy was
explicitly changed (not the same
units as sched_stamp!) */
int unconsumed_quantum; /* leftover quantum (RR/FIFO) */
#endif
/* VM global variables */
boolean_t vm_privilege; /* can use reserved memory? */
vm_offset_t recover; /* page fault recovery (copyin/out) */
/* IPC data structures */
struct ipc_kmsg_queue ith_messages;
mach_port_t ith_mig_reply; /* reply port for mig */
mach_port_t ith_rpc_reply; /* reply port for kernel RPCs */
/* Various bits of stashed state */
union {
struct {
mach_msg_return_t state; /* receive state */
mach_msg_size_t msize; /* max size for recvd msg */
struct ipc_kmsg *kmsg; /* received message */
mach_port_seqno_t seqno; /* seqno of recvd message */
mach_msg_option_t option;
mach_msg_body_t *scatter_list;
mach_msg_size_t scatter_list_size;
} receive;
char *other; /* catch-all for other state */
} saved;
/* Timing data structures */
timer_data_t user_timer; /* user mode timer */
timer_data_t system_timer; /* system mode timer */
timer_data_t depressed_timer;/* depressed priority timer */
timer_save_data_t user_timer_save; /* saved user timer value */
timer_save_data_t system_timer_save; /* saved sys timer val. */
/*** ??? should the next two fields be moved to SP-specific struct?***/
unsigned int cpu_delta; /* cpu usage since last update */
unsigned int sched_delta; /* weighted cpu usage since update */
/* Timers for time-outs */
thread_call_data_t wait_timer;
boolean_t wait_timer_is_set;
thread_call_data_t depress_timer;
/* Ast/Halt data structures */
boolean_t active; /* how alive is the thread */
/* Processor data structures */
processor_set_t processor_set; /* assigned processor set */
#if NCPUS > 1
processor_t bound_processor; /* bound to processor ?*/
#endif /* NCPUS > 1 */
#if MACH_HOST
boolean_t may_assign; /* may assignment change? */
boolean_t assign_active; /* someone waiting for may_assign */
#endif /* MACH_HOST */
#if XKMACHKERNEL
int xk_type;
#endif /* XKMACHKERNEL */
#if NCPUS > 1
processor_t last_processor; /* processor this last ran on */
#if MACH_LOCK_MON
unsigned lock_stack; /* number of locks held */
#endif /* MACH_LOCK_MON */
#endif /* NCPUS > 1 */
int at_safe_point; /* thread_abort_safely allowed */
int funnel_state;
#define TH_FN_OWNED 0x1 /* we own the funnel lock */
#define TH_FN_REFUNNEL 0x2 /* must reaquire funnel lock when unblocking */
#if MACH_LDEBUG
/*
* Debugging: track acquired mutexes and locks.
* Because a thread can block while holding such
* synchronizers, we think of the thread as
* "owning" them.
*/
#define MUTEX_STACK_DEPTH 20
#define LOCK_STACK_DEPTH 20
mutex_t *mutex_stack[MUTEX_STACK_DEPTH];
lock_t *lock_stack[LOCK_STACK_DEPTH];
unsigned int mutex_stack_index;
unsigned int lock_stack_index;
unsigned mutex_count; /* XXX to be deleted XXX */
boolean_t kthread; /* thread is a kernel thread */
#endif /* MACH_LDEBUG */
/*
* End of thread_shuttle proper
*/
/*
* Migration and thread_activation linkage information
*/
struct thread_activation *top_act; /* "current" thr_act */
} Thread_Shuttle;
#define THREAD_SHUTTLE_NULL ((thread_shuttle_t)0)
#define ith_state saved.receive.state
#define ith_msize saved.receive.msize
#define ith_kmsg saved.receive.kmsg
#define ith_seqno saved.receive.seqno
#define ith_option saved.receive.option
#define ith_scatter_list saved.receive.scatter_list
#define ith_scatter_list_size saved.receive.scatter_list_size
#define ith_other saved.other
extern thread_act_t active_kloaded[NCPUS]; /* "" kernel-loaded acts */
extern vm_offset_t active_stacks[NCPUS]; /* active kernel stacks */
extern vm_offset_t kernel_stack[NCPUS];
decl_mutex_data(extern,funnel_lock);
#ifndef MACHINE_STACK_STASH
/*
* MD Macro to fill up global stack state,
* keeping the MD structure sizes + games private
*/
#define MACHINE_STACK_STASH(stack) \
MACRO_BEGIN \
mp_disable_preemption(); \
active_stacks[cpu_number()] = (stack); \
kernel_stack[cpu_number()] = (stack) + KERNEL_STACK_SIZE; \
mp_enable_preemption(); \
MACRO_END
#endif /* MACHINE_STACK_STASH */
/*
* Kernel-only routines
*/
/* Initialize thread module */
extern void thread_init(void);
/* Take reference on thread (make sure it doesn't go away) */
extern void thread_reference(
thread_t thread);
/* Release reference on thread */
extern void thread_deallocate(
thread_t thread);
/* Set priority of calling thread */
extern void thread_set_own_priority(
int priority);
/* Reset thread's priority */
extern kern_return_t thread_priority(
thread_act_t thr_act,
int priority,
boolean_t set_max);
/* Reset thread's max priority */
extern kern_return_t thread_max_priority(
thread_act_t thr_act,
processor_set_t pset,
int max_priority);
/* Reset thread's max priority while holding RPC locks */
extern kern_return_t thread_max_priority_locked(
thread_t thread,
processor_set_t pset,
int max_priority);
/* Set a thread's priority while holding RPC locks */
extern kern_return_t thread_priority_locked(
thread_t thread,
int priority,
boolean_t set_max);
/* Start a thread at specified routine */
#define thread_start(thread, start) \
(thread)->continuation = (start)
/* Reaps threads waiting to be destroyed */
extern void thread_reaper(void);
extern boolean_t thread_not_preemptable(
thread_t thread);
#if MACH_HOST
/* Preclude thread processor set assignement */
extern void thread_freeze(
thread_t thread);
/* Assign thread to a processor set */
extern void thread_doassign(
thread_t thread,
processor_set_t new_pset,
boolean_t release_freeze);
/* Allow thread processor set assignement */
extern void thread_unfreeze(
thread_t thread);
#endif /* MACH_HOST */
/* Insure thread always has a kernel stack */
extern void stack_privilege(
thread_t thread);
extern void consider_thread_collect(void);
/*
* Arguments to specify aggressiveness to thread halt.
* Can't have MUST_HALT and SAFELY at the same time.
*/
#define THREAD_HALT_NORMAL 0
#define THREAD_HALT_MUST_HALT 1 /* no deadlock checks */
#define THREAD_HALT_SAFELY 2 /* result must be restartable */
/*
* Macro-defined routines
*/
#define thread_pcb(th) ((th)->pcb)
#define thread_lock_init(th) \
simple_lock_init(&(th)->lock, ETAP_THREAD_LOCK)
#define thread_lock(th) simple_lock(&(th)->lock)
#define thread_unlock(th) simple_unlock(&(th)->lock)
#define thread_should_halt_fast(thread) \
(!(thread)->top_act || \
!(thread)->top_act->active || \
(thread)->top_act->ast & (AST_HALT|AST_TERMINATE))
#define thread_should_halt(thread) thread_should_halt_fast(thread)
#if 0 /* Gernoble */
/*
* We consider a thread not preemptable if it is marked as either
* suspended, waiting or halted.
* XXX - when scheduling framework and such is done, the
* thread state check can be eliminated
*/
#define thread_not_preemptable(thread) \
(((thread)->state & (TH_WAIT|TH_SUSP)) != 0)
#endif
#define thread_lock_pair(ta,tb) \
MACRO_BEGIN \
if ((ta) < (tb)) { \
thread_lock(ta); \
thread_lock(tb); \
} \
else { \
thread_lock(tb); \
thread_lock(ta); \
} \
MACRO_END
#define thread_unlock_pair(ta,tb) \
MACRO_BEGIN \
if ((ta) < (tb)) { \
thread_unlock(tb); \
thread_unlock(ta); \
} \
else { \
thread_unlock(ta); \
thread_unlock (tb); \
} \
MACRO_END
#define rpc_lock_init(th) mutex_init(&(th)->rpc_lock, ETAP_THREAD_RPC)
#define rpc_lock(th) mutex_lock(&(th)->rpc_lock)
#define rpc_lock_try(th) mutex_try(&(th)->rpc_lock)
#define rpc_unlock(th) mutex_unlock(&(th)->rpc_lock)
/*
* Lock to cover wake_active only; like thread_lock(), is taken
* at splsched(). Used to avoid calling into scheduler with a
* thread_lock() held. Precedes thread_lock() (and other scheduling-
* related locks) in the system lock ordering.
*/
#define wake_lock_init(th) \
simple_lock_init(&(th)->wake_lock, ETAP_THREAD_WAKE)
#define wake_lock(th) simple_lock(&(th)->wake_lock)
#define wake_unlock(th) simple_unlock(&(th)->wake_lock)
static __inline__ vm_offset_t current_stack(void);
static __inline__ vm_offset_t
current_stack(void)
{
vm_offset_t ret;
mp_disable_preemption();
ret = active_stacks[cpu_number()];
mp_enable_preemption();
return ret;
}
extern void pcb_module_init(void);
extern void pcb_init(
thread_act_t thr_act);
extern void pcb_terminate(
thread_act_t thr_act);
extern void pcb_collect(
thread_act_t thr_act);
extern void pcb_user_to_kernel(
thread_act_t thr_act);
extern kern_return_t thread_setstatus(
thread_act_t thr_act,
int flavor,
thread_state_t tstate,
mach_msg_type_number_t count);
extern kern_return_t thread_getstatus(
thread_act_t thr_act,
int flavor,
thread_state_t tstate,
mach_msg_type_number_t *count);
extern boolean_t stack_alloc_try(
thread_t thread,
void (*continuation)(void));
/* This routine now used only internally */
extern kern_return_t thread_info_shuttle(
thread_act_t thr_act,
thread_flavor_t flavor,
thread_info_t thread_info_out,
mach_msg_type_number_t *thread_info_count);
extern void thread_user_to_kernel(
thread_t thread);
/* Machine-dependent routines */
extern void thread_machine_init(void);
extern void thread_machine_set_current(
thread_t thread );
extern kern_return_t thread_machine_create(
thread_t thread,
thread_act_t thr_act,
void (*start_pos)(void));
extern void thread_set_syscall_return(
thread_t thread,
kern_return_t retval);
extern void thread_machine_destroy(
thread_t thread );
extern void thread_machine_flush(
thread_act_t thr_act);
extern thread_t kernel_thread_with_attributes(
task_t task,
sp_attributes_t attributes,
void (*start_at)(void),
boolean_t start_running);
#else /* !MACH_KERNEL_PRIVATE */
extern boolean_t thread_should_halt(thread_t);
#endif /* !MACH_KERNEL_PRIVATE */
extern thread_t kernel_thread(
task_t task,
void (*start)(void));
extern void thread_terminate_self(void);
extern boolean_t thread_get_funneled(void);
extern boolean_t thread_set_funneled(
boolean_t funneled);
extern void thread_set_cont_arg(int);
extern int thread_get_cont_arg(void);
/* JMM - These are only temporary */
extern boolean_t is_thread_running(thread_t); /* True is TH_RUN */
extern boolean_t is_thread_idle(thread_t); /* True is TH_IDLE */
extern event_t get_thread_waitevent(thread_t);
extern kern_return_t get_thread_waitresult(thread_t);
#endif /* _KERN_THREAD_H_ */