Subsystem management functions extends the functions of μT-Kernel itself by adding a user-defined function called "subsystem" to the kernel in order to implement middleware and others running on the μT-Kernel. Some functions provided by μT-Kernel/SM are also implemented by utilizing the subsystem management functions.
A subsystem consists of extended SVC handlers to execute user-defined system calls (called "extended SVCs"), a break function that performs the required processing when any exception occurs, and an event handling function that performs the required processing when any event is raised from devices, etc. (Figure 10)
The extended SVC handler directly accepts requests from applications and others. A break function and event processing function are so-called callback type functions and accept requests from the kernel.
Additional Notes | |
---|---|
Generally speaking, upper layer middleware including the process management functions and the file management functions are also implemented by utilizing the subsystem management functions. Other examples of middleware that are implemented by utilizing the subsystem management functions include TCP/IP manager, USB manager, and PC card manager. Though subsystem management functions are meant to allow users to add custom system calls (SVC: SuperVisor Calls) as the primary purpose, they can be used to build complex and advanced middleware through not only the addition of just user-defined system calls but also through provision of exception processing functions to handle the exceptions, which are required for the added system calls. In addition to the subsystem management functions, μT-Kernel also provides the device driver functions in order to extend itself. Both subsystems and device drivers are function modules independent from μT-Kernel itself. They can be used by loading their corresponding binary programs and then calling them from a task on μT-Kernel. Both run at the protection level 0. While API is limited to using open/close and read/write type when calling a device driver, API for calling a subsystem can be defined without any restriction. Subsystems are identified by subsystem IDs ( |
ID |
ssid
| Subsystem ID | Subsystem ID |
CONST T_DSSY* |
pk_dssy
| Packet to Define Subsystem | Subsystem definition information |
pk_dssy
Detail:
ATR |
ssyatr
| Subsystem Attributes | Subsystem attributes |
PRI |
ssypri
| Subsystem Priority | Subsystem priority |
FP |
svchdr
| Extended SVC Handler Address | Extended SVC handler address |
FP |
breakfn
| Break Function Address | Break function address |
FP |
eventfn
| Event Handling Function Address | Event handling function address |
(Other implementation-dependent parameters may be added beyond this point.) |
E_OK | Normal completion |
E_ID | Invalid ID number (ssid is invalid or cannot be used) |
E_NOMEM | Insufficient memory (memory for control block cannot be allocated) |
E_RSATR | Reserved attribute (ssyatr is invalid or cannot be used) |
E_PAR | Parameter error (pk_dssy is invalid or cannot be used) |
E_OBJ | ssid is already defined (when pk_dssy ≠ NULL) |
E_NOEXS | ssid is not defined (when pk_dssy = NULL) |
Only when all the service profile items below are set to be effective, this system call can be used.
When the service profile items below is set to be effective, subsystem priority (ssypri
) can be specified.
Only when the service profile items below are set to be effective, break function can be specified.
Defines subsystem specified in ssid
.
One subsystem ID must be assigned to one subsystem without overlapping with other subsystems. The kernel does not have a function for assigning subsystem IDs automatically.
Subsystem IDs 1 to 9 are reserved for μT-Kernel use. 10 to 255 are numbers used by middleware, etc. The maximum usable subsystem ID value is implementation-dependent and may be lower than 255 in some implementations.
ssyatr
indicates system attributes in its lower bits and implementation-dependent attributes in its higher bits. The system attribute in ssyatr
are not assigned in this version, and no system attributes are used.
ssypri
indicates the subsystem priority. The startup function, cleanup function, and event handling function are called in order of priority. The calling order is undefined when these subsystems have the same priority. Subsystem priority 1 is the highest priority, with larger numbers indicating lower priorities. The range of priorities that can be specified is implementation-dependent, but it must be possible to assign at least priorities 1 to 16.
NULL can be specified in breakfn
and eventfn
, in which case the corresponding function will not be called.
Specifying pk_dssy
= NULL deletes a subsystem definition.
Extended SVC handler
An extended SVC handler accepts requests from applications and other programs as an application programming interface (API) for a subsystem. It can be called in the same way as an ordinary system call, and is normally invoked using a trap instruction or the like.
The format of an extended SVC handler is as follows.
INT svchdr( void *pk_para, FN fncd ) { /* branching by fncd */ return retcode; /* exit extended SVC handler */ }
fncd
is a function code. The lower 8 bits of the instruction code are the subsystem ID. The remaining higher bits can be used in any way by the subsystem. Ordinarily they are used as a function code inside the subsystem. A function code must be a positive value, so the most significant bit is always 0.
pk_para
points to a packet of parameters passed to this system call. The packet format can be decided by the subsystem. Generally a format like the stack passed to a C language function is used, which in many cases is the same format as a C language structure.
The return code passed from an extended SVC handler is passed to the caller transparently as the function return code. As a rule, negative values are error codes and 0 or positive values are the return code for normal completion. If an extended SVC call fails for some reason, the error code (negative value) set by T-Kernel is returned to the caller without invoking the extended SVC handler, so it is best to avoid confusion with these values.
The format by which an extended SVC is called is dependent on the kernel implementation. As a subsystem API, however, it must be specified in a C language function format independent of the kernel implementation. The subsystem must provide an interface library for converting from the C language function format to the kernel-dependent extended SVC calling format.
An extended SVC handler runs as a quasi-task portion.
It can be called from a task-independent portion, and in this case the extended SVC handler also runs as a task-independent portion.
Break function
A break function is a function called when a task exception is raised for a task while an extended SVC handler is executing.
When a break function is called, the processing by the extended SVC handler running at the time the task exception was raised must be stopped promptly and control must be returned from the extended SVC handler to its caller. The role of a break function is to abort the processing of the currently running extended SVC handler.
The format of a break function is as follows.
void breakfn( ID tskid ) { /* stop the running extended SVC handler */ }
tskid
is the ID of the task in which the task exception was raised.
A break function is called when a task exception is raised by tk_ras_tex. If extended SVC handler calls are nested, then when the nesting level of the extended SVC handler is decreased by the return from the latest extended SVC handler, the break function corresponding to the former extended SVC handler to which the control will be returned next, is called.
A break function is called only once for one extended SVC handler per one task exception.
If another nested extended SVC call is made while a task exception is raised, no break function is called for the called extended SVC handler.
A break function runs as a quasi-task portion. Its requesting task is identified as follows: If a break function is called by tk_ras_tex, it runs as a quasi-task portion of the task that issued tk_ras_tex. On the other hand, when the nesting level of extended SVC handler is decreased, the break function runs as a quasi-task portion of the task that raised the task exception (the task running the extended SVC handler). This means that the task executing the break function may be different from the task executing the extended SVC handler. In such a case, the break function and extended SVC handler run concurrently as controlled by task scheduling.
It is thus conceivable that the extended SVC handler will return to its caller before the break function finished executing, but in that case the extended SVC handler waits at the point right before returning, until the break function completes. How this waiting state maps to the task state transitions is implementation-dependent, but preferably it should remain in READY state (a READY state that does not go to RUNNING state). The precedence of a task may change while it is waiting for a break function to complete, but how task precedence is treated is implementation-dependent.
Similarly, an extended SVC handler cannot call an extended SVC until break function execution completes.
In other words, during the time from the raising of a task interrupt until the break function completes, the affected task must stay in the extended SVC handler that was executing at the time of the task exception.
In the case where the requesting task of the break function differs from that of the extended SVC handler, that is, where the break function and the extended SVC handler run in different task contexts, the task priority of the break function is raised to the same as that of the extended SVC handler only while the break handler is executing if the former is lower than the latter. On the other hand, if the break function task priority is the same as or higher than that of the extended SVC handler, the priority does not change. The priority that gets changed is the current priority; the base priority stays the same.
The change in priority occurs only immediately before entry into the break function; any changes after that of the extended SVC handler task priority are not followed by further changes in priority of the break function task. In no case does a change in the break function priority while a break function is running results in a priority change in the extended SVC handler task. At the same time, there is no restriction on priority changes due to a running break function.
When the break function completes, the current priority of its task reverts to base priority. If a mutex was locked, however, the priority reverts to that as adjusted by the mutex. (In other words, the ability is provided to adjust the current priority at the entry and exit of the break function only; other than that, the priority is the same as when an ordinary task is running.)
Event handling function
An event handling function is called by issuing the tk_evt_ssy system call.
It processes various requests made to a subsystem.
Note that it has to process all requests for all subsystems. If processing is not required, it can simply return E_OK without performing any operation.
The format of an event handling function is as follows.
ER eventfn( INT evttyp, INT info ) { /* event processing */ return ercd; }
evttyp
indicates the request type and info
is a parameter that can be used freely. These parameters are specified in tk_evt_ssy.
If processing completes normally, E_OK is passed in the return code; otherwise an error code (negative value) is returned.
The following event types evttyp
are defined. For more details, see the Section called Device Management Functions in the Chapter called μT-Kernel/SM Functions.
#define TSEVT_SUSPEND_BEGIN 1 /* before suspending device */ #define TSEVT_SUSPEND_DONE 2 /* after suspending device */ #define TSEVT_RESUME_BEGIN 3 /* before resuming device */ #define TSEVT_RESUME_DONE 4 /* after resuming device */ #define TSEVT_DEVICE_REGIST 5 /* device registration notice */ #define TSEVT_DEVICE_DELETE 6 /* device deletion notice */
An event handling function runs as a quasi-task portion of the task that issued tk_evt_ssy.
Extended SVC handlers as well as break functions and event handling functions all have the equivalent of the TA_HLNG attribute only. There is no means of specifying the TA_ASM attribute.
It is possible to issue a system call that enters WAITING state in the extended SVC handler, but in that case the program must be designed so that it can be stopped by calling a break function. The specific processing flow is as follows: If tk_ras_tex is issued for the caller task while an extended SVC handler is executing, it is necessary to stop the running extended SVC handler as soon as possible and return a stop error to the caller task. For this purpose the break function is used. In order to stop the running extended SVC handler immediately, the break function must forcibly release the WAITING state, even if the system call is in WAITING state during processing the extended SVC handler. For this purpose, the tk_dis_wai system call is generally used. tk_dis_wai can prevent the system call from entering WAITING state until the control returns from the extended SVC handler to the caller task, but the implementor should also make it possible to stop the program of the extended SVC handler by calling a break function. For example, leaving from WAITING state with the error code E_DISWAI can mean that the execution is stopped by a break function. So it is best to stop the extended SVC handler immediately and return a stop error to the caller task, without continuing to execute the subsequent processing.
An extended SVC handler may be called concurrently by multiple tasks. If the tasks share same resources, the mutual exclusion control must be performed in the extended SVC handler.
Note that, in an environment where INT data type is 16 bits, part of function code that can be used for subsystem function code is only 7 bits wide (0-127), and care must be taken.
E_OK | Normal completion |
E_ID | Invalid ID number (ssid is invalid or cannot be used) |
E_NOEXS | Object does not exist (the subsystem specified in ssid is not defined) |
E_CTX | Context error (issued from task-independent portion, or in dispatch disabled state) |
Other | Error code returned by the event handling function |
Only when all the service profile items below are set to be effective, this system call can be used.
Calls the event handling function of the subsystem specified in ssid
.
Specifying ssid
= 0 makes the system call applied to all currently defined subsystems. In this case the event handling function of each subsystem is called in sequence.
evttyp
is an odd number:Calls subsystems in descending order of priority.
evttyp
is an even number:Calls subsystems in ascending order of priority.
The calling order is undefined wheren these subsystems have the same priority.
If this system call is issued for a subsystem with no event handling function defined, the function is simply not called; no error results.
If the event handling function returns an error, the error code is passed transparently in the system call return code. When ssid
= 0 and an event handler returns an error, the event handling functions of all other subsystems continue to be called. In the system call return code, only one error code is returned even if more than one event handling function returned an error. It is not possible to know which subsystem's event handling function returned the error.
If a task exception is raised for the task that called tk_evt_ssy, during the execution of event handling function, the task exception is held until the event handling function completes its processing.
An example of using an event handling function is to perform the suspend/resume processing for the power management functions. Specifically, when the system enters the power-off state (device suspended state) due to power failure or other reason, it notifies each subsystem of its transition to suspended state. Then the event handling function of each subsystem is called to perform the appropriate processing for it. In μT-Kernel/SM, tk_evt_ssy is executed for this purpose during the processing of tk_sus_dev. The event handling function of each subsystem performs any necessary operations before going to suspended state, such as saving the data. On the other hand, when the system returns (resumes) from the suspended state due to power on or other reason, it notifies each subsystem of its return from suspended state. Then the event handling function of each subsystem is called again to perform the appropriate processing for it. For more details, see the description of tk_sus_dev.
For another example, when a new device is registered by tk_def_dev, the system notifies each subsystem of the registration, and the event handling function of each subsystem is called to perform the appropriate processing for it. In μT-Kernel/SM, tk_evt_ssy is executed for this purpose during the processing of tk_def_dev.
Note that info
is INT type, and its value range is implementation-dependent, so care must be taken.
pk_rssy
Detail:
Only when all the service profile items below are set to be effective, this system call can be used.
When the service profile items below is set to be effective, subsystem priority (ssypri
) can be acquired.
References information about the subsystem specified in ssid
.
ssypri
returns the subsystem priority specified in tk_def_ssy.
If the subsystem specified in ssid
is not defined, E_NOEXS is returned.