This renames back scheduler implementation functions to their old names,
i.e., the same name as the interface functions, in the source code,
while providing the infrastructure to still produce from them C symbols
namespaced by the scheduler implementation, in order to avoid symbol
collisions with interface dispatching functions and other scheduler
implementations when multiple ones are compiled in. In a nutshell, the
implementation consists in re-routing interface names to implementation
names via the C preprocessor.
The main reasons for this change are that different implementation names:
- Prevented inlining opportunities in internal scheduler code. The only way to regain them without this change would have been to further clutter the existing code (changing calls to use the scheduler-specific names), and would have imposed again the discipline of specifying implementation names in new calls instead of the well-known and shorter interface names.
- Broke navigating code with ctags-like tools like Global.
- Introduced undesirable churn and cognitive burden, in particular in the form of having to ask oneself whether internal scheduler functions should be namespaced or not, and which are their real names when using them.
However, C symbol collisions create difficulties with debugging and ELF
manipulation tools, including when printing backtraces (which scheduler
implementation is in use?). For example, as of this writing,
'disassemble' in GDB will choose one of the existing functions and
disassemble it without mentioning the existing others; our ddb(4) will
set a breakpoint on one of these functions only (which should be
improved); etc. So keeping namespaced symbol names was desirable, which
is why symbol re-routing via the C preprocessor was chosen.
The implementation of the machinery to substitute interface names by
implementation names has two parts.
First, a new generated per-implementation-specific header has to be
included in each implementation ("sched_<NAME>_ns.h"). It contains
simple C preprocessor substitutions, such as, taking the example of ULE:
#define sched_clock sched_ule_clock
#define sched_switch sched_ule_switch
allowing to use the interface names in place of the implementation names
in the implementation itself. It also checks that an implementation
actually defined SCHED_IMPLEMENTATION and to the same value that was
used to produce it.
These headers are generated from the pattern header
'sys/kern/sched_ns.h' through directives in 'sys/conf/files', via the
C preprocessor using the already existing X macros and some light
post-processing by the new 'sys/tools/sched_impl_ns.awk' script.
Second, <sys/sched.h> declares all implementation functions when
included from an implementation, so that out-of-order references within
the implementation do not cause problems, as it was before multiple
schedulers could coexist.
Implementations must define SCHED_IMPLEMENTATION to their name used as
the namespacing symbol part (e.g., ule or 4bsd), which used to be the
name passed as the first argument to DECLARE_SCHEDULER(). This argument
is now redundant and has been removed. That same macro with same value
has to be defined in the directives from 'sys/conf/files' for each
implementation's namespacing header to be produced properly.
For added safety, <sys/sched.h> does not provide interface functions'
declarations when SCHED_IMPLEMENTATION is defined anymore, so that
implementations can never inadvertently call these functions.