LWP_NEWSTK(3L)

NAME
lwp_checkstkset, lwp_stkcswset, CHECK, lwp_setstkcache, lwp_newstk, lwp_datastk, STKTOP - LWP stack management

SYNOPSIS

#include <lwp/lwp.h>
#include <lwp/check.h>
#include <lwp/lwpmachdep.h>
#include <lwp/stackdep.h>

CHECK(location, result)

int lwp_checkstkset(tid, limit)
thread_t tid;
caddr_t limit;

int lwp_stkcswset(tid, limit)
thread_t tid;
caddr_t limit;

int lwp_setstkcache(minstksz, numstks)
int minstksz;
int numstks;

stkalign_t *lwp_newstk()

stkalign_t *lwp_datastk(data, size, addr)
caddr_t data;
int size;
caddr_t *addr;

STKTOP(s)

DESCRIPTION

Stacks are problematical with lightweight processes. What is desired is that stacks for each thread are red-zone protected so that one thread's stack does not unexpectedly grow into the stack of another. In addition, stacks should be of infinite length, grown as needed. The process stack is a maximum-sized segment (see getrlimit(2).) This stack is redzone protected, and you can even try to extend it beyond its initial maximum size in some cases. With SunOS 4.x, it is possible to efficiently allocate large stacks that have red zone protection, and the LWP library provides some support for this. For those systems that do not have flexible memory management, the LWP library provides assistance in dealing with the problems of maintaining multiple stacks.

The stack used by main() is the same stack that the system allocates for a process on fork(2V). For allocating other thread stacks, the client is free to use any statically or dynamically allocated memory (using memory from main()'s stack is subject to the stack resource limit for any process created by fork()). In addition, the LASTRITES agent message is available to free allocated resources when a thread dies. The size of any stack should be at least MINSTACKSZ * sizeof (stkalign_t), because the LWP library will use the client stack to execute primitives. For very fast dynamically allocated stacks, a stack cacheing mechanism is available. lwp_setstkcache() allocates a cache of stacks. Each time the cache is empty, it is filled with numstks new stacks, each containing at least minstksz bytes. minstksz will automatically be augmented to take into account the stack needs of the LWP library. lwp_newstk() returns a cached stack that is suitable for use in an lwp_create() call. lwp_setstkcache() must be called (once) prior to any use of lwp_newstk. If running under SunOS 4.x, the stacks allocated by lwp_newstk() will be red-zone protected (an attempt to reference below the stack bottom will result in a SIGSEGV event).

Threads created with stacks from lwp_newstk() should not use the NOLASTRITES flag. If they do, cached stacks will not be returned to the cache when a thread dies.

lwp_datastk() also returns a red-zone protected stack like lwp_newstk() does. It copies any amount of data (subject to the size limitations imposed by lwp_setstkcache) onto the stack above the stack top that it returns. data points to information of size bytes to be copied. The exact location where the data is stored is returned in the reference parameter addr. Because lwp_create() only passes simple types to the newly-created thread, lwp_datastk() is useful to pass a more complex argument: Call lwp_datastk() to get an initialized stack, and pass the address of the data structure (addr) as an argument to the new thread.

A reaper thread running at the maximum pod priority is created by lwp_setstkcache. It's action may be delayed by other threads running at that priority, so it is suggested that the maximum pod priority not be used for client-created threads when lwp_newstk() is being used. Altering the maximum pod priority with pod_setmaxpri() will have the side effect of increasing the reaper thread priority as well.

The stack address passed to lwp_create() represents the top of the stack: the LWP library will not use any addresses at or above it. Thus, it is safe to store information above the stack top if there is room there.

For stacks that are not protected with hardware redzones, some protection is still possible. For any thread tid with stack boundary limit made part of a special context with lwp_checkstkset(), the CHECK macro may be used. This macro, if used at the beginning of each procedure (and before local storage is initialized (it is all right to declare locals though)), will check that the stack limit has not been violated. If it has, the non-local location will be set to result and the procedure will return. CHECK is not perfect, as it is possible to call a procedure with many arguments after CHECK validates the stack, only to have these arguments clobber the stack before the new procedure is entered.

lwp_stkcswset() checks at context-switch time the stack belonging to thread tid for passing stack boundary limit. In addition, a checksum at the bottom of the stack is validated to ensure that the stack did not temporarily grow beyond its limit. This is automated and more efficient than using CHECK, but by the time a context switch occurs, it's too late to do much but abort(3) if the stack was clobbered.

To portably use statically allocated stacks, the macros in <lwp/stackdep.h> should be used. Declare a stack s to be an array of stkalign_t, and pass the stack to lwp_create() as STKTOP(s).

RETURN VALUES

lwp_checkstkset() and lwp_stkcswset() return 0.

lwp_setstkcache() returns the actual size of the stacks allocated in the cache.

lwp_newstk() and lwp_datastk() return a valid new stack address on success. On failure, they return 0.

SEE ALSO
getrlimit(2), abort(3)

WARNINGS

lwp_datastk() should not be directly used in a lwp_create() call since C does not guarantee the order in which arguments to a function are evaluated.

BUGS

C should provide support for heap-allocated stacks at procedure entry time. The hardware should be segment-based to eliminate the problem altogether.