RFC 2: A proposal for the S.Ha.R.K. Scheduling Module Interface --------------------------------------------------------------- This file contains an almost working proposal for the new Shark Scheduling Module interface. Here is the final result of a series of transformations I did on the behavior of the functions. If you do not want to read them, go directly to the Proposal section (STEP 3). The final result inherits some names from the current shark version, but radically changes the point of view, making it more similar to the work on Scheduling Activations. STEP 0: Current version ---------------------------------------- typedef struct { char level_name[MAX_LEVELNAME]; WORD level_code; BYTE level_version; int (*level_accept_task_model)(LEVEL l, TASK_MODEL *m); int (*level_accept_guest_model)(LEVEL l, TASK_MODEL *m); void (*level_status)(LEVEL l); PID (*level_scheduler)(LEVEL l); int (*level_guarantee)(LEVEL l, bandwidth_t *freebandwidth); int (*task_create)(LEVEL l, PID p, TASK_MODEL *m); void (*task_detach)(LEVEL l, PID p); int (*task_eligible)(LEVEL l, PID p); void (*task_dispatch)(LEVEL l, PID p, int nostop); void (*task_epilogue)(LEVEL l, PID p); void (*task_activate)(LEVEL l, PID p); void (*task_insert)(LEVEL l, PID p); void (*task_extract)(LEVEL l, PID p); void (*task_endcycle)(LEVEL l, PID p); void (*task_end)(LEVEL l, PID p); void (*task_sleep)(LEVEL l, PID p); int (*guest_create)(LEVEL l, PID p, TASK_MODEL *m); void (*guest_detach)(LEVEL l, PID p); void (*guest_dispatch)(LEVEL l, PID p, int nostop); void (*guest_epilogue)(LEVEL l, PID p); void (*guest_activate)(LEVEL l, PID p); void (*guest_insert)(LEVEL l, PID p); void (*guest_extract)(LEVEL l, PID p); void (*guest_endcycle)(LEVEL l, PID p); void (*guest_end)(LEVEL l, PID p); void (*guest_sleep)(LEVEL l, PID p); } level_des; ------------------------------------------------------------------ STEP 1: applying the first RFC to the current version ----------------------------------------------------- This first proposal derives directly applying the 9 observations done in the first RFC. typedef struct { PID (*level_scheduler)(LEVEL l); int (*level_guarantee)(LEVEL l, bandwidth_t *freebandwidth); int (*task_create)(LEVEL l, PID p, TASK_MODEL *m); void (*task_detach)(LEVEL l, PID p); void (*task_end) (LEVEL l, PID p); int (*task_eligible)(LEVEL l, PID p); void (*task_dispatch)(LEVEL l, PID p, int nostop); void (*task_epilogue)(LEVEL l, PID p); void (*task_activate)(LEVEL l, PID p); void (*task_insert)(LEVEL l, PID p); void (*task_extract)(LEVEL l, PID p); void (*task_message)(LEVEL l, PID p, void *m); int (*guest_create)(LEVEL l, PID p, TASK_MODEL *m); void (*guest_dispatch)(LEVEL l, PID p, int nostop); void (*guest_epilogue)(LEVEL l, PID p); void (*guest_end)(LEVEL l, PID p); } level_des; Rationale: - In this case, the structure of the functions are still divided in level, task and guest calls, with the same meaning they have now. - Removed fields: char level_name[MAX_LEVELNAME]; WORD level_code; BYTE level_version; void (*level_status)(LEVEL l); void (*task_endcycle)(LEVEL l, PID p); void (*task_sleep)(LEVEL l, PID p); These fields & functions can be masked using an appropriate use of task_message int (*level_accept_task_model)(LEVEL l, TASK_MODEL *m); int (*level_accept_guest_model)(LEVEL l, TASK_MODEL *m); The behavior of these fields can be easily done by task_create and guest_create void (*guest_detach)(LEVEL l, PID p); void (*guest_activate)(LEVEL l, PID p); void (*guest_insert)(LEVEL l, PID p); void (*guest_extract)(LEVEL l, PID p); void (*guest_endcycle)(LEVEL l, PID p); void (*guest_sleep)(LEVEL l, PID p); These guest calls where inserted in a first moment; I think they are not needed anymore ----------------------------------------------------------------------- STEP 2: Mapping --------------- Now let's change the names of the functions, making more clear and intuitive the behavior of each function: As an hint, I would like to give a mapping between the old names and the new names. guest_create --> private_insert guest_end --> private_extract task_extract --> public_block task_insert --> public_unblock level_* --> public_* task_* --> public_* ---------------------------------------------------------------------- STEP 3: The Proposal -------------------- typedef struct { int (*private_insert )(LEVEL l, PID p, TASK_MODEL *m); void (*private_extract )(LEVEL l, PID p); void (*private_dispatch)(LEVEL l, PID p, int nostop); void (*private_epilogue)(LEVEL l, PID p); PID (*public_scheduler)(LEVEL l); int (*public_guarantee)(LEVEL l, bandwidth_t *freebandwidth); int (*public_create )(LEVEL l, PID p, TASK_MODEL *m); void (*public_detach )(LEVEL l, PID p); void (*public_end )(LEVEL l, PID p); int (*public_eligible )(LEVEL l, PID p); void (*public_dispatch )(LEVEL l, PID p, int nostop); void (*public_epilogue )(LEVEL l, PID p); void (*public_activate )(LEVEL l, PID p); void (*public_unblock )(LEVEL l, PID p); void (*public_block )(LEVEL l, PID p); void (*public_message )(LEVEL l, PID p, void *m); } level_des; - Public and Private functions ---------------------------- The behavior of a scheduling module is twofold: - PUBLIC Functions: on one side, a module should export an interface to the Generic Kernel, giving a set of functions that the Generic Kernel can use to ask a service to the module. That is, the Public Functions are called ONLY by the Generic Kernel. - PRIVATE Functions: on the other side, a module can export an interface to the public part of the same or of another module. That is, Private Functions are called ONLY by Public and Private Functions. (Note that this part is practically a subset of the Scheduler Activations) Typical examples are: - an EDF module have to implement task activation and unblocking simply inserting a task into the ready queue. For that purpose, the functions public_activate and public_unblock directly inserts the tasks into the private queue. private_insert and all the other private functions are not used, and if called they raise an exception (that is, the module do not export any interface to the other modules). - an EDF module have to implement task activation and unblocking simply inserting a task into the ready queue. For that purpose, the functions public_activate and public_unblock internally calls the function private_insert. Moreover, the two functions can have some peculiarities. For example, the implementer would like that public_activate adds a deadline check posting an OSLib event at the deadline time, whereas this is not the case of public_unblock, because the deadline used before have to be used again. Deadline posting can be done into public_activate. private_insert will simply insert the task into its "private" queue. - an aperiodic server wants to insert a task into the EDF queue. Again, the public_activate and the public_unblock of the aperiodic server will call the private_insert of the EDF queue, that will insert the task into its queue. - Hyerarchical scheduling (I'm using the same names of the modules in FIRST D-OS2 Workpackage) - A new task is activated. - The Generic Kernel calls the public_activate of a local scheduler (EDFSTAR) - EDFSTAR calls the private_insert of the module that is right up in the scheduling hyerarchy (CBSSTAR) - The CBSSTAR's private_insert calls the private_insert of the right up module (EDF) Note that: - The EDFSTAR module can only defines public functions as in example 1, or private functions can be used as in example 2. Note that in that way the only difference between the EDF module in example 2 and the EDFSTAR is that the public_activate calls the private_insert that is on the same level in the case of EDF, on another level in the case of EDFSTAR - The CBSSTAR is an "intermediate" module. it does not export a public interface. Instead, it exports a private interface that remaps QoS requests from EDFSTAR to EDF.