Critical threads

A critical thread is one that's allowed to run even if its partition is over budget (provided that partition has a critical time budget). By default, QNX Neutrino automatically identifies all threads that are initiated by an I/O interrupt as critical. However, you can use SchedCtl() to mark selected threads as critical.

Note: The ability to mark any thread as critical may require security control to prevent its abuse as a DOS attack. For information about security, see the "Security for Scheduler Partitions" chapter of this guide.

Critical threads always see realtime latencies, even when the system is fully loaded, or any time other threads in the same partition are being limited to meet budgets. The basic idea is that a critical thread is allowed to violate the budget rules of its partition and run immediately, thereby obtaining the realtime response it requires. For this to work properly, there must not be many critical threads in the system.

You can use a sigevent to make a thread run as critical:

  1. Define and initialize the sigevent as normal. For example:
    struct sigevent my_event;
    SIGEV_PULSE_INIT (&my_event, coid, 10,
                      MY_SIGNAL_CODE, 6969);
  2. Set the flag that will mark the thread that receives your event as a critical event before you send the event:
    SIGEV_MAKE_CRITICAL(&my_event);

    This has an effect only if the thread receiving your event runs in a partition with a critical-time budget.

  3. Process the sigevent as normal in the thread that receives it. This thread doesn't have to do anything to make itself a critical thread; the kernel does that automatically.

To make a thread noncritical, you can use the SIGEV_CLEAR_CRITICAL() macro when you set up a sigevent.

Note: The SIGEV_CLEAR_CRITICAL() and SIGEV_MAKE_CRITICAL() macros set a hidden bit in the sigev_notify field. If you test the value of the sigev_notify field of your sigevent after creating it, and if you've ever used the SIGEV_MAKE_CRITICAL() macro, then use code like this:
switch (SIGEV_GET_TYPE(&my_event) ) {

instead of this:

switch (my_event.sigev_notify) {

A thread that receives a message from a critical thread automatically becomes critical as well.

You may mark selected scheduler partitions as critical and assign each partition a critical time budget. Critical time is specifically intended to allow critical interrupt threads to run over budget.

The critical time budget is specified in milliseconds. It's the amount of time all critical threads may use during an averaging window. A critical thread will run even if its scheduler partition is out of budget, as long as its partition has critical budget remaining.

Critical time is billed against a partition while all these conditions are met:

Otherwise, the critical time isn't billed. The critical threads run whether or not the time is billed as critical. The only time critical threads won't run is when their partition has exhausted its critical budget (see " Bankruptcy ").

In order to be useful and effective, the number of critical threads in the system must be few, and it's also ideal to give them high and unique priorities. Consequently, if critical threads are the majority, the thread scheduler will rarely be able to guarantee all of the partitions their minimum CPU budgets. In other words, the system degrades to a priority-based thread scheduler when there are too many critical threads.

To gain benefit from being critical, a critical thread must be the highest priority thread in the system, and not share its priority with other threads. If a ready-to-run critical thread is behind other noncritical threads (either because others have a higher priority, or are at the same priority and were made ready before your critical thread), then the critical thread may stall if the partition is out of budget.

Although your thread is critical, it must wait for a higher priority, and earlier threads sharing its partition to run first. However, if those other threads are noncritical, and if the partition is out of budget, your critical thread won't run until the averaging window rotates so that the partition once again has a budget.

A critical thread remains critical until it becomes receive-blocked. A critical thread that's being billed for critical time won't be round-robin-timesliced (even if its scheduling policy is round robin).

Note: QNX Neutrino marks all sigevent structures that are returned from a user's interrupt-event handler functions as critical. This makes all I/O handling threads automatically critical. This is done to minimize code changes that you would need to do for basic use of partition thread scheduling. If you don't want this behavior to occur, specify the -c option to procnto in your buildfile.

To make a partition's critical budget infinite, set it to the number of processors times the size of the averaging window. Do this with caution, as it can cause security problems; see the "Security for Scheduler Partitions" chapter of this guide.