PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/MEME/website/scripts/Process.pm

https://bitbucket.org/bdartigu/stagereport
Perl | 183 lines | 146 code | 14 blank | 23 comment | 12 complexity | ca9dc42367cfd7bdbe16620e8409ef70 MD5 | raw file
  1. # $Id: Process.pm,v 1.1.1.1 2004/10/07 19:44:13 cegrant Exp $
  2. # Paul Pavlidis 2000
  3. # Functions for managing processes. Specifically, for handling background processes, errors in same, and cancelations by users.
  4. package Process;
  5. require Exporter;
  6. @ISA = qw(Exporter);
  7. @EXPORT = qw(
  8. cancelJob
  9. forkOK
  10. isDone
  11. readSemaphore
  12. setUpSpawn
  13. writeSemaphore
  14. );
  15. use strict;
  16. use MetaGlobals;
  17. use CGIutil;
  18. #-----------------------------------------------------------------
  19. # End a background process which was canceled by the user
  20. #-----------------------------------------------------------------
  21. sub cancelJob($$) {
  22. my ($pid, $uid) = @_;
  23. my $runningModPerl = $ENV{MOD_PERL};
  24. # Make sure the pid we are handed agrees with the one the user's job is running under.
  25. warn "Trying to kill $pid for $uid. I am process $$, $ENV{MOD_PERL}\n";
  26. my $sema = readSemaphore($uid);
  27. if ($sema) {
  28. $sema =~ m/^([0-9]+)\s.*?([0-9]+)\s/;
  29. my $userspid = $2;
  30. die "Hey! That isn't the PID I expected! ($userspid != $pid, $sema)\n" unless $userspid == $pid;
  31. # Be very paranoid about the pid. (this might be redundant)
  32. sanity($pid);
  33. $pid =~ m/^([0-9]+)$/;
  34. $pid = $1;
  35. # Is it already dead?
  36. if (kill 0 => $pid) {
  37. warn "$pid is still alive\n";
  38. } else {
  39. warn "$pid is already dead, probably of natural causes.\n";
  40. return 1;
  41. }
  42. # Try to kill it.
  43. warn "Looks okay to kill. Sending 'QUIT' to $pid\n";
  44. kill 'QUIT' => $pid; # we've registered a QUIT handler to 'die'.
  45. # Did it die? Wait briefly to make sure change registers. (This is debug code).
  46. sleep 1;
  47. if ( kill 0 => $pid ) {
  48. warn "Seems I failed to kill $pid: $!\n";
  49. return 0;
  50. } else {
  51. warn "Seems I have successfully killed $pid (or it died of natural causes)\n";
  52. return 1;
  53. }
  54. } else {
  55. return 0;
  56. }
  57. } # sub cancelJob
  58. #-----------------------------------------------------------------
  59. # Figure out if it is okay to fork on this system.
  60. #-----------------------------------------------------------------
  61. sub forkOK() {
  62. # Fork is okay under unix but not windows unless perl is v5.6
  63. # (supposedly) We don't want to fork at all under modperl
  64. # (performance killer), but use another trick (post_connection)
  65. my $runningModPerl = $ENV{MOD_PERL};
  66. my $forkOK = ( $^O !~ /MSWin32/i && !$runningModPerl) ? 1 : 0; # don't try to fork under windows. It don't work (?)
  67. return $forkOK;
  68. } # sub forkOK
  69. #-----------------------------------------------------------------
  70. # Figure out if a given job is complete
  71. #------------------------------------------------------------------
  72. sub isDone($$$) {
  73. my ($pid, $uid, $sema) = @_;
  74. # warn "isDone got PID:$pid UID:$uid $sema\n";
  75. # be optimistic: is it done? (note that the order of these is very
  76. # important!)
  77. if ($sema && $sema =~ /DONE/) {
  78. return 'finished';
  79. } elsif ($sema && $sema =~ /ABORT/) {
  80. return 'aborted';
  81. } elsif ($sema && $sema =~ /RUN/) {
  82. return 'running';
  83. } elsif ($sema && $sema =~ /WAITING/) {
  84. return 'waiting';
  85. } else {
  86. # not in a readily recognizable state.
  87. }
  88. # Be very paranoid about the pid. (this might be redundant)
  89. sanity($pid);
  90. $pid =~ m/^([0-9]+)$/;
  91. $pid = $1;
  92. # get a pid that was really the one that we should be using, as a check.
  93. $sema =~ m/^([0-9]+)\s([0-9]+)\s/;
  94. my $userspid = $2;
  95. die "Hey! That isn't the PID I expected! ($userspid != $pid)\n" unless $userspid == $pid;
  96. my $runningModPerl = $ENV{MOD_PERL};
  97. # Hmm. Not done. Is the process still alive? (if not, we have a potential problem)
  98. if (! kill 0 => $pid) {
  99. warn "process $pid died\n";
  100. return 'died';
  101. } else {
  102. return 'running';
  103. }
  104. } # sub isDone
  105. #-------------------------------------------------------------------
  106. # Read line from semaphore file.
  107. #-------------------------------------------------------------------
  108. sub readSemaphore($) {
  109. my ($uid) = @_;
  110. my $semaphoreFile = "$UPLOAD_DIR/$uid/${uid}.$SEMAPHORE_SUFFIX";
  111. # print STDERR "Reading from $semaphoreFile...\n";
  112. my $sema;
  113. if (-e $semaphoreFile) {
  114. eval { open (SEMA, "<$semaphoreFile");
  115. flock(SEMA, LOCK_SH() );
  116. $sema = <SEMA>;
  117. close SEMA;
  118. # print STDERR "Read '$sema' from $semaphoreFile\n";
  119. };
  120. die "Error reading semaphore file: $@\n" if $@;
  121. } else {
  122. warn "$semaphoreFile does not exist\n";
  123. }
  124. return $sema;
  125. } # sub readSemaphore
  126. #-------------------------------------------------------------------
  127. # Set up environment so we can keep track of background processes
  128. #-------------------------------------------------------------------
  129. sub setUpSpawn($) {
  130. my ($forkOK) = @_;
  131. # establish some details of how we deal with errant children, etc.
  132. if ($forkOK) { # what to do when certain signals are received.
  133. $SIG{CHLD} = 'IGNORE'; # Autoreap zombies. child process sends this signal to the parent when it quits. See pg 415 of camel 3rd ed.
  134. $SIG{QUIT} = sub { die "\nAction canceled by user.\n" };
  135. setpgrp(0, 0); # processid (0=current), process group (default) # not be platform-independent.
  136. }
  137. } # sub setUpSpawn
  138. #-------------------------------------------------------------------
  139. # Write something to a semaphore file.
  140. #-------------------------------------------------------------------
  141. sub writeSemaphore($$$) {
  142. my ($uid, $text, $overwrite) = @_;
  143. $overwrite = $overwrite ? ">" : ">>";
  144. my $semaphoreFile = "$UPLOAD_DIR/$uid/${uid}.$SEMAPHORE_SUFFIX";
  145. # print STDERR "writing to $semaphoreFile\n";
  146. eval { open (SEMA, "$overwrite$semaphoreFile");
  147. flock(SEMA, LOCK_EX() );
  148. $|++;
  149. print SEMA $text;
  150. close SEMA;
  151. };
  152. die "Error reading semaphore file: $@\n" if $@;
  153. chmod (0666, $semaphoreFile);
  154. # print STDERR "Successfully wrote $text to $semaphoreFile\n";
  155. } # sub writeSemaphore
  156. 1;