summaryrefslogtreecommitdiffstats
path: root/upstream/debian-unstable/man3/threads.3perl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/debian-unstable/man3/threads.3perl
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/debian-unstable/man3/threads.3perl')
-rw-r--r--upstream/debian-unstable/man3/threads.3perl1065
1 files changed, 1065 insertions, 0 deletions
diff --git a/upstream/debian-unstable/man3/threads.3perl b/upstream/debian-unstable/man3/threads.3perl
new file mode 100644
index 00000000..95de3d9d
--- /dev/null
+++ b/upstream/debian-unstable/man3/threads.3perl
@@ -0,0 +1,1065 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "threads 3perl"
+.TH threads 3perl 2024-01-12 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+threads \- Perl interpreter\-based threads
+.SH VERSION
+.IX Header "VERSION"
+This document describes threads version 2.36
+.SH WARNING
+.IX Header "WARNING"
+The "interpreter-based threads" provided by Perl are not the fast, lightweight
+system for multitasking that one might expect or hope for. Threads are
+implemented in a way that makes them easy to misuse. Few people know how to
+use them correctly or will be able to provide help.
+.PP
+The use of interpreter-based threads in perl is officially
+discouraged.
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 4
+\& use threads (\*(Aqyield\*(Aq,
+\& \*(Aqstack_size\*(Aq => 64*4096,
+\& \*(Aqexit\*(Aq => \*(Aqthreads_only\*(Aq,
+\& \*(Aqstringify\*(Aq);
+\&
+\& sub start_thread {
+\& my @args = @_;
+\& print(\*(AqThread started: \*(Aq, join(\*(Aq \*(Aq, @args), "\en");
+\& }
+\& my $thr = threads\->create(\*(Aqstart_thread\*(Aq, \*(Aqargument\*(Aq);
+\& $thr\->join();
+\&
+\& threads\->create(sub { print("I am a thread\en"); })\->join();
+\&
+\& my $thr2 = async { foreach (@files) { ... } };
+\& $thr2\->join();
+\& if (my $err = $thr2\->error()) {
+\& warn("Thread error: $err\en");
+\& }
+\&
+\& # Invoke thread in list context (implicit) so it can return a list
+\& my ($thr) = threads\->create(sub { return (qw/a b c/); });
+\& # or specify list context explicitly
+\& my $thr = threads\->create({\*(Aqcontext\*(Aq => \*(Aqlist\*(Aq},
+\& sub { return (qw/a b c/); });
+\& my @results = $thr\->join();
+\&
+\& $thr\->detach();
+\&
+\& # Get a thread\*(Aqs object
+\& $thr = threads\->self();
+\& $thr = threads\->object($tid);
+\&
+\& # Get a thread\*(Aqs ID
+\& $tid = threads\->tid();
+\& $tid = $thr\->tid();
+\& $tid = "$thr";
+\&
+\& # Give other threads a chance to run
+\& threads\->yield();
+\& yield();
+\&
+\& # Lists of non\-detached threads
+\& my @threads = threads\->list();
+\& my $thread_count = threads\->list();
+\&
+\& my @running = threads\->list(threads::running);
+\& my @joinable = threads\->list(threads::joinable);
+\&
+\& # Test thread objects
+\& if ($thr1 == $thr2) {
+\& ...
+\& }
+\&
+\& # Manage thread stack size
+\& $stack_size = threads\->get_stack_size();
+\& $old_size = threads\->set_stack_size(32*4096);
+\&
+\& # Create a thread with a specific context and stack size
+\& my $thr = threads\->create({ \*(Aqcontext\*(Aq => \*(Aqlist\*(Aq,
+\& \*(Aqstack_size\*(Aq => 32*4096,
+\& \*(Aqexit\*(Aq => \*(Aqthread_only\*(Aq },
+\& \e&foo);
+\&
+\& # Get thread\*(Aqs context
+\& my $wantarray = $thr\->wantarray();
+\&
+\& # Check thread\*(Aqs state
+\& if ($thr\->is_running()) {
+\& sleep(1);
+\& }
+\& if ($thr\->is_joinable()) {
+\& $thr\->join();
+\& }
+\&
+\& # Send a signal to a thread
+\& $thr\->kill(\*(AqSIGUSR1\*(Aq);
+\&
+\& # Exit a thread
+\& threads\->exit();
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+Since Perl 5.8, thread programming has been available using a model called
+\&\fIinterpreter threads\fR which provides a new Perl interpreter for each
+thread, and, by default, results in no data or state information being shared
+between threads.
+.PP
+(Prior to Perl 5.8, \fI5005threads\fR was available through the \f(CW\*(C`Thread.pm\*(C'\fR API.
+This threading model has been deprecated, and was removed as of Perl 5.10.0.)
+.PP
+As just mentioned, all variables are, by default, thread local. To use shared
+variables, you need to also load threads::shared:
+.PP
+.Vb 2
+\& use threads;
+\& use threads::shared;
+.Ve
+.PP
+When loading threads::shared, you must \f(CW\*(C`use threads\*(C'\fR before you
+\&\f(CW\*(C`use threads::shared\*(C'\fR. (\f(CW\*(C`threads\*(C'\fR will emit a warning if you do it the
+other way around.)
+.PP
+It is strongly recommended that you enable threads via \f(CW\*(C`use threads\*(C'\fR as early
+as possible in your script.
+.PP
+If needed, scripts can be written so as to run on both threaded and
+non-threaded Perls:
+.PP
+.Vb 8
+\& my $can_use_threads = eval \*(Aquse threads; 1\*(Aq;
+\& if ($can_use_threads) {
+\& # Do processing using threads
+\& ...
+\& } else {
+\& # Do it without using threads
+\& ...
+\& }
+.Ve
+.ie n .IP "$thr = threads\->create(FUNCTION, ARGS)" 4
+.el .IP "\f(CW$thr\fR = threads\->create(FUNCTION, ARGS)" 4
+.IX Item "$thr = threads->create(FUNCTION, ARGS)"
+This will create a new thread that will begin execution with the specified
+entry point function, and give it the \fIARGS\fR list as parameters. It will
+return the corresponding threads object, or \f(CW\*(C`undef\*(C'\fR if thread creation failed.
+.Sp
+\&\fIFUNCTION\fR may either be the name of a function, an anonymous subroutine, or
+a code ref.
+.Sp
+.Vb 5
+\& my $thr = threads\->create(\*(Aqfunc_name\*(Aq, ...);
+\& # or
+\& my $thr = threads\->create(sub { ... }, ...);
+\& # or
+\& my $thr = threads\->create(\e&func, ...);
+.Ve
+.Sp
+The \f(CW\*(C`\->new()\*(C'\fR method is an alias for \f(CW\*(C`\->create()\*(C'\fR.
+.ie n .IP $thr\->\fBjoin()\fR 4
+.el .IP \f(CW$thr\fR\->\fBjoin()\fR 4
+.IX Item "$thr->join()"
+This will wait for the corresponding thread to complete its execution. When
+the thread finishes, \f(CW\*(C`\->join()\*(C'\fR will return the return value(s) of the
+entry point function.
+.Sp
+The context (void, scalar or list) for the return value(s) for \f(CW\*(C`\->join()\*(C'\fR
+is determined at the time of thread creation.
+.Sp
+.Vb 10
+\& # Create thread in list context (implicit)
+\& my ($thr1) = threads\->create(sub {
+\& my @results = qw(a b c);
+\& return (@results);
+\& });
+\& # or (explicit)
+\& my $thr1 = threads\->create({\*(Aqcontext\*(Aq => \*(Aqlist\*(Aq},
+\& sub {
+\& my @results = qw(a b c);
+\& return (@results);
+\& });
+\& # Retrieve list results from thread
+\& my @res1 = $thr1\->join();
+\&
+\& # Create thread in scalar context (implicit)
+\& my $thr2 = threads\->create(sub {
+\& my $result = 42;
+\& return ($result);
+\& });
+\& # Retrieve scalar result from thread
+\& my $res2 = $thr2\->join();
+\&
+\& # Create a thread in void context (explicit)
+\& my $thr3 = threads\->create({\*(Aqvoid\*(Aq => 1},
+\& sub { print("Hello, world\en"); });
+\& # Join the thread in void context (i.e., no return value)
+\& $thr3\->join();
+.Ve
+.Sp
+See "THREAD CONTEXT" for more details.
+.Sp
+If the program exits without all threads having either been joined or
+detached, then a warning will be issued.
+.Sp
+Calling \f(CW\*(C`\->join()\*(C'\fR or \f(CW\*(C`\->detach()\*(C'\fR on an already joined thread will
+cause an error to be thrown.
+.ie n .IP $thr\->\fBdetach()\fR 4
+.el .IP \f(CW$thr\fR\->\fBdetach()\fR 4
+.IX Item "$thr->detach()"
+Makes the thread unjoinable, and causes any eventual return value to be
+discarded. When the program exits, any detached threads that are still
+running are silently terminated.
+.Sp
+If the program exits without all threads having either been joined or
+detached, then a warning will be issued.
+.Sp
+Calling \f(CW\*(C`\->join()\*(C'\fR or \f(CW\*(C`\->detach()\*(C'\fR on an already detached thread
+will cause an error to be thrown.
+.IP threads\->\fBdetach()\fR 4
+.IX Item "threads->detach()"
+Class method that allows a thread to detach itself.
+.IP threads\->\fBself()\fR 4
+.IX Item "threads->self()"
+Class method that allows a thread to obtain its own \fIthreads\fR object.
+.ie n .IP $thr\->\fBtid()\fR 4
+.el .IP \f(CW$thr\fR\->\fBtid()\fR 4
+.IX Item "$thr->tid()"
+Returns the ID of the thread. Thread IDs are unique integers with the main
+thread in a program being 0, and incrementing by 1 for every thread created.
+.IP threads\->\fBtid()\fR 4
+.IX Item "threads->tid()"
+Class method that allows a thread to obtain its own ID.
+.IP """$thr""" 4
+.IX Item """$thr"""
+If you add the \f(CW\*(C`stringify\*(C'\fR import option to your \f(CW\*(C`use threads\*(C'\fR declaration,
+then using a threads object in a string or a string context (e.g., as a hash
+key) will cause its ID to be used as the value:
+.Sp
+.Vb 1
+\& use threads qw(stringify);
+\&
+\& my $thr = threads\->create(...);
+\& print("Thread $thr started\en"); # Prints: Thread 1 started
+.Ve
+.IP threads\->object($tid) 4
+.IX Item "threads->object($tid)"
+This will return the \fIthreads\fR object for the \fIactive\fR thread associated
+with the specified thread ID. If \f(CW$tid\fR is the value for the current thread,
+then this call works the same as \f(CW\*(C`\->self()\*(C'\fR. Otherwise, returns \f(CW\*(C`undef\*(C'\fR
+if there is no thread associated with the TID, if the thread is joined or
+detached, if no TID is specified or if the specified TID is undef.
+.IP threads\->\fByield()\fR 4
+.IX Item "threads->yield()"
+This is a suggestion to the OS to let this thread yield CPU time to other
+threads. What actually happens is highly dependent upon the underlying
+thread implementation.
+.Sp
+You may do \f(CW\*(C`use threads qw(yield)\*(C'\fR, and then just use \f(CWyield()\fR in your
+code.
+.IP threads\->\fBlist()\fR 4
+.IX Item "threads->list()"
+.PD 0
+.IP threads\->list(threads::all) 4
+.IX Item "threads->list(threads::all)"
+.IP threads\->list(threads::running) 4
+.IX Item "threads->list(threads::running)"
+.IP threads\->list(threads::joinable) 4
+.IX Item "threads->list(threads::joinable)"
+.PD
+With no arguments (or using \f(CW\*(C`threads::all\*(C'\fR) and in a list context, returns a
+list of all non-joined, non-detached \fIthreads\fR objects. In a scalar context,
+returns a count of the same.
+.Sp
+With a \fItrue\fR argument (using \f(CW\*(C`threads::running\*(C'\fR), returns a list of all
+non-joined, non-detached \fIthreads\fR objects that are still running.
+.Sp
+With a \fIfalse\fR argument (using \f(CW\*(C`threads::joinable\*(C'\fR), returns a list of all
+non-joined, non-detached \fIthreads\fR objects that have finished running (i.e.,
+for which \f(CW\*(C`\->join()\*(C'\fR will not \fIblock\fR).
+.ie n .IP $thr1\->equal($thr2) 4
+.el .IP \f(CW$thr1\fR\->equal($thr2) 4
+.IX Item "$thr1->equal($thr2)"
+Tests if two threads objects are the same thread or not. This is overloaded
+to the more natural forms:
+.Sp
+.Vb 7
+\& if ($thr1 == $thr2) {
+\& print("Threads are the same\en");
+\& }
+\& # or
+\& if ($thr1 != $thr2) {
+\& print("Threads differ\en");
+\& }
+.Ve
+.Sp
+(Thread comparison is based on thread IDs.)
+.IP "async BLOCK;" 4
+.IX Item "async BLOCK;"
+\&\f(CW\*(C`async\*(C'\fR creates a thread to execute the block immediately following
+it. This block is treated as an anonymous subroutine, and so must have a
+semicolon after the closing brace. Like \f(CW\*(C`threads\->create()\*(C'\fR, \f(CW\*(C`async\*(C'\fR
+returns a \fIthreads\fR object.
+.ie n .IP $thr\->\fBerror()\fR 4
+.el .IP \f(CW$thr\fR\->\fBerror()\fR 4
+.IX Item "$thr->error()"
+Threads are executed in an \f(CW\*(C`eval\*(C'\fR context. This method will return \f(CW\*(C`undef\*(C'\fR
+if the thread terminates \fInormally\fR. Otherwise, it returns the value of
+\&\f(CW$@\fR associated with the thread's execution status in its \f(CW\*(C`eval\*(C'\fR context.
+.ie n .IP $thr\->\fB_handle()\fR 4
+.el .IP \f(CW$thr\fR\->\fB_handle()\fR 4
+.IX Item "$thr->_handle()"
+This \fIprivate\fR method returns a pointer (i.e., the memory location expressed
+as an unsigned integer) to the internal thread structure associated with a
+threads object. For Win32, this is a pointer to the \f(CW\*(C`HANDLE\*(C'\fR value returned
+by \f(CW\*(C`CreateThread\*(C'\fR (i.e., \f(CW\*(C`HANDLE *\*(C'\fR); for other platforms, it is a pointer
+to the \f(CW\*(C`pthread_t\*(C'\fR structure used in the \f(CW\*(C`pthread_create\*(C'\fR call (i.e.,
+\&\f(CW\*(C`pthread_t *\*(C'\fR).
+.Sp
+This method is of no use for general Perl threads programming. Its intent is
+to provide other (XS-based) thread modules with the capability to access, and
+possibly manipulate, the underlying thread structure associated with a Perl
+thread.
+.IP threads\->\fB_handle()\fR 4
+.IX Item "threads->_handle()"
+Class method that allows a thread to obtain its own \fIhandle\fR.
+.SH "EXITING A THREAD"
+.IX Header "EXITING A THREAD"
+The usual method for terminating a thread is to
+\&\fBreturn()\fR from the entry point function with the
+appropriate return value(s).
+.IP threads\->\fBexit()\fR 4
+.IX Item "threads->exit()"
+If needed, a thread can be exited at any time by calling
+\&\f(CW\*(C`threads\->exit()\*(C'\fR. This will cause the thread to return \f(CW\*(C`undef\*(C'\fR in a
+scalar context, or the empty list in a list context.
+.Sp
+When called from the \fImain\fR thread, this behaves the same as \f(CWexit(0)\fR.
+.IP threads\->exit(status) 4
+.IX Item "threads->exit(status)"
+When called from a thread, this behaves like \f(CW\*(C`threads\->exit()\*(C'\fR (i.e., the
+exit status code is ignored).
+.Sp
+When called from the \fImain\fR thread, this behaves the same as \f(CWexit(status)\fR.
+.IP \fBdie()\fR 4
+.IX Item "die()"
+Calling \f(CWdie()\fR in a thread indicates an abnormal exit for the thread. Any
+\&\f(CW$SIG{_\|_DIE_\|_}\fR handler in the thread will be called first, and then the
+thread will exit with a warning message that will contain any arguments passed
+in the \f(CWdie()\fR call.
+.IP exit(status) 4
+.IX Item "exit(status)"
+Calling \fBexit()\fR inside a thread causes the whole
+application to terminate. Because of this, the use of \f(CWexit()\fR inside
+threaded code, or in modules that might be used in threaded applications, is
+strongly discouraged.
+.Sp
+If \f(CWexit()\fR really is needed, then consider using the following:
+.Sp
+.Vb 2
+\& threads\->exit() if threads\->can(\*(Aqexit\*(Aq); # Thread friendly
+\& exit(status);
+.Ve
+.IP "use threads 'exit' => 'threads_only'" 4
+.IX Item "use threads 'exit' => 'threads_only'"
+This globally overrides the default behavior of calling \f(CWexit()\fR inside a
+thread, and effectively causes such calls to behave the same as
+\&\f(CW\*(C`threads\->exit()\*(C'\fR. In other words, with this setting, calling \f(CWexit()\fR
+causes only the thread to terminate.
+.Sp
+Because of its global effect, this setting should not be used inside modules
+or the like.
+.Sp
+The \fImain\fR thread is unaffected by this setting.
+.IP "threads\->create({'exit' => 'thread_only'}, ...)" 4
+.IX Item "threads->create({'exit' => 'thread_only'}, ...)"
+This overrides the default behavior of \f(CWexit()\fR inside the newly created
+thread only.
+.ie n .IP $thr\->set_thread_exit_only(boolean) 4
+.el .IP \f(CW$thr\fR\->set_thread_exit_only(boolean) 4
+.IX Item "$thr->set_thread_exit_only(boolean)"
+This can be used to change the \fIexit thread only\fR behavior for a thread after
+it has been created. With a \fItrue\fR argument, \f(CWexit()\fR will cause only the
+thread to exit. With a \fIfalse\fR argument, \f(CWexit()\fR will terminate the
+application.
+.Sp
+The \fImain\fR thread is unaffected by this call.
+.IP threads\->set_thread_exit_only(boolean) 4
+.IX Item "threads->set_thread_exit_only(boolean)"
+Class method for use inside a thread to change its own behavior for \f(CWexit()\fR.
+.Sp
+The \fImain\fR thread is unaffected by this call.
+.SH "THREAD STATE"
+.IX Header "THREAD STATE"
+The following boolean methods are useful in determining the \fIstate\fR of a
+thread.
+.ie n .IP $thr\->\fBis_running()\fR 4
+.el .IP \f(CW$thr\fR\->\fBis_running()\fR 4
+.IX Item "$thr->is_running()"
+Returns true if a thread is still running (i.e., if its entry point function
+has not yet finished or exited).
+.ie n .IP $thr\->\fBis_joinable()\fR 4
+.el .IP \f(CW$thr\fR\->\fBis_joinable()\fR 4
+.IX Item "$thr->is_joinable()"
+Returns true if the thread has finished running, is not detached and has not
+yet been joined. In other words, the thread is ready to be joined, and a call
+to \f(CW\*(C`$thr\->join()\*(C'\fR will not \fIblock\fR.
+.ie n .IP $thr\->\fBis_detached()\fR 4
+.el .IP \f(CW$thr\fR\->\fBis_detached()\fR 4
+.IX Item "$thr->is_detached()"
+Returns true if the thread has been detached.
+.IP threads\->\fBis_detached()\fR 4
+.IX Item "threads->is_detached()"
+Class method that allows a thread to determine whether or not it is detached.
+.SH "THREAD CONTEXT"
+.IX Header "THREAD CONTEXT"
+As with subroutines, the type of value returned from a thread's entry point
+function may be determined by the thread's \fIcontext\fR: list, scalar or void.
+The thread's context is determined at thread creation. This is necessary so
+that the context is available to the entry point function via
+\&\fBwantarray()\fR. The thread may then specify a value of
+the appropriate type to be returned from \f(CW\*(C`\->join()\*(C'\fR.
+.SS "Explicit context"
+.IX Subsection "Explicit context"
+Because thread creation and thread joining may occur in different contexts, it
+may be desirable to state the context explicitly to the thread's entry point
+function. This may be done by calling \f(CW\*(C`\->create()\*(C'\fR with a hash reference
+as the first argument:
+.PP
+.Vb 3
+\& my $thr = threads\->create({\*(Aqcontext\*(Aq => \*(Aqlist\*(Aq}, \e&foo);
+\& ...
+\& my @results = $thr\->join();
+.Ve
+.PP
+In the above, the threads object is returned to the parent thread in scalar
+context, and the thread's entry point function \f(CW\*(C`foo\*(C'\fR will be called in list
+(array) context such that the parent thread can receive a list (array) from
+the \f(CW\*(C`\->join()\*(C'\fR call. (\f(CW\*(Aqarray\*(Aq\fR is synonymous with \f(CW\*(Aqlist\*(Aq\fR.)
+.PP
+Similarly, if you need the threads object, but your thread will not be
+returning a value (i.e., \fIvoid\fR context), you would do the following:
+.PP
+.Vb 3
+\& my $thr = threads\->create({\*(Aqcontext\*(Aq => \*(Aqvoid\*(Aq}, \e&foo);
+\& ...
+\& $thr\->join();
+.Ve
+.PP
+The context type may also be used as the \fIkey\fR in the hash reference followed
+by a \fItrue\fR value:
+.PP
+.Vb 4
+\& threads\->create({\*(Aqscalar\*(Aq => 1}, \e&foo);
+\& ...
+\& my ($thr) = threads\->list();
+\& my $result = $thr\->join();
+.Ve
+.SS "Implicit context"
+.IX Subsection "Implicit context"
+If not explicitly stated, the thread's context is implied from the context
+of the \f(CW\*(C`\->create()\*(C'\fR call:
+.PP
+.Vb 2
+\& # Create thread in list context
+\& my ($thr) = threads\->create(...);
+\&
+\& # Create thread in scalar context
+\& my $thr = threads\->create(...);
+\&
+\& # Create thread in void context
+\& threads\->create(...);
+.Ve
+.ie n .SS $thr\->\fBwantarray()\fP
+.el .SS \f(CW$thr\fP\->\fBwantarray()\fP
+.IX Subsection "$thr->wantarray()"
+This returns the thread's context in the same manner as
+\&\fBwantarray()\fR.
+.SS threads\->\fBwantarray()\fP
+.IX Subsection "threads->wantarray()"
+Class method to return the current thread's context. This returns the same
+value as running \fBwantarray()\fR inside the current
+thread's entry point function.
+.SH "THREAD STACK SIZE"
+.IX Header "THREAD STACK SIZE"
+The default per-thread stack size for different platforms varies
+significantly, and is almost always far more than is needed for most
+applications. On Win32, Perl's makefile explicitly sets the default stack to
+16 MB; on most other platforms, the system default is used, which again may be
+much larger than is needed.
+.PP
+By tuning the stack size to more accurately reflect your application's needs,
+you may significantly reduce your application's memory usage, and increase the
+number of simultaneously running threads.
+.PP
+Note that on Windows, address space allocation granularity is 64 KB,
+therefore, setting the stack smaller than that on Win32 Perl will not save any
+more memory.
+.IP threads\->\fBget_stack_size()\fR; 4
+.IX Item "threads->get_stack_size();"
+Returns the current default per-thread stack size. The default is zero, which
+means the system default stack size is currently in use.
+.ie n .IP "$size = $thr\->\fBget_stack_size()\fR;" 4
+.el .IP "\f(CW$size\fR = \f(CW$thr\fR\->\fBget_stack_size()\fR;" 4
+.IX Item "$size = $thr->get_stack_size();"
+Returns the stack size for a particular thread. A return value of zero
+indicates the system default stack size was used for the thread.
+.ie n .IP "$old_size = threads\->set_stack_size($new_size);" 4
+.el .IP "\f(CW$old_size\fR = threads\->set_stack_size($new_size);" 4
+.IX Item "$old_size = threads->set_stack_size($new_size);"
+Sets a new default per-thread stack size, and returns the previous setting.
+.Sp
+Some platforms have a minimum thread stack size. Trying to set the stack size
+below this value will result in a warning, and the minimum stack size will be
+used.
+.Sp
+Some Linux platforms have a maximum stack size. Setting too large of a stack
+size will cause thread creation to fail.
+.Sp
+If needed, \f(CW$new_size\fR will be rounded up to the next multiple of the memory
+page size (usually 4096 or 8192).
+.Sp
+Threads created after the stack size is set will then either call
+\&\f(CWpthread_attr_setstacksize()\fR \fI(for pthreads platforms)\fR, or supply the
+stack size to \f(CWCreateThread()\fR \fI(for Win32 Perl)\fR.
+.Sp
+(Obviously, this call does not affect any currently extant threads.)
+.IP "use threads ('stack_size' => VALUE);" 4
+.IX Item "use threads ('stack_size' => VALUE);"
+This sets the default per-thread stack size at the start of the application.
+.ie n .IP $ENV{'PERL5_ITHREADS_STACK_SIZE'} 4
+.el .IP \f(CW$ENV\fR{'PERL5_ITHREADS_STACK_SIZE'} 4
+.IX Item "$ENV{'PERL5_ITHREADS_STACK_SIZE'}"
+The default per-thread stack size may be set at the start of the application
+through the use of the environment variable \f(CW\*(C`PERL5_ITHREADS_STACK_SIZE\*(C'\fR:
+.Sp
+.Vb 3
+\& PERL5_ITHREADS_STACK_SIZE=1048576
+\& export PERL5_ITHREADS_STACK_SIZE
+\& perl \-e\*(Aquse threads; print(threads\->get_stack_size(), "\en")\*(Aq
+.Ve
+.Sp
+This value overrides any \f(CW\*(C`stack_size\*(C'\fR parameter given to \f(CW\*(C`use threads\*(C'\fR. Its
+primary purpose is to permit setting the per-thread stack size for legacy
+threaded applications.
+.IP "threads\->create({'stack_size' => VALUE}, FUNCTION, ARGS)" 4
+.IX Item "threads->create({'stack_size' => VALUE}, FUNCTION, ARGS)"
+To specify a particular stack size for any individual thread, call
+\&\f(CW\*(C`\->create()\*(C'\fR with a hash reference as the first argument:
+.Sp
+.Vb 2
+\& my $thr = threads\->create({\*(Aqstack_size\*(Aq => 32*4096},
+\& \e&foo, @args);
+.Ve
+.ie n .IP "$thr2 = $thr1\->create(FUNCTION, ARGS)" 4
+.el .IP "\f(CW$thr2\fR = \f(CW$thr1\fR\->create(FUNCTION, ARGS)" 4
+.IX Item "$thr2 = $thr1->create(FUNCTION, ARGS)"
+This creates a new thread (\f(CW$thr2\fR) that inherits the stack size from an
+existing thread (\f(CW$thr1\fR). This is shorthand for the following:
+.Sp
+.Vb 3
+\& my $stack_size = $thr1\->get_stack_size();
+\& my $thr2 = threads\->create({\*(Aqstack_size\*(Aq => $stack_size},
+\& FUNCTION, ARGS);
+.Ve
+.SH "THREAD SIGNALLING"
+.IX Header "THREAD SIGNALLING"
+When safe signals is in effect (the default behavior \- see "Unsafe signals"
+for more details), then signals may be sent and acted upon by individual
+threads.
+.ie n .IP $thr\->kill('SIG...'); 4
+.el .IP \f(CW$thr\fR\->kill('SIG...'); 4
+.IX Item "$thr->kill('SIG...');"
+Sends the specified signal to the thread. Signal names and (positive) signal
+numbers are the same as those supported by
+\&\fBkill()\fR. For example, 'SIGTERM', 'TERM' and
+(depending on the OS) 15 are all valid arguments to \f(CW\*(C`\->kill()\*(C'\fR.
+.Sp
+Returns the thread object to allow for method chaining:
+.Sp
+.Vb 1
+\& $thr\->kill(\*(AqSIG...\*(Aq)\->join();
+.Ve
+.PP
+Signal handlers need to be set up in the threads for the signals they are
+expected to act upon. Here's an example for \fIcancelling\fR a thread:
+.PP
+.Vb 1
+\& use threads;
+\&
+\& sub thr_func
+\& {
+\& # Thread \*(Aqcancellation\*(Aq signal handler
+\& $SIG{\*(AqKILL\*(Aq} = sub { threads\->exit(); };
+\&
+\& ...
+\& }
+\&
+\& # Create a thread
+\& my $thr = threads\->create(\*(Aqthr_func\*(Aq);
+\&
+\& ...
+\&
+\& # Signal the thread to terminate, and then detach
+\& # it so that it will get cleaned up automatically
+\& $thr\->kill(\*(AqKILL\*(Aq)\->detach();
+.Ve
+.PP
+Here's another simplistic example that illustrates the use of thread
+signalling in conjunction with a semaphore to provide rudimentary \fIsuspend\fR
+and \fIresume\fR capabilities:
+.PP
+.Vb 2
+\& use threads;
+\& use Thread::Semaphore;
+\&
+\& sub thr_func
+\& {
+\& my $sema = shift;
+\&
+\& # Thread \*(Aqsuspend/resume\*(Aq signal handler
+\& $SIG{\*(AqSTOP\*(Aq} = sub {
+\& $sema\->down(); # Thread suspended
+\& $sema\->up(); # Thread resumes
+\& };
+\&
+\& ...
+\& }
+\&
+\& # Create a semaphore and pass it to a thread
+\& my $sema = Thread::Semaphore\->new();
+\& my $thr = threads\->create(\*(Aqthr_func\*(Aq, $sema);
+\&
+\& # Suspend the thread
+\& $sema\->down();
+\& $thr\->kill(\*(AqSTOP\*(Aq);
+\&
+\& ...
+\&
+\& # Allow the thread to continue
+\& $sema\->up();
+.Ve
+.PP
+CAVEAT: The thread signalling capability provided by this module does not
+actually send signals via the OS. It \fIemulates\fR signals at the Perl-level
+such that signal handlers are called in the appropriate thread. For example,
+sending \f(CW\*(C`$thr\->kill(\*(AqSTOP\*(Aq)\*(C'\fR does not actually suspend a thread (or the
+whole process), but does cause a \f(CW$SIG{\*(AqSTOP\*(Aq}\fR handler to be called in that
+thread (as illustrated above).
+.PP
+As such, signals that would normally not be appropriate to use in the
+\&\f(CWkill()\fR command (e.g., \f(CW\*(C`kill(\*(AqKILL\*(Aq, $$)\*(C'\fR) are okay to use with the
+\&\f(CW\*(C`\->kill()\*(C'\fR method (again, as illustrated above).
+.PP
+Correspondingly, sending a signal to a thread does not disrupt the operation
+the thread is currently working on: The signal will be acted upon after the
+current operation has completed. For instance, if the thread is \fIstuck\fR on
+an I/O call, sending it a signal will not cause the I/O call to be interrupted
+such that the signal is acted up immediately.
+.PP
+Sending a signal to a terminated/finished thread is ignored.
+.SH WARNINGS
+.IX Header "WARNINGS"
+.IP "Perl exited with active threads:" 4
+.IX Item "Perl exited with active threads:"
+If the program exits without all threads having either been joined or
+detached, then this warning will be issued.
+.Sp
+NOTE: If the \fImain\fR thread exits, then this warning cannot be suppressed
+using \f(CW\*(C`no warnings \*(Aqthreads\*(Aq;\*(C'\fR as suggested below.
+.IP "Thread creation failed: pthread_create returned #" 4
+.IX Item "Thread creation failed: pthread_create returned #"
+See the appropriate \fIman\fR page for \f(CW\*(C`pthread_create\*(C'\fR to determine the actual
+cause for the failure.
+.IP "Thread # terminated abnormally: ..." 4
+.IX Item "Thread # terminated abnormally: ..."
+A thread terminated in some manner other than just returning from its entry
+point function, or by using \f(CW\*(C`threads\->exit()\*(C'\fR. For example, the thread
+may have terminated because of an error, or by using \f(CW\*(C`die\*(C'\fR.
+.IP "Using minimum thread stack size of #" 4
+.IX Item "Using minimum thread stack size of #"
+Some platforms have a minimum thread stack size. Trying to set the stack size
+below this value will result in the above warning, and the stack size will be
+set to the minimum.
+.IP "Thread creation failed: pthread_attr_setstacksize(\fISIZE\fR) returned 22" 4
+.IX Item "Thread creation failed: pthread_attr_setstacksize(SIZE) returned 22"
+The specified \fISIZE\fR exceeds the system's maximum stack size. Use a smaller
+value for the stack size.
+.PP
+If needed, thread warnings can be suppressed by using:
+.PP
+.Vb 1
+\& no warnings \*(Aqthreads\*(Aq;
+.Ve
+.PP
+in the appropriate scope.
+.SH ERRORS
+.IX Header "ERRORS"
+.IP "This Perl not built to support threads" 4
+.IX Item "This Perl not built to support threads"
+The particular copy of Perl that you're trying to use was not built using the
+\&\f(CW\*(C`useithreads\*(C'\fR configuration option.
+.Sp
+Having threads support requires all of Perl and all of the XS modules in the
+Perl installation to be rebuilt; it is not just a question of adding the
+threads module (i.e., threaded and non-threaded Perls are binary
+incompatible).
+.IP "Cannot change stack size of an existing thread" 4
+.IX Item "Cannot change stack size of an existing thread"
+The stack size of currently extant threads cannot be changed, therefore, the
+following results in the above error:
+.Sp
+.Vb 1
+\& $thr\->set_stack_size($size);
+.Ve
+.IP "Cannot signal threads without safe signals" 4
+.IX Item "Cannot signal threads without safe signals"
+Safe signals must be in effect to use the \f(CW\*(C`\->kill()\*(C'\fR signalling method.
+See "Unsafe signals" for more details.
+.IP "Unrecognized signal name: ..." 4
+.IX Item "Unrecognized signal name: ..."
+The particular copy of Perl that you're trying to use does not support the
+specified signal being used in a \f(CW\*(C`\->kill()\*(C'\fR call.
+.SH "BUGS AND LIMITATIONS"
+.IX Header "BUGS AND LIMITATIONS"
+Before you consider posting a bug report, please consult, and possibly post a
+message to the discussion forum to see if what you've encountered is a known
+problem.
+.IP "Thread-safe modules" 4
+.IX Item "Thread-safe modules"
+See "Making your module threadsafe" in perlmod when creating modules that may
+be used in threaded applications, especially if those modules use non-Perl
+data, or XS code.
+.IP "Using non-thread-safe modules" 4
+.IX Item "Using non-thread-safe modules"
+Unfortunately, you may encounter Perl modules that are not \fIthread-safe\fR.
+For example, they may crash the Perl interpreter during execution, or may dump
+core on termination. Depending on the module and the requirements of your
+application, it may be possible to work around such difficulties.
+.Sp
+If the module will only be used inside a thread, you can try loading the
+module from inside the thread entry point function using \f(CW\*(C`require\*(C'\fR (and
+\&\f(CW\*(C`import\*(C'\fR if needed):
+.Sp
+.Vb 4
+\& sub thr_func
+\& {
+\& require Unsafe::Module
+\& # Unsafe::Module\->import(...);
+\&
+\& ....
+\& }
+.Ve
+.Sp
+If the module is needed inside the \fImain\fR thread, try modifying your
+application so that the module is loaded (again using \f(CW\*(C`require\*(C'\fR and
+\&\f(CW\*(C`\->import()\*(C'\fR) after any threads are started, and in such a way that no
+other threads are started afterwards.
+.Sp
+If the above does not work, or is not adequate for your application, then file
+a bug report on <https://rt.cpan.org/Public/> against the problematic module.
+.IP "Memory consumption" 4
+.IX Item "Memory consumption"
+On most systems, frequent and continual creation and destruction of threads
+can lead to ever-increasing growth in the memory footprint of the Perl
+interpreter. While it is simple to just launch threads and then
+\&\f(CW\*(C`\->join()\*(C'\fR or \f(CW\*(C`\->detach()\*(C'\fR them, for long-lived applications, it is
+better to maintain a pool of threads, and to reuse them for the work needed,
+using queues to notify threads of pending work. The CPAN
+distribution of this module contains a simple example
+(\fIexamples/pool_reuse.pl\fR) illustrating the creation, use and monitoring of a
+pool of \fIreusable\fR threads.
+.IP "Current working directory" 4
+.IX Item "Current working directory"
+On all platforms except MSWin32, the setting for the current working directory
+is shared among all threads such that changing it in one thread (e.g., using
+\&\f(CWchdir()\fR) will affect all the threads in the application.
+.Sp
+On MSWin32, each thread maintains its own the current working directory
+setting.
+.IP Locales 4
+.IX Item "Locales"
+Prior to Perl 5.28, locales could not be used with threads, due to various
+race conditions. Starting in that release, on systems that implement
+thread-safe locale functions, threads can be used, with some caveats.
+This includes Windows starting with Visual Studio 2005, and systems compatible
+with POSIX 2008. See "Multi-threaded operation" in perllocale.
+.Sp
+Each thread (except the main thread) is started using the C locale. The main
+thread is started like all other Perl programs; see "ENVIRONMENT" in perllocale.
+You can switch locales in any thread as often as you like.
+.Sp
+If you want to inherit the parent thread's locale, you can, in the parent, set
+a variable like so:
+.Sp
+.Vb 1
+\& $foo = POSIX::setlocale(LC_ALL, NULL);
+.Ve
+.Sp
+and then pass to threads\->\fBcreate()\fR a sub that closes over \f(CW$foo\fR. Then, in
+the child, you say
+.Sp
+.Vb 1
+\& POSIX::setlocale(LC_ALL, $foo);
+.Ve
+.Sp
+Or you can use the facilities in threads::shared to pass \f(CW$foo\fR;
+or if the environment hasn't changed, in the child, do
+.Sp
+.Vb 1
+\& POSIX::setlocale(LC_ALL, "");
+.Ve
+.IP "Environment variables" 4
+.IX Item "Environment variables"
+Currently, on all platforms except MSWin32, all \fIsystem\fR calls (e.g., using
+\&\f(CWsystem()\fR or back-ticks) made from threads use the environment variable
+settings from the \fImain\fR thread. In other words, changes made to \f(CW%ENV\fR in
+a thread will not be visible in \fIsystem\fR calls made by that thread.
+.Sp
+To work around this, set environment variables as part of the \fIsystem\fR call.
+For example:
+.Sp
+.Vb 2
+\& my $msg = \*(Aqhello\*(Aq;
+\& system("FOO=$msg; echo \e$FOO"); # Outputs \*(Aqhello\*(Aq to STDOUT
+.Ve
+.Sp
+On MSWin32, each thread maintains its own set of environment variables.
+.IP "Catching signals" 4
+.IX Item "Catching signals"
+Signals are \fIcaught\fR by the main thread (thread ID = 0) of a script.
+Therefore, setting up signal handlers in threads for purposes other than
+"THREAD SIGNALLING" as documented above will not accomplish what is
+intended.
+.Sp
+This is especially true if trying to catch \f(CW\*(C`SIGALRM\*(C'\fR in a thread. To handle
+alarms in threads, set up a signal handler in the main thread, and then use
+"THREAD SIGNALLING" to relay the signal to the thread:
+.Sp
+.Vb 10
+\& # Create thread with a task that may time out
+\& my $thr = threads\->create(sub {
+\& threads\->yield();
+\& eval {
+\& $SIG{ALRM} = sub { die("Timeout\en"); };
+\& alarm(10);
+\& ... # Do work here
+\& alarm(0);
+\& };
+\& if ($@ =~ /Timeout/) {
+\& warn("Task in thread timed out\en");
+\& }
+\& };
+\&
+\& # Set signal handler to relay SIGALRM to thread
+\& $SIG{ALRM} = sub { $thr\->kill(\*(AqALRM\*(Aq) };
+\&
+\& ... # Main thread continues working
+.Ve
+.IP "Parent-child threads" 4
+.IX Item "Parent-child threads"
+On some platforms, it might not be possible to destroy \fIparent\fR threads while
+there are still existing \fIchild\fR threads.
+.IP "Unsafe signals" 4
+.IX Item "Unsafe signals"
+Since Perl 5.8.0, signals have been made safer in Perl by postponing their
+handling until the interpreter is in a \fIsafe\fR state. See
+"Safe Signals" in perl58delta and "Deferred Signals (Safe Signals)" in perlipc
+for more details.
+.Sp
+Safe signals is the default behavior, and the old, immediate, unsafe
+signalling behavior is only in effect in the following situations:
+.RS 4
+.IP \(bu 4
+Perl has been built with \f(CW\*(C`PERL_OLD_SIGNALS\*(C'\fR (see \f(CW\*(C`perl\ \-V\*(C'\fR).
+.IP \(bu 4
+The environment variable \f(CW\*(C`PERL_SIGNALS\*(C'\fR is set to \f(CW\*(C`unsafe\*(C'\fR
+(see "PERL_SIGNALS" in perlrun).
+.IP \(bu 4
+The module Perl::Unsafe::Signals is used.
+.RE
+.RS 4
+.Sp
+If unsafe signals is in effect, then signal handling is not thread-safe, and
+the \f(CW\*(C`\->kill()\*(C'\fR signalling method cannot be used.
+.RE
+.IP "Identity of objects returned from threads" 4
+.IX Item "Identity of objects returned from threads"
+When a value is returned from a thread through a \f(CW\*(C`join\*(C'\fR operation,
+the value and everything that it references is copied across to the
+joining thread, in much the same way that values are copied upon thread
+creation. This works fine for most kinds of value, including arrays,
+hashes, and subroutines. The copying recurses through array elements,
+reference scalars, variables closed over by subroutines, and other kinds
+of reference.
+.Sp
+However, everything referenced by the returned value is a fresh copy in
+the joining thread, even if a returned object had in the child thread
+been a copy of something that previously existed in the parent thread.
+After joining, the parent will therefore have a duplicate of each such
+object. This sometimes matters, especially if the object gets mutated;
+this can especially matter for private data to which a returned subroutine
+provides access.
+.IP "Returning blessed objects from threads" 4
+.IX Item "Returning blessed objects from threads"
+Returning blessed objects from threads does not work. Depending on the classes
+involved, you may be able to work around this by returning a serialized
+version of the object (e.g., using Data::Dumper or Storable), and then
+reconstituting it in the joining thread. If you're using Perl 5.10.0 or
+later, and if the class supports shared objects,
+you can pass them via shared queues.
+.IP "END blocks in threads" 4
+.IX Item "END blocks in threads"
+It is possible to add END blocks to threads by using require or
+eval with the appropriate code. These \f(CW\*(C`END\*(C'\fR blocks
+will then be executed when the thread's interpreter is destroyed (i.e., either
+during a \f(CW\*(C`\->join()\*(C'\fR call, or at program termination).
+.Sp
+However, calling any threads methods in such an \f(CW\*(C`END\*(C'\fR block will most
+likely \fIfail\fR (e.g., the application may hang, or generate an error) due to
+mutexes that are needed to control functionality within the threads module.
+.Sp
+For this reason, the use of \f(CW\*(C`END\*(C'\fR blocks in threads is \fBstrongly\fR
+discouraged.
+.IP "Open directory handles" 4
+.IX Item "Open directory handles"
+In perl 5.14 and higher, on systems other than Windows that do
+not support the \f(CW\*(C`fchdir\*(C'\fR C function, directory handles (see
+opendir) will not be copied to new
+threads. You can use the \f(CW\*(C`d_fchdir\*(C'\fR variable in Config.pm to
+determine whether your system supports it.
+.Sp
+In prior perl versions, spawning threads with open directory handles would
+crash the interpreter.
+[perl #75154] <https://rt.perl.org/rt3/Public/Bug/Display.html?id=75154>
+.IP "Detached threads and global destruction" 4
+.IX Item "Detached threads and global destruction"
+If the main thread exits while there are detached threads which are still
+running, then Perl's global destruction phase is not executed because
+otherwise certain global structures that control the operation of threads and
+that are allocated in the main thread's memory may get destroyed before the
+detached thread is destroyed.
+.Sp
+If you are using any code that requires the execution of the global
+destruction phase for clean up (e.g., removing temp files), then do not use
+detached threads, but rather join all threads before exiting the program.
+.IP "Perl Bugs and the CPAN Version of threads" 4
+.IX Item "Perl Bugs and the CPAN Version of threads"
+Support for threads extends beyond the code in this module (i.e.,
+\&\fIthreads.pm\fR and \fIthreads.xs\fR), and into the Perl interpreter itself. Older
+versions of Perl contain bugs that may manifest themselves despite using the
+latest version of threads from CPAN. There is no workaround for this other
+than upgrading to the latest version of Perl.
+.Sp
+Even with the latest version of Perl, it is known that certain constructs
+with threads may result in warning messages concerning leaked scalars or
+unreferenced scalars. However, such warnings are harmless, and may safely be
+ignored.
+.Sp
+You can search for threads related bug reports at
+<https://rt.cpan.org/Public/>. If needed submit any new bugs, problems,
+patches, etc. to: <https://rt.cpan.org/Public/Dist/Display.html?Name=threads>
+.SH REQUIREMENTS
+.IX Header "REQUIREMENTS"
+Perl 5.8.0 or later
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+threads on MetaCPAN:
+<https://metacpan.org/release/threads>
+.PP
+Code repository for CPAN distribution:
+<https://github.com/Dual\-Life/threads>
+.PP
+threads::shared, perlthrtut
+.PP
+<https://www.perl.com/pub/a/2002/06/11/threads.html> and
+<https://www.perl.com/pub/a/2002/09/04/threads.html>
+.PP
+Perl threads mailing list:
+<https://lists.perl.org/list/ithreads.html>
+.PP
+Stack size discussion:
+<https://www.perlmonks.org/?node_id=532956>
+.PP
+Sample code in the \fIexamples\fR directory of this distribution on CPAN.
+.SH AUTHOR
+.IX Header "AUTHOR"
+Artur Bergman <sky AT crucially DOT net>
+.PP
+CPAN version produced by Jerry D. Hedden <jdhedden AT cpan DOT org>
+.SH LICENSE
+.IX Header "LICENSE"
+threads is released under the same license as Perl.
+.SH ACKNOWLEDGEMENTS
+.IX Header "ACKNOWLEDGEMENTS"
+Richard Soderberg <perl AT crystalflame DOT net> \-
+Helping me out tons, trying to find reasons for races and other weird bugs!
+.PP
+Simon Cozens <simon AT brecon DOT co DOT uk> \-
+Being there to answer zillions of annoying questions
+.PP
+Rocco Caputo <troc AT netrus DOT net>
+.PP
+Vipul Ved Prakash <mail AT vipul DOT net> \-
+Helping with debugging
+.PP
+Dean Arnold <darnold AT presicient DOT com> \-
+Stack size API