mi_switch(9): update to current day
The function itself and much of the information in this page remains relevant, but many details need to be fixed. - Update function signatures - Update the list of major uses of mi_switch() (it is not exhaustive) - Document 'flags' argument and its possible values - Document thread lock requirement for callers - Thread runtime limits are out of scope now, no need to describe them - Remove outdated information w.r.t. KSE, runqueue, non-preemptible kernel, etc - Update the description of cpu_switch() and its responsibilities PR: 149574 Reviewed by: kib Discussed with: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D38185
This commit is contained in:
parent
1029dab634
commit
175db7b582
@ -2,10 +2,14 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
|
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
|
.\" Copyright (c) 2023 The FreeBSD Foundation
|
||||||
.\"
|
.\"
|
||||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||||
.\" by Paul Kranenburg.
|
.\" by Paul Kranenburg.
|
||||||
.\"
|
.\"
|
||||||
|
.\" Portions of this documentation were written by Mitchell Horne
|
||||||
|
.\" under sponsorship from the FreeBSD Foundation.
|
||||||
|
.\"
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
.\" modification, are permitted provided that the following conditions
|
.\" modification, are permitted provided that the following conditions
|
||||||
.\" are met:
|
.\" are met:
|
||||||
@ -29,7 +33,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 24, 1996
|
.Dd January 9, 2023
|
||||||
.Dt MI_SWITCH 9
|
.Dt MI_SWITCH 9
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -41,96 +45,171 @@
|
|||||||
.In sys/param.h
|
.In sys/param.h
|
||||||
.In sys/proc.h
|
.In sys/proc.h
|
||||||
.Ft void
|
.Ft void
|
||||||
.Fn mi_switch "void"
|
.Fn mi_switch "int flags"
|
||||||
.Ft void
|
.Ft void
|
||||||
.Fn cpu_switch "void"
|
.Fn cpu_switch "struct thread *oldtd" "struct thread *newtd" "struct mtx *lock"
|
||||||
.Ft void
|
.Ft void
|
||||||
.Fn cpu_throw "void"
|
.Fn cpu_throw "struct thread *oldtd" "struct thread *newtd"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Fn mi_switch
|
.Fn mi_switch
|
||||||
function implements the machine independent prelude to a thread context
|
function implements the machine-independent prelude to a thread context
|
||||||
switch.
|
switch.
|
||||||
It is called from only a few distinguished places in the kernel
|
It is the single entry point for every context switch and is called from only
|
||||||
code as a result of the principle of non-preemptable kernel mode execution.
|
a few distinguished places in the kernel.
|
||||||
|
The context switch is, by necessity, always performed by the switched thread,
|
||||||
|
even when the switch is initiated from elsewhere; e.g. preemption requested via
|
||||||
|
Inter-Processor Interrupt (IPI).
|
||||||
|
.Pp
|
||||||
The various major uses of
|
The various major uses of
|
||||||
.Nm
|
.Fn mi_switch
|
||||||
can be enumerated as follows:
|
can be enumerated as follows:
|
||||||
.Bl -enum -offset indent
|
.Bl -enum -offset indent
|
||||||
.It
|
.It
|
||||||
From within a function such as
|
From within a function such as
|
||||||
.Xr cv_wait 9 ,
|
.Xr sleepq_wait 9
|
||||||
.Xr mtx_lock 9 ,
|
|
||||||
or
|
or
|
||||||
.Xr tsleep 9
|
.Fn turnstile_wait
|
||||||
when the current thread
|
when the current thread
|
||||||
voluntarily relinquishes the CPU to wait for some resource or lock to become
|
voluntarily relinquishes the CPU to wait for some resource or lock to become
|
||||||
available.
|
available.
|
||||||
.It
|
.It
|
||||||
After handling a trap
|
Involuntary preemption due to arrival of a higher-priority thread.
|
||||||
(e.g.\& a system call, device interrupt)
|
.It
|
||||||
when the kernel prepares a return to user-mode execution.
|
At the tail end of
|
||||||
This case is
|
.Xr critical_exit 9 ,
|
||||||
typically handled by machine dependent trap-handling code after detection
|
if preemption was deferred due to the critical section.
|
||||||
of a change in the signal disposition of the current process, or when a
|
.It
|
||||||
higher priority thread might be available to run.
|
Within the TDA_SCHED AST handler, when rescheduling before the return to
|
||||||
The latter event is
|
usermode was requested.
|
||||||
communicated by the machine independent scheduling routines by calling
|
There are several reasons for this, a notable one coming from
|
||||||
the machine defined
|
.Fn sched_clock
|
||||||
.Fn need_resched .
|
when the running thread has exceeded its time slice.
|
||||||
.It
|
.It
|
||||||
In the signal handling code
|
In the signal handling code
|
||||||
(see
|
(see
|
||||||
.Xr issignal 9 )
|
.Xr issignal 9 )
|
||||||
if a signal is delivered that causes a process to stop.
|
if a signal is delivered that causes a process to stop.
|
||||||
.It
|
.It
|
||||||
When a thread dies in
|
|
||||||
.Xr thread_exit 9
|
|
||||||
and control of the processor can be passed to the next runnable thread.
|
|
||||||
.It
|
|
||||||
In
|
In
|
||||||
.Xr thread_suspend_check 9
|
.Fn thread_suspend_check
|
||||||
where a thread needs to stop execution due to the suspension state of
|
where a thread needs to stop execution due to the suspension state of
|
||||||
the process as a whole.
|
the process as a whole.
|
||||||
|
.It
|
||||||
|
In
|
||||||
|
.Xr kern_yield 9
|
||||||
|
when a thread wants to voluntarily relinquish the processor.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
|
The
|
||||||
|
.Va flags
|
||||||
|
argument to
|
||||||
.Fn mi_switch
|
.Fn mi_switch
|
||||||
records the amount of time the current thread has been running in the
|
indicates the context switch type.
|
||||||
process structures and checks this value against the CPU time limits
|
One of the following must be passed:
|
||||||
allocated to the process
|
.Bl -tag -offset indent -width "SWT_REMOTEWAKEIDLE"
|
||||||
(see
|
.It Dv SWT_OWEPREEMPT
|
||||||
.Xr getrlimit 2 ) .
|
Switch due to delayed preemption after exiting a critical section.
|
||||||
Exceeding the soft limit results in a
|
.It Dv SWT_TURNSTILE
|
||||||
.Dv SIGXCPU
|
Switch after propagating scheduling priority to the owner of a resource.
|
||||||
signal to be posted to the process, while exceeding the hard limit will
|
.It Dv SWT_SLEEPQ
|
||||||
cause a
|
Begin waiting on a
|
||||||
.Dv SIGKILL .
|
.Xr sleepqueue 9 .
|
||||||
|
.It Dv SWT_RELINQUISH
|
||||||
|
Yield call.
|
||||||
|
.It Dv SWT_NEEDRESCHED
|
||||||
|
Rescheduling was requested.
|
||||||
|
.It Dv SWT_IDLE
|
||||||
|
Switch from the idle thread.
|
||||||
|
.It Dv SWT_IWAIT
|
||||||
|
A kernel thread which handles interrupts has finished work and must wait for
|
||||||
|
interrupts to schedule additional work.
|
||||||
|
.It Dv SWT_SUSPEND
|
||||||
|
Thread suspended.
|
||||||
|
.It Dv SWT_REMOTEPREEMPT
|
||||||
|
Preemption by a higher-priority thread, initiated by a remote processor.
|
||||||
|
.It Dv SWT_REMOTEWAKEIDLE
|
||||||
|
Idle thread preempted, initiated by a remote processor.
|
||||||
|
.It Dv SWT_BIND
|
||||||
|
The running thread has been bound to another processor and must be switched
|
||||||
|
out.
|
||||||
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
If the thread is still in the
|
In addition to the switch type, callers must specify the nature of the
|
||||||
.Dv TDS_RUNNING
|
switch by performing a bitwise OR with one of the
|
||||||
state,
|
.Dv SW_VOL
|
||||||
.Fn mi_switch
|
or
|
||||||
will put it back onto the run queue, assuming that
|
.Dv SW_INVOL
|
||||||
it will want to run again soon.
|
flags, but not both.
|
||||||
If it is in one of the other
|
Respectively, these flags denote whether the context switch is voluntary or
|
||||||
states and KSE threading is enabled, the associated
|
involuntary on the part of the current thread.
|
||||||
.Em KSE
|
For an involuntary context switch in which the running thread is
|
||||||
will be made available to any higher priority threads from the same
|
being preempted, the caller should also pass the
|
||||||
group, to allow them to be scheduled next.
|
.Dv SW_PREEMPT
|
||||||
|
flag.
|
||||||
.Pp
|
.Pp
|
||||||
After these administrative tasks are done,
|
Upon entry to
|
||||||
|
.Fn mi_switch ,
|
||||||
|
the current thread must be holding its assigned thread lock.
|
||||||
|
It may be unlocked as part of the context switch.
|
||||||
|
After they have been rescheduled and execution resumes, threads will exit
|
||||||
.Fn mi_switch
|
.Fn mi_switch
|
||||||
hands over control to the machine dependent routine
|
with their thread lock unlocked.
|
||||||
.Fn cpu_switch ,
|
.Pp
|
||||||
which will perform the actual thread context switch.
|
.Fn mi_switch
|
||||||
|
records the amount of time the current thread has been running before handing
|
||||||
|
control over to the scheduler, via
|
||||||
|
.Fn sched_switch .
|
||||||
|
After selecting a new thread to run, the scheduler will call
|
||||||
|
.Fn cpu_switch
|
||||||
|
to perform the low-level context switch.
|
||||||
.Pp
|
.Pp
|
||||||
.Fn cpu_switch
|
.Fn cpu_switch
|
||||||
first saves the context of the current thread.
|
is the machine-dependent function that performs the actual switch from the
|
||||||
Next, it calls
|
running thread
|
||||||
.Fn choosethread
|
.Fa oldtd
|
||||||
to determine which thread to run next.
|
to the chosen thread
|
||||||
Finally, it reads in the saved context of the new thread and starts to
|
.Fa newtd .
|
||||||
execute the new thread.
|
First, it saves the context of
|
||||||
|
.Fa oldtd
|
||||||
|
to its Process Control Block,
|
||||||
|
.Po
|
||||||
|
PCB
|
||||||
|
.Vt struct pcb
|
||||||
|
.Pc ,
|
||||||
|
pointed at by
|
||||||
|
.Va oldtd->td_pcb .
|
||||||
|
The function then updates important per-CPU state such as the
|
||||||
|
.Dv curthread
|
||||||
|
variable, and activates
|
||||||
|
.Fa newtd\&'s
|
||||||
|
virtual address space using its associated
|
||||||
|
.Xr pmap 9
|
||||||
|
structure.
|
||||||
|
Finally, it reads in the saved context from
|
||||||
|
.Fa newtd\&'s
|
||||||
|
PCB.
|
||||||
|
CPU instruction flow continues in the new thread context, on
|
||||||
|
.Fa newtd\&'s
|
||||||
|
kernel stack.
|
||||||
|
The return from
|
||||||
|
.Fn cpu_switch
|
||||||
|
can be understood as a completion of the function call initiated by
|
||||||
|
.Fa newtd
|
||||||
|
when it was previously switched out, at some point in the distant (relative to
|
||||||
|
CPU time) past.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
|
.Fa mtx
|
||||||
|
argument to
|
||||||
|
.Fn cpu_switch
|
||||||
|
is used to pass the mutex which will be stored as
|
||||||
|
.Fa oldtd\&'s
|
||||||
|
thread lock at the moment that
|
||||||
|
.Fa oldtd
|
||||||
|
is completely switched out.
|
||||||
|
This is an implementation detail of
|
||||||
|
.Fn sched_switch .
|
||||||
.Pp
|
.Pp
|
||||||
.Fn cpu_throw
|
.Fn cpu_throw
|
||||||
is similar to
|
is similar to
|
||||||
@ -140,19 +219,18 @@ This function is useful when the kernel does not have an old thread
|
|||||||
context to save, such as when CPUs other than the boot CPU perform their
|
context to save, such as when CPUs other than the boot CPU perform their
|
||||||
first task switch, or when the kernel does not care about the state of the
|
first task switch, or when the kernel does not care about the state of the
|
||||||
old thread, such as in
|
old thread, such as in
|
||||||
.Fn thread_exit
|
.Xr thread_exit 9
|
||||||
when the kernel terminates the current thread and switches into a new
|
when the kernel terminates the current thread and switches into a new
|
||||||
thread.
|
thread,
|
||||||
.Pp
|
.Fa newtd .
|
||||||
To protect the
|
The
|
||||||
.Xr runqueue 9 ,
|
.Fa oldtd
|
||||||
all of these functions must be called with the
|
argument is unused.
|
||||||
.Va sched_lock
|
|
||||||
mutex held.
|
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr cv_wait 9 ,
|
.Xr critical_exit 9 ,
|
||||||
.Xr issignal 9 ,
|
.Xr issignal 9 ,
|
||||||
|
.Xr kern_yield 9 ,
|
||||||
.Xr mutex 9 ,
|
.Xr mutex 9 ,
|
||||||
.Xr runqueue 9 ,
|
.Xr pmap 9 ,
|
||||||
.Xr tsleep 9 ,
|
.Xr sleepqueue 9 ,
|
||||||
.Xr wakeup 9
|
.Xr thread_exit 9
|
||||||
|
Loading…
Reference in New Issue
Block a user