PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / core / PcntlSignalAdapter.php

PcntlSignalAdapter.php in 404 Solution trunk, at includes/core/PcntlSignalAdapter.php

78 lines 3.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Capability-safe boundary for the pcntl signal functions.
9 *
10 * Split from ABJ_404_Solution_PhpRuntimeCapabilityAdapter along the line the
11 * HOST splits on. Everything that adapter wraps can be removed one function at
12 * a time through disable_functions, but pcntl is an extension: it is absent as
13 * a unit on most shared hosting and on every non-CLI SAPI build that omits it,
14 * so "can this host use signals at all" is one question with one answer rather
15 * than four independent probes.
16 *
17 * These four are also not four capabilities. They are the steps of one
18 * protocol -- check support, enable async dispatch, install the handler, arm
19 * and disarm the alarm -- and exactly one caller runs it,
20 * ABJ_404_Solution_PostResponseWorkerBudget, which is the post-response
21 * wall-clock budget itself. Keeping the protocol in one place is what lets
22 * supportsSignalBudget() be the single precondition the caller checks instead
23 * of each step failing separately halfway through.
24 *
25 * Depends on the main adapter for the availability check and never the other
26 * way round, so the boundary classes stay acyclic.
27 */
28 final class ABJ_404_Solution_PcntlSignalAdapter {
29
30 /** Functions this boundary owns; consumed by the disable-functions lint. */
31 private const OWNED_FUNCTIONS = array(
32 'pcntl_alarm',
33 'pcntl_async_signals',
34 'pcntl_signal',
35 );
36
37 /** @return array<int, string> Functions whose direct use this boundary owns. */
38 public static function ownedFunctions(): array {
39 return self::OWNED_FUNCTIONS;
40 }
41
42 /**
43 * Whether every function the post-response signal budget needs exists.
44 *
45 * All three, not any: arming an alarm whose handler could not be installed
46 * would leave a SIGALRM with the default disposition, which terminates the
47 * process rather than ending the budget.
48 */
49 public static function supportsSignalBudget(): bool {
50 foreach (self::OWNED_FUNCTIONS as $function) {
51 if (!ABJ_404_Solution_PhpRuntimeCapabilityAdapter::isFunctionAvailable($function)) {
52 return false;
53 }
54 }
55 return true;
56 }
57
58 /** Enable asynchronous signal dispatch when supported. */
59 public static function enableAsyncSignals(): bool {
60 return ABJ_404_Solution_PhpRuntimeCapabilityAdapter::isFunctionAvailable('pcntl_async_signals')
61 && pcntl_async_signals(true);
62 }
63
64 /** Install one signal handler when supported. */
65 public static function installSignalHandler(int $signal, callable $handler): bool {
66 return ABJ_404_Solution_PhpRuntimeCapabilityAdapter::isFunctionAvailable('pcntl_signal')
67 && pcntl_signal($signal, $handler);
68 }
69
70 /** Set or clear the process alarm; zero means unavailable or no prior alarm. */
71 public static function alarm(int $seconds): int {
72 if (!ABJ_404_Solution_PhpRuntimeCapabilityAdapter::isFunctionAvailable('pcntl_alarm')) {
73 return 0;
74 }
75 return pcntl_alarm($seconds);
76 }
77 }
78