gdipfrun_variablethread.pm 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #######################################################################
  2. # gdipfrun.pm
  3. #
  4. # This routine is a common FastCGI template.
  5. #
  6. # It starts two looping acceptor threads initially, and starts another
  7. # acceptor whenever all acceptors have a connection. These acceptors
  8. # remain running forever.
  9. #
  10. # See COPYING for licensing information.
  11. #
  12. #######################################################################
  13. # Perl modules
  14. use strict;
  15. use FCGI;
  16. use POSIX;
  17. # global variables
  18. use vars qw($cgi_exit $conf $bad_config);
  19. # GnuDIP modules
  20. use gdiplib;
  21. sub gdipfrun {
  22. # functions to run in thread
  23. my $initfunc = shift;
  24. my $acptfunc = shift;
  25. if (! $initfunc) {
  26. print STDERR "GnuDIP FastCGI has exited - no initialization function passed\n";
  27. exit 1;
  28. }
  29. if (! $acptfunc) {
  30. print STDERR "GnuDIP FastCGI has exited - no accept function passed\n";
  31. exit 1;
  32. }
  33. # number of threads running
  34. # - this many will be started initially
  35. my $pcnt = 2;
  36. # force persistence
  37. $$conf{'persistance'} = 'YES';
  38. # create a pipe to receive notifications
  39. pipe(NTFYREAD, NTFYWRITE);
  40. # flush before forks
  41. select(NTFYWRITE);
  42. $| = 1;
  43. select(STDERR);
  44. $| = 1;
  45. select(STDOUT);
  46. $| = 1;
  47. # count of current connections
  48. my $ccnt = 0;
  49. # start threads
  50. for (my $idx = 0; $idx < $pcnt; $idx++) {
  51. fork_thread($initfunc, $acptfunc);
  52. }
  53. # keep track of notifications
  54. while (my $ntfy = <NTFYREAD>) {
  55. $ntfy = '' if ! defined $ntfy;
  56. chomp($ntfy);
  57. if ($ntfy eq '-') {
  58. # an acceptor has become available
  59. $ccnt--;
  60. next;
  61. }
  62. if ($ntfy eq '+') {
  63. # an acceptor has become unavailable
  64. $ccnt++;
  65. if ($ccnt ge $pcnt)) {
  66. # all acceptors are in use
  67. fork_thread($initfunc, $acptfunc);
  68. $pcnt++;
  69. print STDERR "GnuDIP FastCGI has increased number of threads to $pcnt\n";
  70. }
  71. next;
  72. }
  73. if ($ntfy eq 'x') {
  74. # an acceptor has shut down
  75. $pcnt--;
  76. print STDERR "GnuDIP FastCGI has decreased number of threads to $pcnt\n";
  77. next if $pcnt gt 0;
  78. }
  79. last;
  80. }
  81. # all threads shut down?
  82. return if $pcnt eq 0;
  83. # should never get here
  84. # wait for all children to stop
  85. while (wait() gt 0) {};
  86. # should never get here
  87. print STDERR "GnuDIP FastCGI has ended unexpectedly\n";
  88. }
  89. # subroutine to fork a thread
  90. sub fork_thread {
  91. # functions to run in thread
  92. my $initfunc = shift;
  93. my $acptfunc = shift;
  94. # spawn child process
  95. defined(my $pid = fork()) or die "fork failed: $!\n";
  96. return $pid if $pid gt 0;
  97. # we are the child
  98. thread($initfunc, $acptfunc);
  99. POSIX::_exit(0);
  100. }
  101. # subroutine for each thread
  102. sub thread {
  103. # functions to run in thread
  104. my $initfunc = shift;
  105. my $acptfunc = shift;
  106. # create request
  107. my $req = FCGI::Request();
  108. if (! $req->IsFastCGI()) {
  109. print NTFYWRITE "!\n";
  110. print STDERR "GnuDIP FastCGI not called as FastCGI program\n";
  111. return;
  112. }
  113. # configuration error handler for now
  114. $bad_config = sub {
  115. # go do Finish
  116. goto FINISH;
  117. };
  118. # run initialization
  119. &$initfunc();
  120. # accept connections
  121. my $rtc;
  122. while (($rtc = $req->Accept()) eq 0) {
  123. # notify parent
  124. print NTFYWRITE "+\n";
  125. # override for "exit"
  126. $cgi_exit = sub {
  127. # next connection
  128. goto ENDLOOP;
  129. };
  130. # run the CGI
  131. &$acptfunc();
  132. ENDLOOP:
  133. undef $cgi_exit;
  134. $req->Finish();
  135. # notify parent
  136. print NTFYWRITE "-\n";
  137. }
  138. # shut down request?
  139. if ($rtc eq -1) {
  140. print NTFYWRITE "x\n";
  141. return;
  142. }
  143. FINISH:
  144. undef $bad_config;
  145. # should never get here
  146. print NTFYWRITE "!\n";
  147. print STDERR "GnuDIP FastCGI thread has ended unexpectedly\n";
  148. }
  149. #####################################################
  150. # must return 1
  151. #####################################################
  152. 1;