***** Future Features / Interface Changes ***** optimizations: - implement more methods using custom filters (to reduce Storable usage) - support alternate, faster locking mechanisms (filesystem and/or SysV shmem) - allow for shared memory as transport medium - one alternative is to use BerkeleyDB, e.g. forks::BerkeleyDB join() needs to be able to propagate (die) errors to threads. Currently, it only return undef in error cases. Make thread objects shared in nature, such that their properties may be read across all threads. Will make _handle more reliable, and allow for thread state params to be persisted. Add support for CLONE_SKIP, if possible. Or maybe just add support for a PRECLONE class method, which will be called in parent context. (http://perldoc.perl.org/perlmod.html#Making-your-module-threadsafe-threadsafe-thread-safe-module%2c-threadsafe-module%2c-thread-safe-CLONE-CLONE_SKIP-thread-threads-ithread) Add a method to give the user run-time privilege control over Unix socket file descriptors (for additional security control). ***** Issues to Address ***** Environment variables should be shared among all threads (ithreads behavior). Current working directory should be shared among all threads (ithreads behavior). Memory is currently not reclaimed for shared variables that are no longer referenced by any thread. Determine if it is possible to recover all memory from detached threads. Joined threads reclaim all shared memory (very stable memory usage); detached threads currently use a small amount of memory (~200Kb/100K threads) even after they complete. exit() in a thread may allow other threads that were waiting to join that thread to continue before they are terminated (race condition). Join should not return. Add more defensive logic in _join() to prevent hang on join (for processes that have already terminated). May wish to check client socket when join for that thread is requested: if socket exception, then assume client terminated; otherwise, wait for client (regularly checking client socket connection to determine if it has prematurely closed). In rare cases, if the main thread dies, the server process doesn't appear to shut down correctly. Sometimes, it appears to use high CPU usage (is stuck in a loop somewhere). It is likely that a socket disconnect is getting a read or write while loop stuck in a loop, and that additional error checking (or non-error occurrence but no change to the amount of data read/written) might help the state of things. Reproducing this one is pretty hard--I can't create the exact conditions yet to manually trigger it. Problem last seen in forks 0.20. Note that this issue may have been squashed in forks 0.21, as most of the socket handling was rewritten in that release. Need to look into why some signals very rarely are not handled by threads (i.e. SIGTERM should cause thread to exit--but thread appears to have ignored signal. Is this a side effect of Perl's safe signal handling mechanism?). The thread does appear to actually get the signal, but sometimes it doesn't seem to completely exit. Problem last seen in forks 0.23, but not seen since forks 0.25, so may be resolved. ***** Miscellaneous Items ***** May need to switch to using Sys::SigAction instead of SIG for more consistent signal behavior across different Perl versions. Move source filter from forks.pm to forks::shared.pm, although I doubt that there will be many cases where forks would only be used. Add additional tests to rigorously test tied handle (for shared var) behavior. Test delete with single, hash slice, and array slice elements. Add tests for $thr->join() error cases. Cache signal names from Config.pm for higher performance (avoid tied access)? Begin adding some sort of CLONE forks.pm compatibility framework to insure that modules that implement non-forks.pm CLONE methods are supported. Currently, DBI is the only known module that may need a CLONE patch, and this is only to suppress annoying warning for resources that are closed (or is this something that actually needs to be fixed in DBI?) Signals sent to main thread can propagate to all threads. We need to prevent this from happening, if possible, to replicate threads.pm behavior. This may be due to signal being sent to a process group (so it may not be blockable). Add recursive lock tests with cond_* (to test that recursive locks are correctly acquired and released). Figure out how to suppress SIGIOT warnings on certain plaforms (Solaris): "Caught a SIGIOT at /usr/local/lib/perl5/site_perl/5.8.7/sun4-solaris-64/forks/signals.pm line 59" Add documentation explaining that forks installs a SIGCHLD handler by default, and that system calls in your user code may be interrupted by this handler at any time (threads exiting), depending on the system call and if your kernel auto-continues the system call after handling the signal. NOTE: There still appears to be an issue with the last value of $! not being cleared and EINTR still being returned on the next accept() vall. Setting $! to undef before calling the system call appears to clear the issue. This is system behavior outside of forks module that needs more research to resolve. A few suggestions if this is an issue: 1. Check if $! == POSIX::EINTR() if your system call returns undef. If so, manually re-enter into (call again) the system call, like: while((my $conn = $server->accept) || $! == EINTR) { next if $! == EINTR; ... } This is the most portable solution. 2. Localize $SIG{CHLD} = 'IGNORE' when performing your interruptible (non-reentrant) system call. For example: my $conn; my $loop = 1; while($loop) { { local $SIG{CHLD} = 'IGNORE'; $conn = $server->accept; next if $! == EINTR; last unless $conn; } ... } This is a more verbose but acceptable solution. 3. Set $SIG{CHLD} = 'IGNORE' after loading the forks module. This is the simplest solution as it applies globally to all system calls, but be warned that this may cause the exit value of your script to be ignored (returns -1) depending on your kernel behavior. You can always check your kernel behavior by executing the following at a shell command line: perl -e '$SIG{CHLD} = "IGNORE"; exit(42);'; echo "Expected 42. Got $?"