HPlogo HP-UX Process Management: White Paper > Chapter 1 Process Management

Thread Scheduling

» 

Technical documentation

Complete book in PDF

 » Table of Contents

The thread of a parent process forks a child process. The child process inherits the scheduling policy and priority of the parent process. As with the parent thread, it is the child thread whose scheduling policy and priority will be used.

The following figure illustates the flow of creation.

Figure 1-35 Inheritance of Scheduling policy and priority

[Inheritance of Scheduling policy and priority]
  • Each thread in a process is independently scheduled.

  • Each thread contains its own scheduling policy and priority

  • Thread scheduling policies and priorities may be assigned before a thread is created (in the threads attributes object) or set dynamically while a thread is running.

  • Each thread may be bound directly to a CPU.

  • Each thread may be suspended (and later resumed) by any thread within the process.

The following scheduling attributes may be set in the threads attribute object. The newly created thread will contain these scheduling attributes:

contentionscope

PTHREAD_SCOPE_SYSTEM specifies a bound (1 x 1, kernel-spacel) thread. When a bound thread is created, both a user thread and a kernel-scheduled entity are created.

PTHREAD_SCOPE_PROCESS will specify an unbound (M x N, combination user- and kernel-space) thread. (Note, HP-UX release 10.30 does not support unbound threads.)

inheritsched

PTHREAD_INHERIT_SCHED specifies that the created thread will inherit its scheduling values from the creating thread, instead of from the threads attribute object.

PTHREAD_EXPLICIT_SCHED specifies that the created thread will get its scheduling values from the threads attribute object.

schedpolicy

The scheduling policy of the newly created thread

schedparam

The scheduling parameter (priority) of the newly created thread.

Timeline

A process and its thread change with the passage of time. A thread's priority is adjusted four key times, as shown in the next figure and described in the table that follows..

Figure 1-36 Thread scheduling timeline

[Thread scheduling timeline]

Table 1-24 Thread priority adjustments

IntervalWhat happens
10 milliseconds The clock-interrupt handling routine clock_int() adjusts a time interval on the monarch every clock tick. The monarch processor calls hardclock() to handle clock ticks on the monarch for general maintenance (such as disk and LAN states). hardclock() calls per_spu_hardclock() to charge the running thread with cpu time accumulated (kt_cpu).
40 millisecondsper_spu_hardclock() determines the running thread has accumulated 40ms of time and calls setpri(). setpri() calls calcusrpri() to adjust the running thread's user priority (kt_usrpri).
100 millisecondsBy default, 10 clock ticks represents the value of timeslice, the configurable kernel parameter that defines the amount of time one thread is allowed to run before the CPU is given to the next thread. Once a timeslice interval has expired a call to swtch() is made to enact a context switch.
one secondstatdaemon() loops on the thread list and once every second calls schedcpu() to update all thread priorities. The kt_usrpri priority is given to the thread on the next context switch; if in user mode kt_usrpri is given immediately.

 

Thread Scheduling Routines

The following table summarizes the principal thread scheduling routines.

Table 1-25 Thread scheduling routines

RoutinePurpose
hardclock()Runs on the monarch processor to handle clock ticks.
per_spu_hardclock()handles per-processor hardclock activities.
setpri()Called with a thread as its argument and returns a user priority for that thread. Calls calcusrpri() to get the new user priority. If the new priority is stronger than that of the currently running thread, setpri() generates an MPSCHED interrupt on the processor executing that thread, stores the new user priority in kt_usrpri and returns it to its caller.
calcusrpri()The user priority (kt_usrpri) portion of setpri(). calcusrpri() uses the kt_cpu and p_nice(proc) fields of the thread, tt, to determine tt's user priority and return that value without changing any fields in *tt. If tt is a RTPRIO or RTSCHED thread, kt_usrpri is the current value of kt_pri.
swtch()Finds the most deserving runnable thread, takes it off the run queue, and sets it to run.
statdaemon()A general-purpose kernel process run once per second to check and update process and virtual memory artifacts, such as signal queueing and free protection IDs. Calls schedcpu() to recompute thread priorities and statistics.
schedcpu()Once a second, schedcpu() loops through the thread list to update thread scheduling priorities. If the system has more than one SPU, it balances SPU loads. schedcpu updates thread usage information (kt_prevrecentcycles and kt_fractioncpu), calculates new kt_cpu for the current thread (info used by setpri(), updates the statistics of runnable threads on run queues and those swapped out, and awakens the swapper. Calls setpri().
setrq()Routine used to put threads onto the run queues. Set the appropriate protection (spl7 in UP case, thread lock in MP case). Assert valid HP-UX priority and scheduling policy and perform policy-specific setup
remrq()Routine used to remove a thread from its run queue. With a valid kt_link, set the appropriate protection (spl7 in the UP case or thread lock in MP case). Find the processor on which the thread is running. Decrement the thread count on run queues. Update the mpinfo structure. Restore the old spl level, update RTSCHED counts if necessary. Adjust the kt_pri, return to schedcpu.

 

Adjusting a Thread Priority

Figure 1-37 Adjusting a thread priority

[Adjusting a thread priority]

Every 10 msecs, the routine hardclock() is called with spinlock SPL5 to disable I/O modules and software interrupts. hardclock() calls the per-processor routine per_spu_hardclock(), which looks for threads whose priority is high enough to run. ( Searching the processor run queues depends on the scheduling policy). If a thread is found, the MPSCHED_INT_BIT in the processor EIRR (External Interrupt Request Register) is set.

When the system receives an MPSCHED_INT interrupt while running a thread in user mode, the trap handler puts the thread on a run queue and switches context, to bring in the high- priority thread.

If the current executing thread is the thread with the highest priority, it is given 100ms (one timeslice) to run. hardclock() calls setpri() every 40ms to review the thread's working priority (kt_pri). setpri() adjusts the user priority (kt_usrpri) of a time-share thread process based on cpu usage and nice values. While a time-share thread is running, kt_cpu time increases and its priority (kt_pri) worsens. RTSCHED or RTPRIO thread priorities do not change.

Every 1 second, schedcpu() decrements the kt_cpu value for each thread on the run queue. setpri() is called to calculate a new priority of the current thread being examined in the schedcpu() loop. remrq() is called to remove that thread from the run queue and then setrq() places the thread back into the run queue according to its new priority.

If a process is sleeping or on a swap device (that is, not on the run queue), the user priority (kt_usrpri) is adjusted in setpri() and kt_pri is set in schedcpu().