Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Shutdown management class. 19 * 20 * @package core 21 * @copyright 2013 Petr Skoda {@link http://skodak.org} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 /** 28 * Shutdown management class. 29 * 30 * @package core 31 * @copyright 2013 Petr Skoda {@link http://skodak.org} 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class core_shutdown_manager { 35 /** @var array list of custom callbacks */ 36 protected static $callbacks = []; 37 /** @var array list of custom signal callbacks */ 38 protected static $signalcallbacks = []; 39 /** @var bool is this manager already registered? */ 40 protected static $registered = false; 41 42 /** 43 * Register self as main shutdown handler. 44 * 45 * @private to be called from lib/setup.php only! 46 */ 47 public static function initialize() { 48 if (self::$registered) { 49 debugging('Shutdown manager is already initialised!'); 50 } 51 self::$registered = true; 52 register_shutdown_function(array('core_shutdown_manager', 'shutdown_handler')); 53 54 // Signal handlers should only be used when dealing with a CLI script. 55 // In the case of PHP called in a web server the server is the owning process and should handle the signal chain 56 // properly itself. 57 // The 'pcntl' extension is optional and not available on Windows. 58 if (CLI_SCRIPT && extension_loaded('pcntl') && function_exists('pcntl_async_signals')) { 59 // We capture and handle SIGINT (Ctrl+C) and SIGTERM (termination requested). 60 pcntl_async_signals(true); 61 pcntl_signal(SIGINT, ['core_shutdown_manager', 'signal_handler']); 62 pcntl_signal(SIGTERM, ['core_shutdown_manager', 'signal_handler']); 63 } 64 } 65 66 /** 67 * Signal handler for SIGINT, and SIGTERM. 68 * 69 * @param int $signo The signal being handled 70 */ 71 public static function signal_handler(int $signo) { 72 // Note: There is no need to manually call the shutdown handler. 73 // The fact that we are calling exit() in this script means that the standard shutdown handling is performed 74 // anyway. 75 switch ($signo) { 76 case SIGTERM: 77 // Replicate native behaviour. 78 echo "Terminated: {$signo}\n"; 79 80 // The standard exit code for SIGTERM is 143. 81 $exitcode = 143; 82 break; 83 case SIGINT: 84 // Replicate native behaviour. 85 echo "\n"; 86 87 // The standard exit code for SIGINT (Ctrl+C) is 130. 88 $exitcode = 130; 89 break; 90 default: 91 // The signal handler was called with a signal it was not expecting. 92 // We should exit and complain. 93 echo "Warning: \core_shutdown_manager::signal_handler() was called with an unexpected signal ({$signo}).\n"; 94 $exitcode = 1; 95 } 96 97 // Normally we should exit unless a callback tells us to wait. 98 $shouldexit = true; 99 foreach (self::$signalcallbacks as $data) { 100 list($callback, $params) = $data; 101 try { 102 array_unshift($params, $signo); 103 $shouldexit = call_user_func_array($callback, $params) && $shouldexit; 104 } catch (Throwable $e) { 105 // @codingStandardsIgnoreStart 106 error_log('Exception ignored in signal function ' . get_callable_name($callback) . ': ' . $e->getMessage()); 107 // @codingStandardsIgnoreEnd 108 } 109 } 110 111 if ($shouldexit) { 112 exit ($exitcode); 113 } 114 } 115 116 /** 117 * Register custom signal handler function. 118 * 119 * If a handler returns false the signal will be ignored. 120 * 121 * @param callable $callback 122 * @param array $params 123 * @return void 124 */ 125 public static function register_signal_handler($callback, array $params = null): void { 126 if (!is_callable($callback)) { 127 // @codingStandardsIgnoreStart 128 error_log('Invalid custom signal function detected ' . var_export($callback, true)); 129 // @codingStandardsIgnoreEnd 130 } 131 self::$signalcallbacks[] = [$callback, $params ?? []]; 132 } 133 134 /** 135 * Register custom shutdown function. 136 * 137 * @param callable $callback 138 * @param array $params 139 * @return void 140 */ 141 public static function register_function($callback, array $params = null): void { 142 if (!is_callable($callback)) { 143 // @codingStandardsIgnoreStart 144 error_log('Invalid custom shutdown function detected '.var_export($callback, true)); 145 // @codingStandardsIgnoreEnd 146 } 147 self::$callbacks[] = [$callback, $params ?? []]; 148 } 149 150 /** 151 * @private - do NOT call directly. 152 */ 153 public static function shutdown_handler() { 154 global $DB; 155 156 // Custom stuff first. 157 foreach (self::$callbacks as $data) { 158 list($callback, $params) = $data; 159 try { 160 call_user_func_array($callback, $params); 161 } catch (Throwable $e) { 162 // @codingStandardsIgnoreStart 163 error_log('Exception ignored in shutdown function '.get_callable_name($callback).': '.$e->getMessage()); 164 // @codingStandardsIgnoreEnd 165 } 166 } 167 168 // Handle DB transactions, session need to be written afterwards 169 // in order to maintain consistency in all session handlers. 170 if ($DB->is_transaction_started()) { 171 if (!defined('PHPUNIT_TEST') or !PHPUNIT_TEST) { 172 // This should not happen, it usually indicates wrong catching of exceptions, 173 // because all transactions should be finished manually or in default exception handler. 174 $backtrace = $DB->get_transaction_start_backtrace(); 175 error_log('Potential coding error - active database transaction detected during request shutdown:'."\n".format_backtrace($backtrace, true)); 176 } 177 $DB->force_transaction_rollback(); 178 } 179 180 // Close sessions - do it here to make it consistent for all session handlers. 181 \core\session\manager::write_close(); 182 183 // Other cleanup. 184 self::request_shutdown(); 185 186 // Stop profiling. 187 if (function_exists('profiling_is_running')) { 188 if (profiling_is_running()) { 189 profiling_stop(); 190 } 191 } 192 193 // NOTE: do not dispose $DB and MUC here, they might be used from legacy shutdown functions. 194 } 195 196 /** 197 * Standard shutdown sequence. 198 */ 199 protected static function request_shutdown() { 200 global $CFG; 201 202 // Help apache server if possible. 203 $apachereleasemem = false; 204 if (function_exists('apache_child_terminate') && function_exists('memory_get_usage') && ini_get_bool('child_terminate')) { 205 $limit = (empty($CFG->apachemaxmem) ? 64*1024*1024 : $CFG->apachemaxmem); // 64MB default. 206 if (memory_get_usage() > get_real_size($limit)) { 207 $apachereleasemem = $limit; 208 @apache_child_terminate(); 209 } 210 } 211 212 // Deal with perf logging. 213 if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) { 214 if ($apachereleasemem) { 215 error_log('Mem usage over '.$apachereleasemem.': marking Apache child for reaping.'); 216 } 217 if (defined('MDL_PERFTOLOG')) { 218 $perf = get_performance_info(); 219 error_log("PERF: " . $perf['txt']); 220 } 221 if (defined('MDL_PERFINC')) { 222 $inc = get_included_files(); 223 $ts = 0; 224 foreach ($inc as $f) { 225 if (preg_match(':^/:', $f)) { 226 $fs = filesize($f); 227 $ts += $fs; 228 $hfs = display_size($fs); 229 error_log(substr($f, strlen($CFG->dirroot)) . " size: $fs ($hfs)", null, null, 0); 230 } else { 231 error_log($f , null, null, 0); 232 } 233 } 234 if ($ts > 0 ) { 235 $hts = display_size($ts); 236 error_log("Total size of files included: $ts ($hts)"); 237 } 238 } 239 } 240 } 241 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body