22
22
use Symfony \Component \Console \Completion \CompletionInput ;
23
23
use Symfony \Component \Console \Completion \CompletionSuggestions ;
24
24
use Symfony \Component \Console \Completion \Suggestion ;
25
+ use Symfony \Component \Console \Event \ConsoleAlarmEvent ;
25
26
use Symfony \Component \Console \Event \ConsoleCommandEvent ;
26
27
use Symfony \Component \Console \Event \ConsoleErrorEvent ;
27
28
use Symfony \Component \Console \Event \ConsoleSignalEvent ;
@@ -88,6 +89,7 @@ class Application implements ResetInterface
88
89
private bool $ initialized = false ;
89
90
private ?SignalRegistry $ signalRegistry = null ;
90
91
private array $ signalsToDispatchEvent = [];
92
+ private ?int $ alarmInterval = null ;
91
93
92
94
public function __construct (
93
95
private string $ name = 'UNKNOWN ' ,
@@ -97,7 +99,7 @@ public function __construct(
97
99
$ this ->defaultCommand = 'list ' ;
98
100
if (\defined ('SIGINT ' ) && SignalRegistry::isSupported ()) {
99
101
$ this ->signalRegistry = new SignalRegistry ();
100
- $ this ->signalsToDispatchEvent = [\SIGINT , \SIGQUIT , \SIGTERM , \SIGUSR1 , \SIGUSR2 ];
102
+ $ this ->signalsToDispatchEvent = [\SIGINT , \SIGQUIT , \SIGTERM , \SIGUSR1 , \SIGUSR2 , \ SIGALRM ];
101
103
}
102
104
}
103
105
@@ -128,6 +130,19 @@ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent): void
128
130
$ this ->signalsToDispatchEvent = $ signalsToDispatchEvent ;
129
131
}
130
132
133
+ public function setAlarmInterval (?int $ interval ): void
134
+ {
135
+ $ this ->alarmInterval = $ interval ;
136
+ $ this ->scheduleAlarm ();
137
+ }
138
+
139
+ private function scheduleAlarm (): void
140
+ {
141
+ if (null !== $ this ->alarmInterval ) {
142
+ $ this ->getSignalRegistry ()->scheduleAlarm ($ this ->alarmInterval );
143
+ }
144
+ }
145
+
131
146
/**
132
147
* Runs the current application.
133
148
*
@@ -981,34 +996,47 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
981
996
982
997
$ commandSignals = $ command instanceof SignalableCommandInterface ? $ command ->getSubscribedSignals () : [];
983
998
if ($ commandSignals || $ this ->dispatcher && $ this ->signalsToDispatchEvent ) {
984
- if (!$ this ->signalRegistry ) {
985
- throw new RuntimeException ('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini \'s "disable_functions" directive. ' );
986
- }
999
+ $ signalRegistry = $ this ->getSignalRegistry ();
987
1000
988
1001
if (Terminal::hasSttyAvailable ()) {
989
1002
$ sttyMode = shell_exec ('stty -g ' );
990
1003
991
1004
foreach ([\SIGINT , \SIGQUIT , \SIGTERM ] as $ signal ) {
992
- $ this -> signalRegistry ->register ($ signal , static fn () => shell_exec ('stty ' .$ sttyMode ));
1005
+ $ signalRegistry ->register ($ signal , static fn () => shell_exec ('stty ' .$ sttyMode ));
993
1006
}
994
1007
}
995
1008
996
1009
if ($ this ->dispatcher ) {
997
1010
// We register application signals, so that we can dispatch the event
998
1011
foreach ($ this ->signalsToDispatchEvent as $ signal ) {
999
- $ event = new ConsoleSignalEvent ($ command , $ input , $ output , $ signal );
1000
-
1001
- $ this ->signalRegistry ->register ($ signal , function ($ signal ) use ($ event , $ command , $ commandSignals ) {
1002
- $ this ->dispatcher ->dispatch ($ event , ConsoleEvents::SIGNAL );
1003
- $ exitCode = $ event ->getExitCode ();
1012
+ $ signalEvent = new ConsoleSignalEvent ($ command , $ input , $ output , $ signal );
1013
+ $ alarmEvent = \SIGALRM === $ signal ? new ConsoleAlarmEvent ($ command , $ input , $ output ) : null ;
1014
+
1015
+ $ signalRegistry ->register ($ signal , function ($ signal ) use ($ signalEvent , $ alarmEvent , $ command , $ commandSignals , $ input , $ output ) {
1016
+ $ this ->dispatcher ->dispatch ($ signalEvent , ConsoleEvents::SIGNAL );
1017
+ $ exitCode = $ signalEvent ->getExitCode ();
1018
+
1019
+ if (null !== $ alarmEvent ) {
1020
+ if (false !== $ exitCode ) {
1021
+ $ alarmEvent ->setExitCode ($ exitCode );
1022
+ } else {
1023
+ $ alarmEvent ->abortExit ();
1024
+ }
1025
+ $ this ->dispatcher ->dispatch ($ alarmEvent , ConsoleEvents::ALARM );
1026
+ $ exitCode = $ alarmEvent ->getExitCode ();
1027
+ }
1004
1028
1005
1029
// If the command is signalable, we call the handleSignal() method
1006
1030
if (\in_array ($ signal , $ commandSignals , true )) {
1007
1031
$ exitCode = $ command ->handleSignal ($ signal , $ exitCode );
1008
1032
}
1009
1033
1034
+ if (\SIGALRM === $ signal ) {
1035
+ $ this ->scheduleAlarm ();
1036
+ }
1037
+
1010
1038
if (false !== $ exitCode ) {
1011
- $ event = new ConsoleTerminateEvent ($ command , $ event -> getInput () , $ event -> getOutput () , $ exitCode , $ signal );
1039
+ $ event = new ConsoleTerminateEvent ($ command , $ input , $ output , $ exitCode , $ signal );
1012
1040
$ this ->dispatcher ->dispatch ($ event , ConsoleEvents::TERMINATE );
1013
1041
1014
1042
exit ($ event ->getExitCode ());
@@ -1021,7 +1049,11 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
1021
1049
}
1022
1050
1023
1051
foreach ($ commandSignals as $ signal ) {
1024
- $ this ->signalRegistry ->register ($ signal , function (int $ signal ) use ($ command ): void {
1052
+ $ signalRegistry ->register ($ signal , function (int $ signal ) use ($ command ): void {
1053
+ if (\SIGALRM === $ signal ) {
1054
+ $ this ->scheduleAlarm ();
1055
+ }
1056
+
1025
1057
if (false !== $ exitCode = $ command ->handleSignal ($ signal )) {
1026
1058
exit ($ exitCode );
1027
1059
}
0 commit comments