This appendix builds upon material presented in Chapters 4 and 9 . It describes the programming interface provided by the Hierarchical Scheduler Infrastructure (HSI) for implementing loadable schedulers.
The scheduler instance data structure is used by the HSI to keep track of scheduler instances. Scheduler instance memory is managed by the HSI; the data structure is guaranteed to have been allocated by the time an instance’s I_Init function is called, and will not be deallocated until after its I_Deinit function has returned. The fields of the scheduler instance are shown in Figure B.1. They are used as follows:
struct HLS_SCHED_INSTANCE { char Name[MAX_NAMELEN]; char Type[MAX_NAMELEN]; struct HLS_CALLBACKS *CB; SDHandle SchedData; // private fields for use only by the HSI KTIMER HLSTimer; KDPC HLSDpc; }; |
Virtual processors embody parent / child relationships between two schedulers: each scheduler shares one or more virtual processors (VPs) with its parent(s) and with its children. The responsibility for correctly allocating and deallocating memory for VPs lies with the child. That is, before registering a VP with its parent a child must first allocate and initialize it. The fields in a virtual processor, shown in Figure B.2 , are:
Schedulers, like other device drivers, are event-driven. They must make a collection of function pointers available to the rest of the system in order to receive notifications when events of interest occur. This collection of functions is shown in Figure B.3 ; it also includes a single variable Name. The namespace of schedulers is separate from the namespace of scheduler instances; the HSI keeps track of both kinds of entities. The callbacks can be divided into three categories, identified by a prefix. First, callbacks that are initiated by a scheduler’s child (or potential child) have the prefix “B”. Callbacks from a parent have the prefix “T”. Finally, callbacks from the HSI have the prefix “I”. Most callbacks take a parameter called Self, which is analogous to the implicit self parameter passed to object methods in languages such as C++. The functions that each scheduler provides to the HSI are:
The HSI makes a number of functions available to loadable schedulers; their prototypes are shown in Figure B.4 .
Schedulers may use this function to arrange for a timer callback to arrive in the future. Following Windows convention, negative times are relative and positive times are absolute (setting Time to 0 results in an immediate callback). Currently each scheduler gets only one timer; successive calls to HLSSetTimer result in the timer being reset. The resolution of this timer is tunable and depends on clock interrupt frequency. Currently, it can be assumed to be accurate to approximately 1 ms.
This function returns the current time in 100 ns units. The time is based on the value returned by the rdtsc instruction; this means that reading the time is cheap and precise, but it may not be accurately calibrated with respect to the times used by Windows 2000.
Allocate a block of memory--the interface is the same as the C library function malloc.
Release a block of memory--the interface is the same as the C library function free.
If expr is false, print the line number, file, and expression of the failing assert to the console. Also attempt to trap to the kernel debugger or, if the debugger is unavailable, halt the system.
This macro prints a debugging message to the console if HLS_DBG_PRINT_LEVEL is greater than or equal to the level parameter. The arguments (format, ...) are evaluated similarly to the arguments to the C library function printf.
This type is used by HLS to represent time values. It is an alias for the signed 64-bit integer.
This enumerated type is used as a return value by many HLS functions. HLS_SUCCESS is the success value. Failure values include HLS_NOROOM and HLS_INVALID_PARAMETER.
This integer constant indicates the most processors that a Windows 2000 system could contain. It will probably always be equal to 32.
The maximum length, in bytes, of the name of a scheduler, scheduler type, or scheduler instance.
This integer variable indicates the number of processors currently available in the system. It starts at 1 during boot and increases as more processors are brought online. Schedulers that load after boot time may treat it as a constant. Processors are always numbered 0..HLSNumProcs-1.
This integer variable is equal to the number of the processor on which scheduler code is currently executing.
This is an integer constant that a scheduler can sometimes use when a processor number is required, indicating that no particular processor is preferred.
This integer variable is used to control the amount of debugging information that appears on the console. A value of 0 causes HLS to be completely silent, while 9 is very verbose.
The following two functions, unlike all other functions in this appendix, do not pertain to a particular scheduler instance. Rather, they are called by a scheduler device driver as it is being loaded into or unloaded from the Windows 2000 kernel. Schedulers that are built into the kernel should ignore these functions.
Every Windows 2000 device driver provides a DriverEntry callback that is called by the operating system after the driver has been loaded into the kernel address space. When a scheduler is loaded, its DriverEntry function should at some point call HLSRegisterScheduler to inform the HSI of its presence, passing the address of the scheduler’s callback table (described in Section B.1.3) as a parameter.
Prior to unloading a device driver, Windows 2000 calls the driver’s DriverUnload function. When the driver being unloaded is an HLS scheduler, it should call HLSUnregisterScheduler to notify the HSI of its absence.