Skip to content

Commit 1e9cb6c

Browse files
committed
Add functions to monitor processes
* State: Check a process state (RUNNING, WAITABLE, TERMINATED) * Is_Running: Whether a process is running * Wait_For_Processes: Wait for multiple processes termination Part of TC15-053 Change-Id: I6b108fd289d420f551df89197f18d18881d9fa3e
1 parent c609b17 commit 1e9cb6c

17 files changed

+768
-1
lines changed

gnatcoll.gpr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ project GnatColl is
198198
use "gnatcoll-os-process_types__unix.ads";
199199
for Implementation ("GNATCOLL.OS.Process_Types")
200200
use "gnatcoll-os-process_types__unix.adb";
201+
for Implementation ("GNATCOLL.OS.Process.State")
202+
use "gnatcoll-os-process-state__unix.adb";
203+
for Implementation ("GNATCOLL.OS.Process.Wait_For_Processes")
204+
use "gnatcoll-os-process-wait_for_processes__unix.adb";
201205
for Specification ("GNATCOLL.OS.Dir_Types")
202206
use "gnatcoll-os-dir_types__unix.ads";
203207
for Implementation ("GNATCOLL.OS.Dir.Open")
@@ -233,6 +237,10 @@ project GnatColl is
233237
use "gnatcoll-os-process-wait__win32.adb";
234238
for Implementation ("GNATCOLL.OS.Process.Internal_Spawn")
235239
use "gnatcoll-os-process-internal_spawn__win32.adb";
240+
for Implementation ("GNATCOLL.OS.Process.State")
241+
use "gnatcoll-os-process-state__win32.adb";
242+
for Implementation ("GNATCOLL.OS.Process.Wait_For_Processes")
243+
use "gnatcoll-os-process-wait_for_processes__win32.adb";
236244
for Specification ("GNATCOLL.OS.Dir_Types")
237245
use "gnatcoll-os-dir_types__win32.ads";
238246
for Implementation ("GNATCOLL.OS.Dir.Open")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
------------------------------------------------------------------------------
2+
-- G N A T C O L L --
3+
-- --
4+
-- Copyright (C) 2021, AdaCore --
5+
-- --
6+
-- This library is free software; you can redistribute it and/or modify it --
7+
-- under terms of the GNU General Public License as published by the Free --
8+
-- Software Foundation; either version 3, or (at your option) any later --
9+
-- version. This library is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
12+
-- --
13+
-- As a special exception under Section 7 of GPL version 3, you are granted --
14+
-- additional permissions described in the GCC Runtime Library Exception, --
15+
-- version 3.1, as published by the Free Software Foundation. --
16+
-- --
17+
-- You should have received a copy of the GNU General Public License and --
18+
-- a copy of the GCC Runtime Library Exception along with this program; --
19+
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
20+
-- <http://www.gnu.org/licenses/>. --
21+
-- --
22+
------------------------------------------------------------------------------
23+
24+
separate (GNATCOLL.OS.Process)
25+
function State (H : Process_Handle) return Process_State
26+
is
27+
Status : Integer;
28+
29+
function Internal (Pid : Integer) return Integer
30+
with Import => True,
31+
Convention => C,
32+
External_Name => "__gnatcoll_process_state";
33+
begin
34+
Status := Internal (Integer (H));
35+
36+
if Status = -2 then
37+
return TERMINATED;
38+
elsif Status = -1 then
39+
return WAITABLE;
40+
else
41+
return RUNNING;
42+
end if;
43+
end State;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
------------------------------------------------------------------------------
2+
-- G N A T C O L L --
3+
-- --
4+
-- Copyright (C) 2021, AdaCore --
5+
-- --
6+
-- This library is free software; you can redistribute it and/or modify it --
7+
-- under terms of the GNU General Public License as published by the Free --
8+
-- Software Foundation; either version 3, or (at your option) any later --
9+
-- version. This library is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
12+
-- --
13+
-- As a special exception under Section 7 of GPL version 3, you are granted --
14+
-- additional permissions described in the GCC Runtime Library Exception, --
15+
-- version 3.1, as published by the Free Software Foundation. --
16+
-- --
17+
-- You should have received a copy of the GNU General Public License and --
18+
-- a copy of the GCC Runtime Library Exception along with this program; --
19+
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
20+
-- <http://www.gnu.org/licenses/>. --
21+
-- --
22+
------------------------------------------------------------------------------
23+
24+
with GNATCOLL.OS.Win32.Process; use GNATCOLL.OS.Win32.Process;
25+
with GNATCOLL.OS.Win32; use GNATCOLL.OS.Win32;
26+
27+
separate (GNATCOLL.OS.Process)
28+
function State (H : Process_Handle) return Process_State
29+
is
30+
WHandle : constant GNATCOLL.OS.Win32.HANDLE :=
31+
GNATCOLL.OS.Win32.HANDLE (H);
32+
Status : NTSTATUS;
33+
Process_Info : aliased PROCESS_BASIC_INFORMATION;
34+
Result_Length : ULONG;
35+
begin
36+
Status := NtQueryInformationProcess
37+
(WHandle,
38+
ProcessBasicInformation,
39+
Process_Info'Address,
40+
PROCESS_BASIC_INFORMATION'Size / 8,
41+
Result_Length);
42+
43+
if not Is_Success (Status) then
44+
return TERMINATED;
45+
elsif Process_Info.ExitStatus = 259 then
46+
return RUNNING;
47+
else
48+
return WAITABLE;
49+
end if;
50+
end State;
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
------------------------------------------------------------------------------
2+
-- G N A T C O L L --
3+
-- --
4+
-- Copyright (C) 2021, AdaCore --
5+
-- --
6+
-- This library is free software; you can redistribute it and/or modify it --
7+
-- under terms of the GNU General Public License as published by the Free --
8+
-- Software Foundation; either version 3, or (at your option) any later --
9+
-- version. This library is distributed in the hope that it will be useful, --
10+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
11+
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
12+
-- --
13+
-- As a special exception under Section 7 of GPL version 3, you are granted --
14+
-- additional permissions described in the GCC Runtime Library Exception, --
15+
-- version 3.1, as published by the Free Software Foundation. --
16+
-- --
17+
-- You should have received a copy of the GNU General Public License and --
18+
-- a copy of the GCC Runtime Library Exception along with this program; --
19+
-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
20+
-- <http://www.gnu.org/licenses/>. --
21+
-- --
22+
------------------------------------------------------------------------------
23+
24+
with Ada.Calendar;
25+
with GNATCOLL.OS.Libc; use GNATCOLL.OS.Libc;
26+
with GNATCOLL.OS.FS;
27+
with GNAT.Task_Lock;
28+
29+
separate (GNATCOLL.OS.Process)
30+
31+
function Wait_For_Processes
32+
(Processes : Process_Array;
33+
Timeout : Duration)
34+
return Process_Handle
35+
is
36+
package FS renames GNATCOLL.OS.FS;
37+
package Cal renames Ada.Calendar;
38+
39+
use all type Cal.Time;
40+
41+
-- C Implementation is located in src/os/unix/process-wrappers.c
42+
43+
function Add_Monitoring_Fd (Fd : FS.File_Descriptor) return Libc_Status
44+
with Import => True,
45+
Convention => C,
46+
External_Name => "__gnatcoll_add_monitoring_fd";
47+
-- Add a file descriptor on which a byte should be written each time a
48+
-- SIGCHLD signal is received.
49+
50+
function Remove_Monitoring_Fd (Fd : FS.File_Descriptor) return Libc_Status
51+
with Import => True,
52+
Convention => C,
53+
External_Name => "__gnatcoll_remove_monitoring_fd";
54+
-- Remove a file descriptor added with the previous function.
55+
56+
function Init_Sigchld_Monitoring return Libc_Status
57+
with Import => True,
58+
Convention => C,
59+
External_Name => "__gnatcoll_init_sigchld_monitoring";
60+
-- Set signal handler for SIGCHLD.
61+
62+
function Wait_For_Sigchld
63+
(Fd : FS.File_Descriptor;
64+
Timeout : Sint_64)
65+
return Libc_Status
66+
with Import => True,
67+
Convention => C,
68+
External_Name => "__gnatcoll_wait_for_sigchld";
69+
-- Wait during timeout (in microseconds) for a write on Fd. If Timeout is
70+
-- < 0 then infinite is assumed.
71+
72+
function Get_First_Waitable_Process return Process.Process_Handle;
73+
-- Loop other the monitored processes and returned the first process in the
74+
-- WAITABLE state.
75+
76+
procedure Init_SIGCHLD_Monitoring
77+
with Inline => True;
78+
-- Init SIGCHLD monitoring
79+
80+
procedure Finalize_SIGCHLD_Monitoring
81+
with Inline => True;
82+
-- Finalize SIGCHLD monitorig
83+
84+
Pipe_Read, Pipe_Write : OS.FS.File_Descriptor;
85+
Status : Libc_Status;
86+
Result : Process_Handle := Process.Invalid_Handle;
87+
End_Time : constant Cal.Time := Cal.Clock + Timeout;
88+
-- Maximum end time
89+
90+
--------------------------------
91+
-- Get_First_Waitable_Process --
92+
--------------------------------
93+
94+
function Get_First_Waitable_Process return Process.Process_Handle is
95+
begin
96+
for Index in Processes'Range loop
97+
if State (Processes (Index)) = WAITABLE then
98+
return Processes (Index);
99+
end if;
100+
end loop;
101+
102+
return Invalid_Handle;
103+
end Get_First_Waitable_Process;
104+
105+
-----------------------------
106+
-- Init_SIGCHLD_Monitoring --
107+
-----------------------------
108+
109+
procedure Init_SIGCHLD_Monitoring is
110+
begin
111+
GNAT.Task_Lock.Lock;
112+
Status := Init_Sigchld_Monitoring;
113+
114+
if Status /= Success then
115+
raise OS_Error with "cannot set SIGCHLD signal handler";
116+
end if;
117+
118+
Status := Add_Monitoring_Fd (Pipe_Write);
119+
120+
if Status /= Success then
121+
raise OS_Error
122+
with "cannot call more than 256 concurrent wait_for_processes";
123+
end if;
124+
GNAT.Task_Lock.Unlock;
125+
end Init_SIGCHLD_Monitoring;
126+
127+
---------------------------------
128+
-- Finalize_SIGCHLD_Monitoring --
129+
---------------------------------
130+
131+
procedure Finalize_SIGCHLD_Monitoring is
132+
begin
133+
GNAT.Task_Lock.Lock;
134+
Status := Remove_Monitoring_Fd (Pipe_Write);
135+
136+
if Status /= Success then
137+
raise OS_Error with "invalid SIGCHLD monitoring Fd";
138+
end if;
139+
140+
GNAT.Task_Lock.Unlock;
141+
FS.Close (Pipe_Read);
142+
FS.Close (Pipe_Write);
143+
end Finalize_SIGCHLD_Monitoring;
144+
145+
begin
146+
-- Handle case in which process list is empty
147+
if Processes'Length = 0 then
148+
return Result;
149+
end if;
150+
151+
-- Perform a first check that will avoid need for locks, ...
152+
Result := Get_First_Waitable_Process;
153+
if Result /= Process.Invalid_Handle then
154+
return Result;
155+
end if;
156+
157+
if Timeout = 0.0 then
158+
-- No need to wait
159+
return Result;
160+
end if;
161+
162+
-- Put in place the monitoring infrastructure
163+
FS.Open_Pipe (Pipe_Read, Pipe_Write);
164+
165+
Init_SIGCHLD_Monitoring;
166+
167+
-- As some SIGCHLD might have been missed during the setup, perform another
168+
-- check
169+
Result := Get_First_Waitable_Process;
170+
171+
if Result /= Process.Invalid_Handle then
172+
Finalize_SIGCHLD_Monitoring;
173+
return Result;
174+
end if;
175+
176+
-- Start looping
177+
loop
178+
declare
179+
-- Remaining max waiting time in microseconds
180+
Microsecond_Timeout : constant Sint_64 :=
181+
Sint_64 ((End_Time - Cal.Clock) * 1_000_000);
182+
begin
183+
184+
-- Exit when timeout is reached and Timeout is not infinite
185+
-- (i.e < 0.0)
186+
if Microsecond_Timeout < 0 and then Timeout > 0.0 then
187+
exit;
188+
end if;
189+
190+
-- Wait
191+
Status := Wait_For_Sigchld (Pipe_Read, Microsecond_Timeout);
192+
193+
if Status = Success then
194+
-- A SIGCHLD has been received. Check if the process is in our
195+
-- list.
196+
Result := Get_First_Waitable_Process;
197+
if Result /= Invalid_Handle then
198+
exit;
199+
end if;
200+
end if;
201+
end;
202+
end loop;
203+
204+
Finalize_SIGCHLD_Monitoring;
205+
206+
return Result;
207+
208+
end Wait_For_Processes;

0 commit comments

Comments
 (0)