Page MenuHomePhabricator

D16504.id.diff
No OneTemporary

D16504.id.diff

diff --git a/scripts/__init_script__.php b/scripts/__init_script__.php
--- a/scripts/__init_script__.php
+++ b/scripts/__init_script__.php
@@ -1,5 +1,7 @@
<?php
+declare(ticks = 1);
+
function __phutil_init_script__() {
// Adjust the runtime language configuration to be reasonable and inline with
// expectations. We do this first, then load libraries.
@@ -80,22 +82,10 @@
require_once $root.'/src/__phutil_library_init__.php';
PhutilErrorHandler::initialize();
+ $router = PhutilSignalRouter::initialize();
- // If possible, install a signal handler for SIGHUP which prints the current
- // backtrace out to a named file. This is particularly helpful in debugging
- // hung/spinning processes.
- if (function_exists('pcntl_signal')) {
- pcntl_signal(SIGHUP, '__phutil_signal_handler__');
- }
-}
-
-function __phutil_signal_handler__($signal_number) {
- $e = new Exception();
- $pid = getmypid();
- // Some Phabricator daemons may not be attached to a terminal.
- Filesystem::writeFile(
- sys_get_temp_dir().'/phabricator_backtrace_'.$pid,
- $e->getTraceAsString());
+ $handler = new PhutilBacktraceSignalHandler();
+ $router->installHandler('phutil.backtrace', $handler);
}
__phutil_init_script__();
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -119,6 +119,7 @@
'PhutilAuthCredentialException' => 'auth/exception/PhutilAuthCredentialException.php',
'PhutilAuthException' => 'auth/exception/PhutilAuthException.php',
'PhutilAuthUserAbortedException' => 'auth/exception/PhutilAuthUserAbortedException.php',
+ 'PhutilBacktraceSignalHandler' => 'future/exec/PhutilBacktraceSignalHandler.php',
'PhutilBallOfPHP' => 'phage/util/PhutilBallOfPHP.php',
'PhutilBitbucketAuthAdapter' => 'auth/PhutilBitbucketAuthAdapter.php',
'PhutilBootloader' => 'moduleutils/PhutilBootloader.php',
@@ -132,6 +133,7 @@
'PhutilCIDRList' => 'ip/PhutilCIDRList.php',
'PhutilCLikeCodeSnippetContextFreeGrammar' => 'grammar/code/PhutilCLikeCodeSnippetContextFreeGrammar.php',
'PhutilCallbackFilterIterator' => 'utils/PhutilCallbackFilterIterator.php',
+ 'PhutilCallbackSignalHandler' => 'future/exec/PhutilCallbackSignalHandler.php',
'PhutilChannel' => 'channel/PhutilChannel.php',
'PhutilChannelChannel' => 'channel/PhutilChannelChannel.php',
'PhutilChannelTestCase' => 'channel/__tests__/PhutilChannelTestCase.php',
@@ -358,6 +360,8 @@
'PhutilServiceProfiler' => 'serviceprofiler/PhutilServiceProfiler.php',
'PhutilShellLexer' => 'lexer/PhutilShellLexer.php',
'PhutilShellLexerTestCase' => 'lexer/__tests__/PhutilShellLexerTestCase.php',
+ 'PhutilSignalHandler' => 'future/exec/PhutilSignalHandler.php',
+ 'PhutilSignalRouter' => 'future/exec/PhutilSignalRouter.php',
'PhutilSimpleOptions' => 'parser/PhutilSimpleOptions.php',
'PhutilSimpleOptionsLexer' => 'lexer/PhutilSimpleOptionsLexer.php',
'PhutilSimpleOptionsLexerTestCase' => 'lexer/__tests__/PhutilSimpleOptionsLexerTestCase.php',
@@ -680,6 +684,7 @@
'PhutilAuthCredentialException' => 'PhutilAuthException',
'PhutilAuthException' => 'Exception',
'PhutilAuthUserAbortedException' => 'PhutilAuthException',
+ 'PhutilBacktraceSignalHandler' => 'PhutilSignalHandler',
'PhutilBallOfPHP' => 'Phobject',
'PhutilBitbucketAuthAdapter' => 'PhutilOAuth1AuthAdapter',
'PhutilBootloaderException' => 'Exception',
@@ -695,6 +700,7 @@
'PhutilCIDRList' => 'Phobject',
'PhutilCLikeCodeSnippetContextFreeGrammar' => 'PhutilCodeSnippetContextFreeGrammar',
'PhutilCallbackFilterIterator' => 'FilterIterator',
+ 'PhutilCallbackSignalHandler' => 'PhutilSignalHandler',
'PhutilChannel' => 'Phobject',
'PhutilChannelChannel' => 'PhutilChannel',
'PhutilChannelTestCase' => 'PhutilTestCase',
@@ -930,6 +936,8 @@
'PhutilServiceProfiler' => 'Phobject',
'PhutilShellLexer' => 'PhutilLexer',
'PhutilShellLexerTestCase' => 'PhutilTestCase',
+ 'PhutilSignalHandler' => 'Phobject',
+ 'PhutilSignalRouter' => 'Phobject',
'PhutilSimpleOptions' => 'Phobject',
'PhutilSimpleOptionsLexer' => 'PhutilLexer',
'PhutilSimpleOptionsLexerTestCase' => 'PhutilTestCase',
diff --git a/src/daemon/PhutilDaemon.php b/src/daemon/PhutilDaemon.php
--- a/src/daemon/PhutilDaemon.php
+++ b/src/daemon/PhutilDaemon.php
@@ -70,14 +70,16 @@
return $this->verbose;
}
- private static $sighandlerInstalled;
-
final public function __construct(array $argv) {
$this->argv = $argv;
- if (!self::$sighandlerInstalled) {
- self::$sighandlerInstalled = true;
- pcntl_signal(SIGTERM, __CLASS__.'::exitOnSignal');
+ $router = PhutilSignalRouter::getRouter();
+ $handler_key = 'daemon.term';
+ if (!$router->getHandler($handler_key)) {
+ $handler = new PhutilCallbackSignalHandler(
+ SIGTERM,
+ __CLASS__.'::onTermSignal');
+ $router->installHandler($handler_key, $handler);
}
pcntl_signal(SIGINT, array($this, 'onGracefulSignal'));
@@ -166,13 +168,8 @@
return;
}
- public static function exitOnSignal($signo) {
+ public static function onTermSignal($signo) {
self::didCatchSignal($signo);
-
- // Normally, PHP doesn't invoke destructors when exiting in response to
- // a signal. This forces it to do so, so we have a fighting chance of
- // releasing any locks, leases or resources on our way out.
- exit(128 + $signo);
}
final protected function getArgv() {
diff --git a/src/future/exec/PhutilBacktraceSignalHandler.php b/src/future/exec/PhutilBacktraceSignalHandler.php
new file mode 100644
--- /dev/null
+++ b/src/future/exec/PhutilBacktraceSignalHandler.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * Signal handler for SIGHUP which prints the current backtrace out to a
+ * file. This is particularly helpful in debugging hung/spinning processes.
+ */
+final class PhutilBacktraceSignalHandler extends PhutilSignalHandler {
+
+ public function canHandleSignal(PhutilSignalRouter $router, $signo) {
+ return ($signo === SIGHUP);
+ }
+
+ public function handleSignal(PhutilSignalRouter $router, $signo) {
+ $e = new Exception();
+ $pid = getmypid();
+ // Some Phabricator daemons may not be attached to a terminal.
+ Filesystem::writeFile(
+ sys_get_temp_dir().'/phabricator_backtrace_'.$pid,
+ $e->getTraceAsString());
+ }
+
+}
diff --git a/src/future/exec/PhutilCallbackSignalHandler.php b/src/future/exec/PhutilCallbackSignalHandler.php
new file mode 100644
--- /dev/null
+++ b/src/future/exec/PhutilCallbackSignalHandler.php
@@ -0,0 +1,22 @@
+<?php
+
+
+final class PhutilCallbackSignalHandler extends PhutilSignalHandler {
+
+ private $signal;
+ private $callback;
+
+ public function __construct($signal, $callback) {
+ $this->signal = $signal;
+ $this->callback = $callback;
+ }
+
+ public function canHandleSignal(PhutilSignalRouter $router, $signo) {
+ return ($signo === $this->signal);
+ }
+
+ public function handleSignal(PhutilSignalRouter $router, $signo) {
+ call_user_func($this->callback, $signo);
+ }
+
+}
diff --git a/src/future/exec/PhutilSignalHandler.php b/src/future/exec/PhutilSignalHandler.php
new file mode 100644
--- /dev/null
+++ b/src/future/exec/PhutilSignalHandler.php
@@ -0,0 +1,8 @@
+<?php
+
+abstract class PhutilSignalHandler extends Phobject {
+
+ abstract public function canHandleSignal(PhutilSignalRouter $router, $signo);
+ abstract public function handleSignal(PhutilSignalRouter $router, $signo);
+
+}
diff --git a/src/future/exec/PhutilSignalRouter.php b/src/future/exec/PhutilSignalRouter.php
new file mode 100644
--- /dev/null
+++ b/src/future/exec/PhutilSignalRouter.php
@@ -0,0 +1,80 @@
+<?php
+
+final class PhutilSignalRouter extends Phobject {
+
+ private $handlers = array();
+ private static $router;
+
+ private function __construct() {
+ // <private>
+ }
+
+ public static function initialize() {
+ if (!self::$router) {
+ $router = new self();
+
+ pcntl_signal(SIGHUP, array($router, 'routeSignal'));
+ pcntl_signal(SIGTERM, array($router, 'routeSignal'));
+
+ self::$router = $router;
+ }
+
+ return self::getRouter();
+ }
+
+ public static function getRouter() {
+ if (!self::$router) {
+ throw new Exception(pht('Signal router has not been initialized!'));
+ }
+
+ return self::$router;
+ }
+
+ public function installHandler($key, PhutilSignalHandler $handler) {
+ if (isset($this->handlers[$key])) {
+ throw new Exception(
+ pht(
+ 'Signal handler with key "%s" is already installed.',
+ $key));
+ }
+
+ $this->handlers[$key] = $handler;
+
+ return $this;
+ }
+
+ public function getHandler($key) {
+ return idx($this->handlers, $key);
+ }
+
+ public function routeSignal($signo) {
+ $exceptions = array();
+
+ $handlers = $this->handlers;
+ foreach ($handlers as $key => $handler) {
+ try {
+ if ($handler->canHandleSignal($this, $signo)) {
+ $handler->handleSignal($this, $signo);
+ }
+ } catch (Exception $ex) {
+ $exceptions[] = $ex;
+ }
+ }
+
+ if ($exceptions) {
+ throw new PhutilAggregateException(
+ pht(
+ 'Signal handlers raised exceptions while handling "%s".',
+ phutil_get_signal_name($signo)));
+ }
+
+ switch ($signo) {
+ case SIGTERM:
+ // Normally, PHP doesn't invoke destructors when exiting in response to
+ // a signal. This forces it to do so, so we have a fighting chance of
+ // releasing any locks, leases or resources on our way out.
+ exit(128 + $signo);
+ }
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Sat, May 11, 6:43 AM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6277548
Default Alt Text
D16504.id.diff (9 KB)

Event Timeline