gdipfrun_replacethread.pm 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #######################################################################
  2. # gdipfrun.pm
  3. #
  4. # This routine is a common FastCGI template.
  5. #
  6. # It starts two non-looping acceptor threads initially, and starts a
  7. # replacement acceptor when a current acceptor accepts a connection.
  8. #
  9. # See COPYING for licensing information.
  10. #
  11. #######################################################################
  12. # Perl modules
  13. use strict;
  14. use FCGI;
  15. use POSIX;
  16. # global variables
  17. use vars qw($cgi_exit $conf $logger $bad_config);
  18. # GnuDIP modules
  19. use gdiplib;
  20. sub gdipfrun {
  21. # functions to run in thread
  22. my $initfunc = shift;
  23. my $acptfunc = shift;
  24. if (! $initfunc) {
  25. print STDERR "GnuDIP FastCGI has exited - no initialization function passed\n";
  26. exit 1;
  27. }
  28. if (! $acptfunc) {
  29. print STDERR "GnuDIP FastCGI has exited - no accept function passed\n";
  30. exit 1;
  31. }
  32. # force persistence
  33. $$conf{'persistance'} = 'YES';
  34. # create a pipe to receive notifications
  35. pipe(NTFYREAD, NTFYWRITE);
  36. # set flush before forks
  37. select(NTFYWRITE);
  38. $| = 1;
  39. select(STDERR);
  40. $| = 1;
  41. select(STDOUT);
  42. $| = 1;
  43. # avoid zombie children
  44. sub REAPER {
  45. wait();
  46. $SIG{CHLD} = \&REAPER;
  47. }
  48. $SIG{CHLD} = \&REAPER;
  49. # start two inital acceptors
  50. # - can start any number
  51. fork_thread($initfunc, $acptfunc);
  52. fork_thread($initfunc, $acptfunc);
  53. # start new acceptor to replace each old one
  54. my $ntfy;
  55. while ($ntfy = <NTFYREAD>) {
  56. $ntfy = '' if ! defined $ntfy;
  57. chomp($ntfy);
  58. if ($ntfy eq '+') {
  59. # start replacement acceptor
  60. fork_thread($initfunc, $acptfunc);
  61. next;
  62. }
  63. last;
  64. }
  65. # thread got shut down request?
  66. return if $ntfy eq 'x';
  67. # should never get here
  68. # wait for all children to stop
  69. while (wait() gt 0) {};
  70. print STDERR "GnuDIP FastCGI has ended unexpectedly\n";
  71. }
  72. # subroutine to fork a thread
  73. sub fork_thread {
  74. # functions to run in thread
  75. my $initfunc = shift;
  76. my $acptfunc = shift;
  77. # spawn child process
  78. defined(my $pid = fork()) or die "fork failed: $!\n";
  79. return $pid if $pid gt 0;
  80. # we are the child
  81. thread($initfunc, $acptfunc);
  82. POSIX::_exit(0);
  83. }
  84. # subroutine for each thread
  85. sub thread {
  86. # functions to run in thread
  87. my $initfunc = shift;
  88. my $acptfunc = shift;
  89. # create request
  90. my $req = FCGI::Request();
  91. if (! $req->IsFastCGI()) {
  92. print NTFYWRITE "!\n";
  93. print STDERR "GnuDIP FastCGI not called as FastCGI program\n";
  94. return;
  95. }
  96. # configuration error handler for now
  97. $bad_config = sub {
  98. # go do Finish
  99. goto FINISH;
  100. };
  101. # run initialization
  102. &$initfunc();
  103. # accept connection
  104. my $rtc = $req->Accept();
  105. # shut down request?
  106. if ($rtc eq -1) {
  107. print NTFYWRITE "x\n";
  108. return;
  109. }
  110. # notify parent
  111. print NTFYWRITE "+\n";
  112. # did Accept succeed?
  113. return if $rtc ne 0;
  114. # override for "exit"
  115. $cgi_exit = sub {
  116. # go do Finish
  117. goto FINISH;
  118. };
  119. # run the CGI
  120. &$acptfunc();
  121. FINISH:
  122. undef $bad_config;
  123. undef $cgi_exit;
  124. $req->Finish();
  125. }
  126. #####################################################
  127. # must return 1
  128. #####################################################
  129. 1;