thr_create(3thread)


thr_create -- create a thread

Synopsis

   cc [options] -Kthread file
   

#include <thread.h>

int thr_create(void *stack_address, size_t stack_size,
void *(*start_routine)(void *), void *arg,
long flags, thread_t *new_thread);

Description

thr_create creates a new thread in the current process. The new thread will execute the function specified by start_routine with the argument specified by arg. The new thread will be immediately runnable, unless it is created with the THR_SUSPENDED flag (see the description of the flags parameter).

Parameters


stack_address
pointer to the base address for the new thread's stack

stack_size
size of the new thread's stack

start_routine
pointer to the function the new thread will execute

arg
the argument to start_routine

flags
attributes for the new thread

new_thread
pointer to the identifier for the new thread, set by thr_create

stack_address and stack_size parameters

The new thread will run on the stack described by stack_address and stack_size. The stack can be explicitly allocated by the user or allocated automatically.

For an explicitly allocated stack:

For an automatically allocated stack:

Note that the stack can be silently shrunken so the low and high addresses are properly aligned.

This implementation provides basic stack overflow detection for stacks allocated by the library. If a thread overflows its stack a SIGSEGV signal will be generated.

start_routine parameter

start_routine points to the function that the new thread will execute. A return from start_routine has the same effect as an explicit thr_exit(3thread) by the new thread with status equal to the function return value. The status or return value of a thread can be retrieved with thr_join(3thread).

arg parameter

arg is the argument to start_routine.

flags parameter

flags specifies attributes for the new thread. It can be 0 or constructed from the bitwise inclusive OR of any of the following:

THR_SUSPENDED
Create the new thread in the suspended state. This permits modification of scheduling parameters and other attributes before the new thread executes start_routine. The creating thread or another thread must call thr_continue for the new thread to begin executing.

THR_BOUND
Bind the new thread to a new lightweight process (LWP) created for the purpose, regardless of other flags. The thread will not be scheduled on other LWPs even though the implementation supports multiplexing of threads across LWPs.

THR_DETACHED
Create the new thread in the detached state. The new thread cannot be awaited with thr_join(3thread). This gives a hint to the implementation that immediate reuse of the new thread's resources on thr_exit is acceptable to the user. The exit status of a detached thread cannot be retrieved.

THR_INCR_CONC
Increase the concurrency level as returned by thr_getconcurrency(3thread) by creating a new LWP in the pool, regardless of other flags.

THR_DAEMON
Create the new thread as a daemon thread. The new thread will not be counted when determining if the last thread has terminated. The process will terminate when the last non-daemon thread terminates. Such ``helper threads'' can be created for asynchronous I/O or other activities, but do not prolong the life of the process when there are no real application threads remaining.
If both THR_BOUND and THR_INCR_CONC are set, two new LWPs are created: one to which the new thread will be bound and one to increase the pool.

new_thread parameter

If new_thread is not NULL, thr_create sets the location pointed to by new_thread to the identifier for the created thread. The thread ID is valid only within the calling process.

Signal mask and scheduling characteristics

The newly created thread inherits the creating thread's signal mask, as established by thr_sigsetmask(3thread), but without any pending signals.

The following table shows how priority and scheduling class of a new thread are determined in this implementation. Note that there are two levels of scheduling, each with its own set of scheduling characteristics:

Bound threads are influenced exclusively by LWP scheduling (system scheduling). The scheduling of multiplexed threads is primarily influenced by thread-level scheduling, although it is affected by both levels.

  New Bound Thread New Multiplexed Thread
  LWP sched class: from creator LWP sched class: from pool
Bound LWP priority: from creator LWP priority: from pool
Creator Thread sched class: not used Thread sched class: SCHED_TS
  Thread priority: not used Thread priority: default (63)
  LWP sched class: from creator LWP sched class: from pool
Multiplexed LWP priority: from creator LWP priority: from pool
Creator Thread sched class: not used Thread sched class: SCHED_TS
  Thread priority: not used Thread priority: from creator

             | New Bound Thread                   | New Multiplexed Thread
             | LWP sched class:      from creator | LWP sched class:      from pool
 Bound       | LWP priority:         from creator | LWP priority:         from pool
 Creator     | Thread sched class:   not used     | Thread sched class:   SCHED_TS
             | Thread priority:      not used     | Thread priority:      default (63)
             | LWP sched class:      from creator | LWP sched class:      from pool
 Multiplexed | LWP priority:         from creator | LWP priority:         from pool
 Creator     | Thread sched class:   not used     | Thread sched class:   SCHED_TS
             | Thread priority:      not used     | Thread priority:      from creator

In this implementation, a multiplexed thread is always created with the default scheduling class (SCHED_TS), but its priority depends on whether the creating thread is bound or multiplexed. If the creating thread is multiplexed, then a multiplexed thread inherits the priority of the creating thread. If the creating thread is bound, then a multiplexed thread is given the default priority of 63. The Threads Library maintains a pool of LWPs for multiplexing threads to run on. The LWPs in the pool all have the same scheduling characteristics.

A bound thread inherits its scheduling class and priority from the creating thread. A bound thread is scheduled by the system, therefore the scheduling class and priority it inherits are those of the creating thread's LWP.

Security restrictions

thr_create requires no special permissions or privilege.

Return values

thr_create returns zero for success and an error number for failure, as described below.

Errors

If any of the following conditions occurs, thr_create returns the corresponding value:

ENOMEM
Insufficient memory to complete thr_create.

EINVAL
stack_size is zero and stack_address is not NULL.

EINVAL
stack_size, after shrinking to aligned offsets, is smaller than an implementation-defined lower bound as returned by thr_minstack.

EINVAL
start_routine is NULL.

If any of the following conditions are detected, thr_create returns the corresponding value:


EAGAIN
A resource limit would be exceeded if the call succeeded. Note that EAGAIN cannot always be detected.

EINVAL
The process is being traced using ptrace.

Usage

Examples

The following example creates a multiplexed thread that will use a library-allocated stack. Note that using 0 as the flags argument will create a thread that is multiplexed (not bound) and can be awaited with thr_join. The library will allocate a default size stack because stack_address is NULL and stack_size is 0.
   void *
   t_main(void *arg)
   {
   	...
   }
   int error;
   void *t_arg = NULL;
   thread_t t1_id;
   

error = thr_create((void*)NULL, 0, t_main, t_arg, 0, &t1_id);

The following example creates a multiplexed thread that will use a user-allocated stack.

   void *
   t_main(void *arg)
   {
   	...
   }
   int error;
   void *t1_stack;
   void *t_arg = NULL;
   size_t t_size = 8192;
   thread_t t1_id;
   

t1_stack = malloc(t_size); error = thr_create(t1_stack, t_size, t_main, t_arg, 0, &t1_id);

The following example creates a daemon thread that will use a minimally-sized stack allocated by the library:

   void *
   t_main(void *arg)
   {
   	...
   }
   int error;
   void *t1_stack;
   void *t_arg = NULL;
   thread_t t1_id;
   

error = thr_create((void*)NULL, (size_t)thr_minstack(), t_main, t_arg, THR_DAEMON, &t1_id);

The following example creates a suspended, bound thread, then modifies its scheduling parameters before continuing. See thr_setscheduler(3thread) for more details about modifying thread scheduling parameters. The library will allocate a default size stack because stack_address is NULL and stack_size is 0.

   void *
   t_main(void *arg)
   {
   	...
   }
   int error;
   void *t1_stack;
   void *t_arg = NULL;
   thread_t t1_id;
   sched_param_t sched_param;
   

error = thr_create((void*)NULL, 0, t_main, t_arg, THR_SUSPENDED|THR_BOUND, &t1_id);

/* initialize sched_param to the SCHED_FIFO policy with priority 62 */ sched_param.policy = SCHED_FIFO; ((struct fifo_param *) sched_param.policy_params)->prio = 62;

error = thr_setscheduler(t1_id, &sched_param); error = thr_continue(t1_id);

References

Intro(3thread), fork(2), thr_continue(3thread), thr_exit(3thread), thr_getconcurrency(3thread), thr_join(3thread), thr_minstack(3thread), thr_self(3thread), thr_setconcurrency(3thread), thr_setscheduler(3thread), thr_suspend(3thread)
© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 25 April 2004