freebsd-dev/sys/i386/include/critical.h
Matthew Dillon 182da8209d Stage-2 commit of the critical*() code. This re-inlines cpu_critical_enter()
and cpu_critical_exit() and moves associated critical prototypes into their
own header file, <arch>/<arch>/critical.h, which is only included by the
three MI source files that need it.

Backout and re-apply improperly comitted syntactical cleanups made to files
that were still under active development.  Backout improperly comitted program
structure changes that moved localized declarations to the top of two
procedures.  Partially re-apply one of the program structure changes to
move 'mask' into an intermediate block rather then in three separate
sub-blocks to make the code more readable.  Re-integrate bug fixes that Jake
made to the sparc64 code.

Note: In general, developers should not gratuitously move declarations out
of sub-blocks.  They are where they are for reasons of structure, grouping,
readability, compiler-localizability, and to avoid developer-introduced bugs
similar to several found in recent years in the VFS and VM code.

Reviewed by:	jake
2002-04-01 23:51:23 +00:00

112 lines
2.9 KiB
C

/*-
* Copyright (c) 2002 Matthew Dillon. This code is distributed under
* the BSD copyright, /usr/src/COPYRIGHT.
*
* This file contains prototypes and high-level inlines related to
* machine-level critical function support:
*
* cpu_critical_enter() - inlined
* cpu_critical_exit() - inlined
* cpu_critical_fork_exit() - prototyped
* cpu_thread_link() - prototyped
* related support functions residing
* in <arch>/<arch>/critical.c - prototyped
*
* $FreeBSD$
*/
#ifndef _MACHINE_CRITICAL_H_
#define _MACHINE_CRITICAL_H_
__BEGIN_DECLS
extern int critical_mode;
/*
* Prototypes - see <arch>/<arch>/critical.c
*/
void cpu_unpend(void);
void cpu_critical_fork_exit(void);
void cpu_thread_link(struct thread *td);
#ifdef __GNUC__
/*
* cpu_critical_enter:
*
* This routine is called from critical_enter() on the 0->1 transition
* of td_critnest, prior to it being incremented to 1.
*
* If old-style critical section handling (critical_mode == 0), we
* disable interrupts.
*
* If new-style critical section handling (criticla_mode != 0), we
* do not have to do anything. However, as a side effect any
* interrupts occuring while td_critnest is non-zero will be
* deferred.
*/
static __inline void
cpu_critical_enter(void)
{
if (critical_mode == 0) {
struct thread *td = curthread;
td->td_md.md_savecrit = intr_disable();
}
}
/*
* cpu_critical_exit:
*
* This routine is called from critical_exit() on a 1->0 transition
* of td_critnest, after it has been decremented to 0. We are
* exiting the last critical section.
*
* If td_critnest is -1 this is the 'new' critical_enter()/exit()
* code (the default critical_mode=1) and we do not have to do
* anything unless PCPU_GET(int_pending) is non-zero.
*
* Note that the td->critnest (1->0) transition interrupt race against
* our int_pending/unpend() check below is handled by the interrupt
* code for us, so we do not have to do anything fancy.
*
* Otherwise td_critnest contains the saved hardware interrupt state
* and will be restored. Since interrupts were hard-disabled there
* will be no pending interrupts to dispatch (the 'original' code).
*/
static __inline void
cpu_critical_exit(void)
{
struct thread *td = curthread;
if (td->td_md.md_savecrit != (register_t)-1) {
intr_restore(td->td_md.md_savecrit);
td->td_md.md_savecrit = (register_t)-1;
} else {
/*
* We may have to schedule pending interrupts. Create
* conditions similar to an interrupt context and call
* unpend().
*
* note: we do this even if we are in an interrupt
* nesting level. Deep nesting is protected by
* critical_*() and if we conditionalized it then we
* would have to check int_pending again whenever
* we decrement td_intr_nesting_level to 0.
*/
if (PCPU_GET(int_pending))
cpu_unpend();
}
}
#else /* !__GNUC__ */
void cpu_critical_enter(void)
void cpu_critical_exit(void)
#endif /* __GNUC__ */
__END_DECLS
#endif /* !_MACHINE_CRITICAL_H_ */