Managing threads (low-level API thread_api.h)
The API is defined in the header file sysroot-*-kos/include/coresrv/thread/thread_api.h
from the KasperskyOS SDK.
Main capabilities of the API:
- Create, terminate, and lock threads.
- Resume execution of locked threads.
- Change the priorities and scheduler classes of threads.
- Handle exceptions.
- Detach threads from interrupts.
- Attach threads to processors (processor cores).
API functions that take the thread ID (TID) as input or return it are obsolete and will be removed in the future. These functions are not described in this section.
Information about API functions is provided in the table below.
The libkos
library also provides a high-level API for thread management. This API is defined in the header file sysroot-*-kos/include/kos/thread.h
from the KasperskyOS SDK. It is recommended to use this specific API. The low-level API should be used only if the high-level API does not have sufficient capabilities.
Creating threads. Thread scheduler classes
To create a thread, call the KnThreadCreateByHandle()
function. You can use the flags
parameter of this function for the created thread to define the following scheduler classes:
- Class for scheduling standard threads.
- Class for scheduling FIFO real-time threads (First In, First Out).
- Class for scheduling RR real-time threads Round-Robin).
The priority of a standard thread can take values ranging from 0 to 15. The higher the priority of a standard thread, the larger the time slice allocated to this thread and the more frequently these time slices are allocated. One standard thread with a high priority can occupy multiple consecutive places in the thread queue. Standard threads cannot supersede other standard threads or real-time threads, regardless of their respective priorities. If a real-time thread appears in the queue, the current standard thread immediately transfers control to the real-time thread. If there are no real-time threads in the queue, the current standard thread transfers control to the next standard thread if the current one is terminated, becomes locked, uses up its time slice or gives it up to the next standard thread.
The priority of a real-time thread can take values ranging from 0 to 31. Higher-priority real-time threads supersede lower-priority real-time threads. Real-time threads also supersede standard threads, regardless of their respective priorities. Control is transferred from the current real-time thread to the next real-time thread in the queue in the following cases:
- The current real-time thread with a FIFO scheduler class is terminated or locked, or a real-time thread with a higher priority appears in the queue.
Until the real-time thread with a FIFO scheduler class is terminated, locked, or superseded by a real-time thread with a higher priority, it can retain control indefinitely and not transfer control to the next real-time thread.
- The current real-time thread with an RR scheduler class is terminated, locked or uses up its time slice, or a real-time thread with a higher priority appears in the queue.
A real-time thread with an RR scheduler class that is not terminated, locked, or superseded by a higher-priority real-time thread transfers control to the next one upon expiry of its time slice if the next one is a real-time thread with the same priority. Otherwise, it transfers control to itself again.
- The current real-time thread has given up its time slice to the next real-time thread with the same priority in the queue.
A real-time thread can give up its time slice to the next one in the queue if the next one is a real-time thread with the same priority. Otherwise, it transfers control to itself again.
Execution of lower-priority real-time threads begins only after each of the real-time threads with a higher priority is terminated or locked. Real-time threads with the same priority form a queue based on the FIFO principle.
The thread scheduler class can be changed by calling the KnThreadSetSchedPolicyByHandle()
function. This function also changes the size of the time slice allocated to a real-time thread with an RR scheduler class. This value is the only parameter of a real-time thread RR scheduler class that has a default value of 10 ms but can take values ranging from 2 ms to 100 ms. The scheduler class of standard threads and the scheduler class of FIFO real-time threads do not have parameters.
The priority of a thread can be changed by calling the KnThreadSetSchedPolicyByHandle()
or KnThreadSetPriorityByHandle()
function.
After a thread is attached to an interrupt, the thread becomes a real-time thread with a FIFO scheduler class and a priority higher than 31, irrespective of the specific scheduler class and priority this thread had before it was attached to the interrupt. Managing interrupt processing (irq.h).)
Many API functions cannot be applied for threads that are attached to interrupts. These functions include KnThreadCreateByHandle()
, KnThreadSetPriorityByHandle()
, KnThreadSuspendCurrent()
, KnThreadResumeByHandle()
, KnThreadTerminateByHandle()
, KnThreadWaitByHandle()
, KnSleep()
, and KnThreadSetSchedPolicyByHandle()
.
Creating thread handles
A thread handle is created whenever a thread is created by the KnThreadCreateByHandle()
function call. A thread (including the initial thread) can also create its own handle by calling the KnThreadOpenCurrent()
function.
A thread handle cannot be transferred to another process via IPC.
Handling exceptions
To register an exception handling function for a thread, call the KnThreadSetExceptionHandler()
function. This function deregisters the previous exception handling function and returns its ID. By saving this ID, you can subsequently register the previous exception handling function again.
To get information about the last exception of a thread, call the KnThreadGetLastException()
function in the exception handler.
Detaching threads from interrupts
To detach a thread from an interrupt, call the KnThreadDetachIrq()
function. (For more details about using the KnThreadDetachIrq()
function, see Managing interrupt processing (irq.h).)
After a thread is detached from an interrupt, the thread receives the scheduler class and priority that it had before it was attached to the interrupt.
Attaching threads to processors (processor cores)
To restrict the set of processors (processor cores) that can be used to execute a thread, define an affinity mask for this thread. An affinity mask is a bit mask indicating which specific processors or processor cores must execute the thread.
To create, adjust, and perform other operations with affinity masks, use the API that is defined in the header file sysroot-*-kos/include/rtl/cpuset.h
from the KasperskyOS SDK.
To define a thread affinity mask, call the KnThreadSetAffinityByHandle()
function.
Terminating threads
When a thread is terminated, it is permanently deleted from the scheduler. A thread is terminated in the following cases:
- The function executed by the thread is exited.
The root function (not a nested function) performed by the thread must be exited by the
return
operator. - The
KnThreadTerminateByHandle()
orKnThreadExit()
function is called.The
KnThreadExit()
function terminates the thread even if the function is called from a nested function instead of the root function executed by the thread. - The process was terminated or switched to the "frozen" state.
For details about the "frozen" state, see Managing processes (low-level API task_api.h).
Thread exit codes are defined by the developer of the KasperskyOS-based solution. These codes should be specified in the code
parameter of the KnThreadTerminateByHandle()
and KnThreadExit()
functions, and when calling the return
operator in the function executed by the thread. To get the thread exit code, call the KnThreadWaitByHandle()
function.
Getting the address of the TCB and defining the base address of a TLS for threads
A thread control block (TCB) is a structure containing thread information that is used by the kernel to manage this specific thread. The type of structure is defined in the header file sysroot-*-kos/include/thread/tcbpage.h
from the KasperskyOS SDK. A TCB contains the base address of the thread local storage (TLS). The KnThreadGetTcb()
function gets the TCB address. The KnThreadSetTls()
function defines the base address of the TLS. These functions are intended for use by the libc
library.
Getting thread information
The KnThreadGetInfoByHandle()
function gets the base address and stack limit of the thread, and the thread identifier (TID). This function is intended for use by the libc
library.
Freeing resources of terminated threads
Resources of a thread include its stack, context, and TCB. To free the resources of a thread after the thread is terminated, you need to close its handle before or after termination of this thread by calling the KnHandleClose()
function, which is declared in the header file sysroot-*-kos/include/coresrv/handle/handle_api.h
from the KasperskyOS SDK (an exception to this case is the initial thread of a process whose resources are freed without calling the KnHandleClose()
function if the initial thread did not create its own handle by calling the KnThreadOpenCurrent()
function). Resources of threads are also freed upon termination of the process that includes these threads.
Information about API functions
thread_api.h functions
Function |
Information about the function |
---|---|
|
Purpose Creates a thread. Parameters
Returned values If successful, the function returns Additional information In the
A standard thread is created by default. Handles of threads cannot be transferred between processes via IPC. |
|
Purpose Creates the handle of the calling thread. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the priority of a thread. Parameters
Returned values If successful, the function returns |
|
Purpose Defines the priority of a thread. Parameters
Returned values If successful, the function returns |
|
Purpose Locks the calling thread. Parameters N/A Returned values If successful, the function returns |
|
Purpose Resumes execution of a locked thread. Parameters
Returned values If successful, the function returns |
|
Purpose Terminates a thread. Parameters
Returned values If successful, the function returns |
|
Purpose Terminates the calling thread. Parameters
Returned values Error code. |
|
Purpose Gets information about a thread. Parameters
Returned values If successful, the function returns |
|
Purpose Locks the calling thread until the defined thread is terminated. Parameters
Returned values If successful, the function returns |
|
Purpose Locks the calling thread for the specified duration. Parameters
Returned values If successful, the function returns |
|
Purpose Gets the address of the thread control block (TCB) for the calling thread. Parameters N/A Returned values Pointer to the TCB. The data type for TCB storage is defined in the header file |
|
Purpose Defines the base address of the thread local storage (TLS) for the calling thread. Parameters
Returned values If successful, the function returns |
|
Purpose Detaches the calling thread from the interrupt handled in its context. Parameters N/A Returned values If successful, the function returns |
|
Purpose Registers the exception handling function for the calling thread. Parameters
Returned values ID of the previously registered exception handling function if one exists, otherwise |
|
Purpose Gets information about the last exception of the calling thread. Parameters
Returned values N/A |
|
Purpose Gets a thread affinity mask. Parameters
Returned values If successful, the function returns |
|
Purpose Defines a thread affinity mask. Parameters
Returned values If successful, the function returns |
|
Purpose Gets information about the thread scheduler class. Parameters
Returned values If successful, the function returns Additional information In the In the |
|
Purpose Defines the scheduler class and priority of the thread. Parameters
Returned values If successful, the function returns Additional information In the In the |