Subject: SMP API things, take 2
To: None <tech-smp@netbsd.org>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: tech-smp
Date: 07/29/1999 13:08:22
The following is an update to my previous message. Note that some of
these things have already been committed to NetBSD-current.
The major change here is the auto-spl simplelock support (which I have
working on the i386, and the changes for all the other ports are coming
along...)
-- Jason R. Thorpe <thorpej@nas.nasa.gov>
The following is to propose some basic API components necessary
for multiprocessor support in the NetBSD kernel.
IMPORTANT NOTE
--------------
Some people have suggested that a data type `cpuid_t' be introduced to
hold CPU identifiers. After some consideration, I have concluded that
the type `unsigned long' is preferable for the following reasons:
Machine-independent code may wish to print out the value of
a CPU identifier. Therefore a type with a well-defined printf
format should be used.
The `unsigned long' type is the size of a register on all current
ILP32 and LP64 platforms supported by NetBSD. Therefore, this
type is safe to use for this purpose on all platforms.
HEADER FILES
------------
API components will be defined in <machine/cpu.h> and by <machine/lock.h>.
The <machine/lock.h> header will be included by <sys/lock.h> only if the
CPP symbol MULTIPROCESSOR is defined.
FUNCTIONS AND MACROS
--------------------
The following functions or macros will be exported by <machine/cpu.h>:
u_long cpu_number(void);
MANDATORY
This function, inline function, or macro returns the
CPU identifier of the currently-running CPU. If the
system does not support multiple processors, or the
kernel is built without support for multiple processors,
this value should return a constant, unspecified value.
struct cpu_info *curcpu(void);
only if MULTIPROCESSOR
This function, inline function, or macro returns the
CPU identifier of the currently-running CPU. See below
for information about the cpu_info structure.
int cpu_lock_spl(int);
MANDATORY
This function, inline function, or macro performs
the appropriate spl*() operation according to
the provided LK_SPL_* token (see below). Its return
value will be passed to splx().
XXX Should be in <machine/intr.h>.
The following macros will be exported by <machine/cpu.h>:
LK_SPL_NONE
MANDATORY
This macro is an integer constant representing that
no raising of interrupt priority is necessary when
asserting the lock.
The following are mandatory integer constants representing
that interrupt priority should be raised to the specified
level when asserting the lock:
LK_SPL_SOFTNET splsoftnet()
LK_SPL_BIO splbio()
LK_SPL_NET splnet()
LK_SPL_TTY spltty()
LK_SPL_IMP splimp()
LK_SPL_CLOCK splclock()
LK_SPL_STATCLOCK splstatclock()
LK_SPL_HIGH splhigh()
The following are mandatory if the associated spl*() function
is defined for the platform:
LK_SPL_AUDIO splaudio()
LK_SPL_SERIAL splserial()
LK_SPL_SOFTSERIAL splsoftserial()
XXX Should be in <machine/intr.h>
The following macros may be exported by <machine/lock.h>:
SIMPLELOCK_LOCKED
OPTIONAL
This macro is an integer constant representing the
value the `lock_data' member of `struct simplelock'
will hold while the simple lock is locked. If
this is not defined, <sys/lock.h> will define it
to the value 1.
SIMPLELOCK_UNLOCKED
OPTIONAL
This macro is an integer constant representing the
value the `lock_data' member of `struct simplelock'
will hold while the simple lock is unlocked. If
this is not defined, <sys/lock.h> will define it
to the value 0.
The following functions or macros will be exported by <machine/lock.h>:
void cpu_simple_lock_init(__volatile struct simplelock *alp);
MANDATORY
This function, inline function, or macro initializes
the `lock_data' member of `struct simplelock' to the
value SIMPLELOCK_UNLOCKED.
void cpu_simple_lock(__volatile struct simplelock *alp);
MANDATORY
This function, inline function, or macro acquires
the specified simple lock by performing the following
operations in an atomic manner:
while (alp->lock_data != SIMPLELOCK_UNLOCKED)
/* spin */;
alp->lock_data = SIMPLELOCK_LOCKED;
int cpu_simple_lock_try(__volatile struct simplelock *alp);
MANDATORY
This function, inline function, or macro attempts to
acquire the specified simple lock by performing the
following operations in an atomic manner:
if (alp->lock_data != SIMPLELOCK_UNLOCKED)
return (0);
else {
alp->lock_data = SIMPLELOCK_LOCKED;
return (1);
}
void cpu_simple_unlock(__volatile struct simplelock *alp);
MANDATORY
This function, inline function, or macro releases
a previously acquired simple lock by performing
the following operation:
alp->lock_data = SIMPLELOCK_UNLOCKED;
DATA STRUCTURES
---------------
The following data structures will be exported by <machine/cpu.h>:
struct cpu_info;
only if MULTIPROCESSOR
This structure will always export the following members:
- struct proc *ci_curproc: current process on this processor
- struct simplelock ci_slock: simple lock for cpu_info
structure. Note that use of this lock must remain
untracked in the case of lock debugging. While this
lock is held, all interrupts MUST be blocked, as this
lock may be asserted from an interrupt context.
- u_long ci_cpuid: CPU identifier of associated CPU
This structure will export the following members if
the DIAGNOSTIC or LOCKDEBUG CPP symbols are defined:
- u_long ci_spin_locks: number of spin locks held
by this processor
- u_long ci_simple_locks: number of simple locks held
by this processor
The cpu_info structure will be referenced in <sys/proc.h>
by the following code block:
#if defined(MULTIPROCESSOR)
#define curproc curcpu()->ci_curproc
#else
extern struct proc *curproc;
#endif