Threads can have a scheduling priority ranging from 1 to 255 (the highest priority), independent of the scheduling policy. A thread inherits the priority of its parent thread by default.
Unprivileged threads can have a priority ranging from 1 to 63 (by default); threads with the PROCMGR_AID_PRIORITY ability enabled (see procmgr_ability()) are allowed to set priorities above 63. You can change the allowed priority range for unprivileged processes with the procnto -P option.
The process manager has a set of special idle threads (one per available CPU core) that have priority 0 and are always ready to run. A CPU core is considered to be idle when the idle thread is scheduled to run on that core. At any instant, a core is either idle or busy; only by averaging over time can a CPU be said to be some percent busy (e.g., 75% CPU usage).
A thread has both a real priority and an effective priority, and is scheduled in accordance with its effective priority. The thread itself can change both its real and effective priority together, but the effective priority may change because of priority inheritance or the scheduling policy. Normally, the effective priority is the same as the real priority.
Interrupt handlers are of higher priority than any thread, but they're not scheduled in the same way as threads. If an interrupt occurs, then:
Although interrupt handlers aren't scheduled in the same way as threads, they're considered to be of a higher priority because an interrupt handler will preempt any running thread.
As an extension to POSIX, when you're setting a priority, you can wrap it in one these macros to specify how to handle out-of-range priority requests:
You can append an s or S to procnto's -P option if you want out-of-range priority requests by default to saturate at the maximum allowed value instead of resulting in an error.