Rogue Wave banner
Previous fileTop of DocumentContentsIndex pageNext file
Threads Module Platform Guide
Rogue Wave web site:  Home Page  |  Main Documentation Page

5.3 Solaris Threads Attribute Support

On Solaris, the Solaris native and POSIX 1003.1c thread APIs are supported. While the POSIX API simply wraps the underlying Solaris thread library, it does not provide access to the same capabilities as is available from the native library. When possible, you should configure the Threads Module to use the native library as this will give you the greatest level of control over your threads. According to Sun, you can mix these APIs within a single application, but this requires a complicated build process, and is not recommended.


Native Solaris Threads are not supported with the GNU GCC compiler.

5.3.1 Scheduling Attributes

The following sections describe both the Solaris native and POSIX thread attribute-specific support, behavior, and restrictions for attributes related to thread scheduling. When the Threads Module is configured to use the POSIX API, most of the capabilities and attributes available under the native API are still available, with the exception of the concurrency policy attribute.

5.3.1.1 Start Policy

The start policy attribute is fully supported by the Solaris implementation of the Threads Module and defaults to RW_THR_START_RUNNING.

5.3.1.2 Scheduling Contention Scope

Solaris implicitly supports the concept of contention scope. Solaris allows both process-scope and system-scope threads.

Under Solaris, a process-scope thread is an unbound thread, and a system-scope thread is a bound thread. A bound thread is a thread that is permanently assigned to an underlying light-weight process, or LWP. An LWP can be thought of as the Solaris equivalent of a kernel thread. Unbound threads are scheduled by the threads library and contend for LWPs, while bound threads are scheduled by the kernel and contend directly for processors.

The Threads Module implementation maps contention scope policies to the underlying API as follows:

Under Solaris, threads with a contention scope value of RW_THR_PROCESS_SCOPE have a fixed scheduling policy of RW_THR_PREEMPTIVE, while threads with RW_THR_SYSTEM_SCOPE have a fixed scheduling policy of RW_THR_TIME_SLICED_DYNAMIC, unless the process has the super-user privilege, in which case, the thread also has access to RW_THR_TIME_SLICED_FIXED, and RW_THR_PREEMPTIVE policies. Each of these scheduling policies can have a different legal range of priority values.

If you change the contention scope attribute, the Threads Module will check that the scheduling policy and priority are still legal in the new contention scope, and if not, will force the scheduling policy or priority values to the appropriate default values. (See the sections on Scheduling Policy, Scheduling Priority, and Scheduling Time-Slice Quantum.)

The Threads Module defines RW_THR_PROCESS_SCOPE as the default contention scope policy under Solaris.

5.3.1.3 Scheduling Inheritance Policy

The scheduling inheritance policy attribute is fully supported. The Solaris threads implementation of the Threads Module defaults to RW_THR_INHERIT. The POSIX threads implementation defaults to RW_THR_EXPLICIT.

5.3.1.4 Concurrency Policy


The Concurrency Policy attribute is available under the native API. it is not available under the Solaris POSIX 1003.1c API.

The concurrency policy attribute is supported in the Solaris implementation of the Threads Module, but only while the contention scope is RW_THR_PROCESS_SCOPE.

This attribute is used to tell the underlying threads system that it should create a new LWP when it creates a new unbound thread. By creating new LWPs, the effective concurrency of a multithreaded application can be increased, since LWPs are time-sliced and can be scheduled on different processors.

The Threads Module implementation maps concurrency policies to the underlying API as follows:

5.3.1.5 Scheduling Policy

If the contention scope is RW_THR_PROCESS_SCOPE, then the scheduling policy is fixed at RW_THR_PREEMPTIVE because, under Solaris, process-scope, or "unbound" threads run until preempted or blocked; the threads are not time-sliced.


The scheduling under RW_THR_PROCESS_SCOPE is not truly preemptive, because unbound threads are scheduled for execution on one or more LWPs, and these LWPs are scheduled independently of the unbound threads, usually in a time-sliced manner. This results in a hybrid form of scheduling that is difficult to describe using a single policy.

If the contention scope is RW_THR_PROCESS_SCOPE, you may query the scheduling policy, and may set the scheduling policy to RW_THR_PREEMPTIVE, but any attempt to change to another policy will produce an exception.

If the contention scope is RW_THR_SYSTEM_SCOPE, then the thread will be "bound" to an LWP which, depending on the scheduling attributes of the creating thread, the attributes of the thread's LWP, and the current process privileges, may support any one of RW_THR_TIME_SLICED_DYNAMIC, RW_THR_TIME_SLICED_FIXED, or RW_THR_PREEMPTIVE scheduling policies.

The Threads Module implementation for Solaris maps scheduling policies to the underlying API as follows:

If the contention scope is RW_THR_SYSTEM_SCOPE, you may query the scheduling policy, and you may attempt to set the scheduling policy to any of the three policies listed above, but if the process lacks the necessary privileges, or if an unsupported policy is specified, then these attempts will produce an exception.

The Solaris implementation of the Threads Module requires the use of two separate priority values for threads with system contention scope; one priority value sets the system-level scheduling priority for a thread (a thread's LWP, actually), while the second value is used to prioritize access to any thread-level synchronization resources shared with other threads in the same process. The process-level synchronization priority is called the process scope priority value, and the system-level scheduling priority is called the system-scope priority value.

The RWThreadAttribute class provides separate families of member functions for independently manipulating these two priority values; see the Threads Module User's Guide for a listing of these functions.

You should only need to define a separate process-scope priority for a system-scope thread when you have used more than one priority value for your process-scope threads, and it is possible that your system-scope thread may deadlock as a result of priority inversion because it was created with the default process-scope priority value.

A new thread's scheduling policy is inherited from the creating thread, unless the scheduling policy attribute has been explicitly set or the inheritance policy is set to RW_THR_EXPLICIT. If the inheritance policy is RW_THR_EXPLICIT, the Threads Module defines the default scheduling policy based on the current contention scope:

Table 9: Solaris native thread support: Relationship of contention scope to default scheduling policy

Contention Scope Default Scheduling Policy
RW_THR_PROCESS_SCOPE RW_THR_PREEMPTIVE
RW_THR_SYSTEM_SCOPE RW_THR_TIME_SLICED_DYNAMIC

If you change the scheduling policy attribute, the Threads Module will check that the priority and time-slice quantum values are still legal under the new scheduling policy, and if not, will force those attributes to the appropriate default values. (See the next sections on Scheduling Priority and Scheduling Time-Slice Quantum.)

Similarly, changing the contention scope attribute may force changes in the scheduling policy and related attribute values.

5.3.1.6 Scheduling Priority

Under Solaris, the legal range of thread priority values and the default priorities depend on the current contention scope and scheduling policy.

Scheduling Priority For Process-Scope Threads. For unbound, or process-scope threads, Solaris allows any priority value in the range between 0 and MAX_INT. Process scope threads are scheduled onto LWPs according to this priority value.

Solaris maintains a separate scheduling queue for each thread priority value up to 127. Priority values greater that 127 share a single queue, forcing the Solaris threads scheduler to traverse the entire queue each time another thread must be scheduled.

For this reason, the Threads Module limits the Solaris process-scope priority range to a minimum of 0 and a maximum of 127. If the inheritance policy is RW_THR_INHERIT, a new thread's priority is inherited from the creating thread, and if the inheritance policy is RW_THR_EXPLICIT, the default priority is 0.

How are process-scope threads scheduled at the system level? That depends on the scheduling attributes of the LWP pool that is used to execute the unbound threads. When a process is created, the initial LWP in the process inherits its scheduling class and priority from the parent process. Each LWP created to execute unbound threads inherits its scheduling class and priority from this initial LWP. This means that all LWPs used for unbound threads will possess the same scheduling parameters.

Scheduling Priority For System-Scope Threads. When a thread is given system contention scope in the Solaris implementation of the Threads Module, that thread is permanently bound to an LWP.

These system-scope threads are scheduled using two separate priority values; one priority value defines the system-level scheduling, or LWP priority of the thread, while the second value is used to resolve any contention for thread-level synchronization resources shared with other threads in the same process (such as a mutex created with the USYNC_THREAD flag).

The process-level, synchronization priority is called the process scope priority value, while the system-level scheduling priority is called the system-scope priority value.

The RWThreadAttribute class provides two additional sets of member functions for use in independently manipulating these two priority values. The regular priority functions may still be used; but it should be understood that these functions are limited to manipulating the priority value corresponding to the current contention scope; when the contention scope is RW_THR_PROCESS_SCOPE, the regular priority functions do the same thing as the process-scope priority functions, and when the contention scope is RW_THR_SYSTEM_SCOPE, the regular priority functions do the same thing as the system-scope priority functions.

You cannot get or set the system-scope priority value when the contention scope is RW_THR_PROCESS_SCOPE; any attempt to do so will result in an exception.

You only need to define a separate process-scope priority for a system-scope thread when you have used more than one priority value for your process-scope threads, and there exists the possibility that your system-scope thread may deadlock as a result of priority inversion because it assumed the default process-scope priority value.

The range of process-scope priority values remains unchanged regardless of contention scope and scheduling policy, while the system-scope priority values can vary with scheduling policy.

To determine the range of priority values for the various system-scope policies, use the getMinPriority() or getMinSystemScopePriority()and getMaxPriority() or getMaxSystemScopePriority() functions to retrieve the minimum and maximum allowable values. The minimum priority value for system-scope threads is always 0. The maximum priority values are defined as part of the operating system configuration on each workstation; the maximum can vary significantly from machine to machine.

If the scheduling policy value of an RWThreadAttribute instance is RW_THR_TIME_SLICED_DYNAMIC, you will not be able to set, get, or query the legal range for the priority, or system-scope priority attribute values, unless the process has the super-user privilege. If the current process does not have this privilege, you will have to wait until the thread has been created and perform operations on the active thread.

In either case, when the desired or current scheduling policy is RW_THR_TIME_SLICED_DYNAMIC, the Threads Module must consider several factors in determining the maximum allowable priority value:

This information is used to determine whether the user-priority limit can be adjusted up to the maximum priority value, and if not, what maximum priority value can be expected. To make this determination the Threads Module:

When the scheduling policy is RW_THR_TIME_SLICED_FIXED or RW_THR_PREEMPTIVE, the LWP associated a newly-created bound thread is assigned to the real-time (RT) scheduling class. The Threads Module retrieves the maximum priority for these policies by using the priocntl() function to query the real-time class for the maximum priority value supported by that class. This value is defined as part of the operating system configuration, and can vary from machine to machine. To use either one of these policies requires the super-user privilege.

Scheduling Priority Inheritance. A new thread's priority value is inherited from the creating thread, unless the priority attribute has been explicitly set or the inheritance policy is set to RW_THR_EXPLICIT. If the inheritance policy is RW_THR_EXPLICIT, the Threads Module defines the default priority to be 0, as shown in the following table:

Table 10: Solaris native thread support: Setting of scheduling priority values

Contention Scope Scheduling Policy Default Process-Scope Priority Default System-Scope Priority
Process RW_THR_PREEMPTIVE Inherited or 0 N/A
RW_THR_TIME_SLICED_DYNAMIC Inherited or 0 Inherited or 0
System RW_THR_TIME_SLICED_FIXED Inherited or 0 Inherited or 0
RW_THR_PREEMPTIVE Inherited or 0 Inherited or 0

If you change the scheduling contention scope or policy attributes, the Threads Module will check that the priority values are still legal under the new settings, and if not, will force the priority values the appropriate defaults.

5.3.1.7 Scheduling Time-Slice Quantum

Under Solaris, the time-slice quantum attribute is only supported when the contention scope is RW_THR_SYSTEM_SCOPE, and the scheduling policy is RW_THR_TIME_SLICED_FIXED. Attempts to get or set this attribute value under other circumstances will result in exceptions.

The Threads Module accepts time-slice quantum values as an unsigned long number of milliseconds. The library converts milliseconds into seconds and nanoseconds so the value can be passed to the Solaris priocntl() function using the real-time class parameters structure. The Threads Module allows you to specify the quantum with an accuracy of 1 millisecond; the system, however, will round the value to the next largest integral multiple of the system clock's resolution.

The minimum time-slice quantum allowed by the Threads Module under Solaris is 1 millisecond. The maximum is limited by to the largest number of milliseconds that can be represented by an unsigned long. If an infinite time-slice quantum is desired the RW_THR_PREEMPTIVE scheduling policy should be used.

If supported under current circumstances, a new thread's time-slice quantum value is inherited from the creating thread, unless the time-slice quantum attribute has been explicitly set or the inheritance policy has been set to RW_THR_EXPLICIT. If the inheritance policy is RW_THR_INHERIT, and you query for the default time-slice quantum, The Threads Module will return the time-slice quantum value of the calling thread. If the calling thread does not have a time-slice quantum to query (because it does not have the proper contention scope or scheduling policy), the query will fail with an exception. If the inheritance policy is RW_THR_EXPLICIT, the Threads Module will ask the operating system to use the default time-slice quantum for the current priority level. This default value may not be queried, and any attempts to do so will result in an exception.

The following table summarizes the relationship between contention scope, scheduling policy, and the time-slice quantum attribute:

Table 11: Solaris native thread support: Summary of the relationship between contention scope, scheduling policy and the time-slice quantum attribute

Contention Scope Scheduling Policy Default Time-Slice Quantum
Process RW_THR_PREEMPTIVE N/A
RW_THR_TIME_SLICED_DYNAMIC N/A
System RW_THR_TIME_SLICED_FIXED Inherited or System Default
RW_THR_PREEMPTIVE N/A (Infinite)

5.3.2 Stack Attributes

Solaris native and POSIX API supports the use of system-managed and user-managed stacks.

5.3.2.1 System-Managed Stack Attributes

Solaris native and POSIX API supports user-specification of the reserve size for a system-managed stack, but provides no support for controlling the commitment of physical memory and page-file space to such a stack.

Stack Reserve Size. Solaris supports the stack reserve size attribute for a system-managed stack.

The minimum stack size necessary to execute a null function is returned by the getMinStackSize() member. The Threads Module uses the thr_min_stack() function to determine this value. To ensure that each thread's stack size is always greater than the minimum allowable stack size, the Threads Module adds the minimum stack size value to any reserve size value retrieved from a thread attribute at the time a thread is created.

The Threads Module imposes no upper limit for stack reserve size; the maximum stack size is effectively limited by available virtual memory space and pagefile size. If the stack reserve size specified is too large for the available resources, an exception will be produced at the time a thread is created using the thread attribute instance with the offending reserve size value. Any such exception is thrown by the start() function invocation that attempted to create the thread.

Solaris uses allocation on demand even when the user specifies the amount of stack size to reserve. When Solaris allocates stack space, it maps the space as anonymous, zeroed memory, but does not allocate real memory until the memory is accessed. Solaris reserves an inaccessible page at the end of each stack area, called a red zone, that is used to produce a segmentation fault should the stack overflow. The stack address space is mapped using the MAP_NORESERVE attribute to delay the cost of reserving swap space until the memory is used. The only resource consumed by reserving space is addresses in the virtual address space of your process; no memory or pagefile space is allocated until the memory is committed. Therefore, there is little harm in reserving a large area if it might be needed.

The default stack reserve size for a 32-bit image used by Solaris and returned by getStackReserveSize() is 1MB. The value for a 64-bit minage is 2MB. This stack is allocated on demand, and starts with 1 page committed to memory.

A call to setUserStack() replaces or nullifies the attribute settings produced by any previous call to setStackReserveSize() and vice versa.

Stack Commit Size. The stack commit size attribute is not supported in the Solaris implementation of the Threads Module. Attempts to get or set this attribute value will result in exceptions.

5.3.2.2 User-Managed Stack Attributes

The Solaris implementation of the Threads Module supports user-managed stacks.

If an attempt is made to set the user stack address to zero, or to set the user stack size to a value less than the minimum stack size returned by the getMinStackSize() function, a RWTHRBoundsError exception is produced.

The Threads Module imposes no upper limit for user stack size; the maximum stack size is effectively limited by the virtual memory space and pagefile size available to the user.

Attempts to query for a default user-stack address value or user-stack size value will result in an RWTHROperationNotAvailable exception. These values may only be queried after they have been set.

A call to setStackReserveSize() replaces or nullifies the attribute settings produced by any previous call to setUserStack() and vice-versa.

5.3.3 Signal Handling Considerations

When using the native Solaris Threads API, the Threads Module terminates threads using the thr_kill() method. This method really just sends a signal to the target thread. The Threads Module arbitrarily uses the SIGPWR signal to perform thread termination. Any thread created using the Threads Module will unmask this signal prior to entering user code. If this signal is already used within an application, another signal may be specified by changing the source code. Simply search for the macro definition RW_THR_TERMINATE_SIGNAL and change its value to the desired signal value (the definition currently resides in rw/thread/RWThread.h).

When the Threads Module is built using the POSIX API, it uses the thread cancellation mechanism to terminate threads, which does not involve the use of signals.



Previous fileTop of DocumentContentsNo linkNext file

Copyright © Rogue Wave Software, Inc. All Rights Reserved.

The Rogue Wave name and logo, and SourcePro, are registered trademarks of Rogue Wave Software. All other trademarks are the property of their respective owners.
Provide feedback to Rogue Wave about its documentation.