comparison vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents c2387f117808
children
comparison
equal deleted inserted replaced
16:c2387f117808 17:129ea1e6d783
31 * 31 *
32 * @return bool 32 * @return bool
33 */ 33 */
34 public static function isSupported() 34 public static function isSupported()
35 { 35 {
36 return function_exists('pcntl_signal') && function_exists('posix_getpid'); 36 return \function_exists('pcntl_signal') && \function_exists('posix_getpid');
37 } 37 }
38 38
39 /** 39 /**
40 * Forks into a master and a loop process. 40 * Forks into a master and a loop process.
41 * 41 *
44 * 44 *
45 * @param Shell $shell 45 * @param Shell $shell
46 */ 46 */
47 public function beforeRun(Shell $shell) 47 public function beforeRun(Shell $shell)
48 { 48 {
49 list($up, $down) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP); 49 list($up, $down) = \stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
50 50
51 if (!$up) { 51 if (!$up) {
52 throw new \RuntimeException('Unable to create socket pair'); 52 throw new \RuntimeException('Unable to create socket pair');
53 } 53 }
54 54
55 $pid = pcntl_fork(); 55 $pid = \pcntl_fork();
56 if ($pid < 0) { 56 if ($pid < 0) {
57 throw new \RuntimeException('Unable to start execution loop'); 57 throw new \RuntimeException('Unable to start execution loop');
58 } elseif ($pid > 0) { 58 } elseif ($pid > 0) {
59 // This is the main thread. We'll just wait for a while. 59 // This is the main thread. We'll just wait for a while.
60 60
61 // We won't be needing this one. 61 // We won't be needing this one.
62 fclose($up); 62 \fclose($up);
63 63
64 // Wait for a return value from the loop process. 64 // Wait for a return value from the loop process.
65 $read = [$down]; 65 $read = [$down];
66 $write = null; 66 $write = null;
67 $except = null; 67 $except = null;
68 68
69 do { 69 do {
70 $n = @stream_select($read, $write, $except, null); 70 $n = @\stream_select($read, $write, $except, null);
71 71
72 if ($n === 0) { 72 if ($n === 0) {
73 throw new \RuntimeException('Process timed out waiting for execution loop'); 73 throw new \RuntimeException('Process timed out waiting for execution loop');
74 } 74 }
75 75
76 if ($n === false) { 76 if ($n === false) {
77 $err = error_get_last(); 77 $err = \error_get_last();
78 if (!isset($err['message']) || stripos($err['message'], 'interrupted system call') === false) { 78 if (!isset($err['message']) || \stripos($err['message'], 'interrupted system call') === false) {
79 $msg = $err['message'] ? 79 $msg = $err['message'] ?
80 sprintf('Error waiting for execution loop: %s', $err['message']) : 80 \sprintf('Error waiting for execution loop: %s', $err['message']) :
81 'Error waiting for execution loop'; 81 'Error waiting for execution loop';
82 throw new \RuntimeException($msg); 82 throw new \RuntimeException($msg);
83 } 83 }
84 } 84 }
85 } while ($n < 1); 85 } while ($n < 1);
86 86
87 $content = stream_get_contents($down); 87 $content = \stream_get_contents($down);
88 fclose($down); 88 \fclose($down);
89 89
90 if ($content) { 90 if ($content) {
91 $shell->setScopeVariables(@unserialize($content)); 91 $shell->setScopeVariables(@\unserialize($content));
92 } 92 }
93 93
94 throw new BreakException('Exiting main thread'); 94 throw new BreakException('Exiting main thread');
95 } 95 }
96 96
97 // This is the child process. It's going to do all the work. 97 // This is the child process. It's going to do all the work.
98 if (function_exists('setproctitle')) { 98 if (\function_exists('setproctitle')) {
99 setproctitle('psysh (loop)'); 99 setproctitle('psysh (loop)');
100 } 100 }
101 101
102 // We won't be needing this one. 102 // We won't be needing this one.
103 fclose($down); 103 \fclose($down);
104 104
105 // Save this; we'll need to close it in `afterRun` 105 // Save this; we'll need to close it in `afterRun`
106 $this->up = $up; 106 $this->up = $up;
107 } 107 }
108 108
123 */ 123 */
124 public function afterLoop(Shell $shell) 124 public function afterLoop(Shell $shell)
125 { 125 {
126 // if there's an old savegame hanging around, let's kill it. 126 // if there's an old savegame hanging around, let's kill it.
127 if (isset($this->savegame)) { 127 if (isset($this->savegame)) {
128 posix_kill($this->savegame, SIGKILL); 128 \posix_kill($this->savegame, SIGKILL);
129 pcntl_signal_dispatch(); 129 \pcntl_signal_dispatch();
130 } 130 }
131 } 131 }
132 132
133 /** 133 /**
134 * After the REPL session ends, send the scope variables back up to the main 134 * After the REPL session ends, send the scope variables back up to the main
138 */ 138 */
139 public function afterRun(Shell $shell) 139 public function afterRun(Shell $shell)
140 { 140 {
141 // We're a child thread. Send the scope variables back up to the main thread. 141 // We're a child thread. Send the scope variables back up to the main thread.
142 if (isset($this->up)) { 142 if (isset($this->up)) {
143 fwrite($this->up, $this->serializeReturn($shell->getScopeVariables(false))); 143 \fwrite($this->up, $this->serializeReturn($shell->getScopeVariables(false)));
144 fclose($this->up); 144 \fclose($this->up);
145 145
146 posix_kill(posix_getpid(), SIGKILL); 146 \posix_kill(\posix_getpid(), SIGKILL);
147 } 147 }
148 } 148 }
149 149
150 /** 150 /**
151 * Create a savegame fork. 151 * Create a savegame fork.
155 * a PHP fatal error). 155 * a PHP fatal error).
156 */ 156 */
157 private function createSavegame() 157 private function createSavegame()
158 { 158 {
159 // the current process will become the savegame 159 // the current process will become the savegame
160 $this->savegame = posix_getpid(); 160 $this->savegame = \posix_getpid();
161 161
162 $pid = pcntl_fork(); 162 $pid = \pcntl_fork();
163 if ($pid < 0) { 163 if ($pid < 0) {
164 throw new \RuntimeException('Unable to create savegame fork'); 164 throw new \RuntimeException('Unable to create savegame fork');
165 } elseif ($pid > 0) { 165 } elseif ($pid > 0) {
166 // we're the savegame now... let's wait and see what happens 166 // we're the savegame now... let's wait and see what happens
167 pcntl_waitpid($pid, $status); 167 \pcntl_waitpid($pid, $status);
168 168
169 // worker exited cleanly, let's bail 169 // worker exited cleanly, let's bail
170 if (!pcntl_wexitstatus($status)) { 170 if (!\pcntl_wexitstatus($status)) {
171 posix_kill(posix_getpid(), SIGKILL); 171 \posix_kill(\posix_getpid(), SIGKILL);
172 } 172 }
173 173
174 // worker didn't exit cleanly, we'll need to have another go 174 // worker didn't exit cleanly, we'll need to have another go
175 $this->createSavegame(); 175 $this->createSavegame();
176 } 176 }
197 if (Context::isSpecialVariableName($key)) { 197 if (Context::isSpecialVariableName($key)) {
198 continue; 198 continue;
199 } 199 }
200 200
201 // Resources and Closures don't error, but they don't serialize well either. 201 // Resources and Closures don't error, but they don't serialize well either.
202 if (is_resource($value) || $value instanceof \Closure) { 202 if (\is_resource($value) || $value instanceof \Closure) {
203 continue; 203 continue;
204 } 204 }
205 205
206 try { 206 try {
207 @serialize($value); 207 @\serialize($value);
208 $serializable[$key] = $value; 208 $serializable[$key] = $value;
209 } catch (\Throwable $e) { 209 } catch (\Throwable $e) {
210 // we'll just ignore this one... 210 // we'll just ignore this one...
211 } catch (\Exception $e) { 211 } catch (\Exception $e) {
212 // and this one too... 212 // and this one too...
213 // @todo remove this once we don't support PHP 5.x anymore :) 213 // @todo remove this once we don't support PHP 5.x anymore :)
214 } 214 }
215 } 215 }
216 216
217 return @serialize($serializable); 217 return @\serialize($serializable);
218 } 218 }
219 } 219 }