PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/mysql/mysql-test/lib/My/SafeProcess/Base.pm

https://gitlab.com/envieidoc/tomato
Perl | 222 lines | 164 code | 26 blank | 32 comment | 7 complexity | 604a39a17b15b49735c71368b5efbafd MD5 | raw file
  1. # -*- cperl -*-
  2. # Copyright (c) 2007 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
  3. # Use is subject to license terms.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; version 2 of the License.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. # This is a library file used by the Perl version of mysql-test-run,
  18. # and is part of the translation of the Bourne shell script with the
  19. # same name.
  20. use strict;
  21. package My::SafeProcess::Base;
  22. #
  23. # Utility functions for Process management
  24. #
  25. use Carp;
  26. use IO::Pipe;
  27. use base qw(Exporter);
  28. our @EXPORT= qw(create_process);
  29. #
  30. # safe_fork
  31. # Retry a couple of times if fork returns EAGAIN
  32. #
  33. sub _safe_fork {
  34. my $retries= 5;
  35. my $pid;
  36. FORK:
  37. {
  38. $pid= fork;
  39. if ( not defined($pid)) {
  40. croak("fork failed after: $!") if (!$retries--);
  41. warn("fork failed sleep 1 second and redo: $!");
  42. sleep(1);
  43. redo FORK;
  44. }
  45. }
  46. return $pid;
  47. };
  48. #
  49. # Decode exit status
  50. #
  51. sub exit_status {
  52. my $self= shift;
  53. my $raw= $self->{EXIT_STATUS};
  54. croak("Can't call exit_status before process has died")
  55. unless defined $raw;
  56. if ($raw & 127)
  57. {
  58. # Killed by signal
  59. my $signal_num= $raw & 127;
  60. my $dumped_core= $raw & 128;
  61. return 1; # Return error code
  62. }
  63. else
  64. {
  65. # Normal process exit
  66. return $raw >> 8;
  67. };
  68. }
  69. # threads.pm may not exist everywhere, so use only on Windows.
  70. use if $^O eq "MSWin32", "threads";
  71. use if $^O eq "MSWin32", "threads::shared";
  72. my $win32_spawn_lock :shared;
  73. #
  74. # Create a new process
  75. # Return pid of the new process
  76. #
  77. sub create_process {
  78. my %opts=
  79. (
  80. @_
  81. );
  82. my $path = delete($opts{'path'}) or die "path required";
  83. my $args = delete($opts{'args'}) or die "args required";
  84. my $input = delete($opts{'input'});
  85. my $output = delete($opts{'output'});
  86. my $error = delete($opts{'error'});
  87. my $open_mode= $opts{append} ? ">>" : ">";
  88. if ($^O eq "MSWin32"){
  89. lock($win32_spawn_lock);
  90. #printf STDERR "stdin %d, stdout %d, stderr %d\n",
  91. # fileno STDIN, fileno STDOUT, fileno STDERR;
  92. # input output redirect
  93. my ($oldin, $oldout, $olderr);
  94. open $oldin, '<&', \*STDIN or die "Failed to save old stdin: $!";
  95. open $oldout, '>&', \*STDOUT or die "Failed to save old stdout: $!";
  96. open $olderr, '>&', \*STDERR or die "Failed to save old stderr: $!";
  97. if ( $input ) {
  98. if ( ! open(STDIN, "<", $input) ) {
  99. croak("can't redirect STDIN to '$input': $!");
  100. }
  101. }
  102. if ( $output ) {
  103. if ( ! open(STDOUT, $open_mode, $output) ) {
  104. croak("can't redirect STDOUT to '$output': $!");
  105. }
  106. }
  107. if ( $error ) {
  108. if ( $output eq $error ) {
  109. if ( ! open(STDERR, ">&STDOUT") ) {
  110. croak("can't dup STDOUT: $!");
  111. }
  112. }
  113. elsif ( ! open(STDERR, $open_mode, $error) ) {
  114. croak("can't redirect STDERR to '$error': $!");
  115. }
  116. }
  117. # Magic use of 'system(1, @args)' to spawn a process
  118. # and get a proper Win32 pid
  119. unshift (@$args, $path);
  120. my $pid= system(1, @$args);
  121. if ( $pid == 0 ){
  122. print $olderr "create_process failed: $^E\n";
  123. die "create_process failed: $^E";
  124. }
  125. # Retore IO redirects
  126. open STDERR, '>&', $olderr
  127. or croak("unable to reestablish STDERR");
  128. open STDOUT, '>&', $oldout
  129. or croak("unable to reestablish STDOUT");
  130. open STDIN, '<&', $oldin
  131. or croak("unable to reestablish STDIN");
  132. #printf STDERR "stdin %d, stdout %d, stderr %d\n",
  133. # fileno STDIN, fileno STDOUT, fileno STDERR;
  134. return $pid;
  135. }
  136. local $SIG{PIPE}= sub { print STDERR "Got signal $@\n"; };
  137. my $pipe= IO::Pipe->new();
  138. my $pid= _safe_fork();
  139. if ($pid){
  140. # Parent
  141. $pipe->reader();
  142. my $line= <$pipe>; # Wait for child to say it's ready
  143. return $pid;
  144. }
  145. $SIG{INT}= 'DEFAULT';
  146. # Make this process it's own process group to be able to kill
  147. # it and any childs(that hasn't changed group themself)
  148. setpgrp(0,0) if $opts{setpgrp};
  149. if ( $output and !open(STDOUT, $open_mode, $output) ) {
  150. croak("can't redirect STDOUT to '$output': $!");
  151. }
  152. if ( $error ) {
  153. if ( defined $output and $output eq $error ) {
  154. if ( ! open(STDERR, ">&STDOUT") ) {
  155. croak("can't dup STDOUT: $!");
  156. }
  157. }
  158. elsif ( ! open(STDERR, $open_mode, $error) ) {
  159. croak("can't redirect STDERR to '$error': $!");
  160. }
  161. }
  162. if ( $input ) {
  163. if ( ! open(STDIN, "<", $input) ) {
  164. croak("can't redirect STDIN to '$input': $!");
  165. }
  166. }
  167. # Tell parent to continue
  168. $pipe->writer();
  169. print $pipe "ready\n";
  170. if ( !exec($path, @$args) ){
  171. croak("Failed to exec '$path': $!");
  172. }
  173. croak("Should never come here");
  174. }
  175. 1;