lelotto85 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, i'm trying to create a cgi script that works with threads. The problem is that my little script works perfectly when i run it from command-line but, as soon as a try to call it from my browser, I get a [notice] child pid 7715 exit signal Segmentation fault (11) in apache log. I saw that the Segfault is thrown exactly when I create a new thread

Here is the code. File Test.pm

package Test; sub thr_func { my @args = @_; print('Thread started: ', join(' ', @args), "\n"); sleep $args[0]; return qw(all done); } 1;
And File thread.pl
use threads; use strict; use CGI qw(:standard); use CGI::Carp qw(warningsToBrowser fatalsToBrowser); use Test; print header('text/html'); my $r = shift; my $MAX_THREADS = 5; my @res; for my $i (1 .. $MAX_THREADS) { threads->create('Test::thr_func', $i*2); } print "Here I am!\n"; while (threads->list()) { sleep 1; print "running...\n"; foreach my $thread (threads->list(threads::joinable)) { if($thread->is_joinable()) {; push(@res, $thread->join()); } } } print "That's all folks!\n"; #Here goes the end of html code
I run Apache 2 with mod_perl 2.0.4 on Ubuntu 11.04. My site is configured with these params:
<Directory "/var/www/cgi-bin"> SetHandler perl-script PerlResponseHandler ModPerl::PerlRun #PerlResponseHandler ModPerl::Registry PerlHandler Apache::Registry PerlOptions +ParseHeaders +GlobalRequest AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory>

Running from command-line the output is (as aspected):

Content-Type: text/html; charset=ISO-8859-1 Thread started: 4 Thread started: 2 Thread started: 6 Thread started: 8 Here I am! Thread started: 10 running... running... running... running... running... running... running... running... running... running... That's all folks!
Could you help me to find the problem? Thanks

Replies are listed 'Best First'.
Re: cgi thread creation segfault
by Eliya (Vicar) on Dec 28, 2011 at 13:14 UTC

    The situation between running the script from the command line and running it from mod_perl is a fundamentally different one. When running it from the command line, your Perl interpreter is a dedicated process, while with mod_perl, the interpreter has been dynamically loaded into the Apache process (as a shared library), i.e. the Perl interpreter and Apache are one and the same process.

    Such close cooperation requires the involved parties to behave as expected. And apparently, Apache does not expect the Perl part to create multiple threads of themselves. In other words, Apache - at least the MPM you're using (prefork?) - doesn't seem to be thread-safe.

      I'm using MPM worker (not prefork)... These are my apache settings:

      Server version: Apache/2.2.17 (Ubuntu) Server built: Nov 3 2011 02:13:18 Server's Module Magic Number: 20051115:25 Server loaded: APR 1.4.2, APR-Util 1.3.9 Compiled using: APR 1.4.2, APR-Util 1.3.9 Architecture: 32-bit Server MPM: Worker threaded: yes (fixed thread count) forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/worker" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=128 -D HTTPD_ROOT="/etc/apache2" -D SUEXEC_BIN="/usr/lib/apache2/suexec" -D DEFAULT_PIDLOG="/var/run/apache2.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="mime.types" -D SERVER_CONFIG_FILE="apache2.conf"
      As you can see i'm not using prefork MPM and that's why I thought apache could create threads while executing my perl script... Is my reasoning wrong? Maybe I'm missing some parameter or I misconfigured some IfModule statement.

        I thought apache could create threads while executing my perl script...

        The worker model uses threads for handling multiple requests.  From the docs:

        "A single control process (the parent) is responsible for launching child processes. Each child process creates a fixed number of server threads as specified in the ThreadsPerChild directive, as well as a listener thread which listens for connections and passes them to a server thread for processing when they arrive."

        This is not the same as creating threads "while executing" the Perl script. The situation you have is that one of the worker threads - with Perl being an integral part of them - is again trying to create further threads.  I'm not too familiar with the implementation details of the worker module to tell if that's supposed to work or not... (Practice shows, it doesn't :)

      In other words, Apache - at least the MPM you're using (prefork?) - doesn't seem to be thread-safe.

      <speculation>I would suppose prefork to be able to run this kind of script or at least pose the least problems, while any threaded MPMs will likely (and obviously do) become very confused if some other component such as Perl starts fiddling with the thread pool created by any of their processes.</speculation>

        I'm a bit confused... @mbethke, are you telling me that I should try with MPM prefork?

        I've been scraping the apache documentation for days and I found about MPM prefork: It is appropriate for sites that need to avoid threading for compatibility with non-thread-safe libraries So I thought this could not be the best approach. Otherwise I didn't understand how can I make a multi-threaded perl script working under Apache... Any help is welcome even if this could not be the correct place to post this request... Thank you very much.