diff --git a/source/spawn/spawn-channels__glib_posix.adb b/source/spawn/spawn-channels__glib_posix.adb index 3acfacc..7aa9ff0 100644 --- a/source/spawn/spawn-channels__glib_posix.adb +++ b/source/spawn/spawn-channels__glib_posix.adb @@ -76,7 +76,28 @@ package body Spawn.Channels is with Convention => C; -- Common code to start (continue) watching of the IO channel. - procedure On_Close_Channels (Self : Channels); + procedure Channel_Error (Self : Channels); + -- Executed on IO channel failure to report postponed Finished signal. + + ------------------- + -- Channel_Error -- + ------------------- + + procedure Channel_Error (Self : Channels) is + begin + if Self.Process.Pending_Finish then + -- Check whether all IO operations are done, then emit Finished + -- callback. + + if not Is_Active (Self) then + Self.Process.Pending_Finish := False; + Self.Process.Status := Not_Running; + + Self.Process.Emit_Finished + (Self.Process.Exit_Status, Self.Process.Exit_Code); + end if; + end if; + end Channel_Error; ----------------------------- -- Close_Child_Descriptors -- @@ -113,28 +134,12 @@ package body Spawn.Channels is function Is_Active (Self : Channels) return Boolean is begin - return Self.Stdout_Event /= Glib.Main.No_Source_Id - or Self.Stderr_Event /= Glib.Main.No_Source_Id; + return + Self.Stdin_Event /= Glib.Main.No_Source_Id + or Self.Stdout_Event /= Glib.Main.No_Source_Id + or Self.Stderr_Event /= Glib.Main.No_Source_Id; end Is_Active; - ----------------------- - -- On_Close_Channels -- - ----------------------- - - procedure On_Close_Channels (Self : Channels) is - begin - if Self.Process.Pending_Finish then - Self.Process.Pending_Finish := False; - Self.Process.Status := Not_Running; - - Self.Process.Emit_Finished - (Self.Process.Exit_Status, Self.Process.Exit_Code); - end if; - exception - when others => - null; - end On_Close_Channels; - --------------------- -- On_Stderr_Event -- --------------------- @@ -149,26 +154,29 @@ package body Spawn.Channels is Self : Channels renames data.Self.Channels; begin - if (condition and Glib.IOChannel.G_Io_In) /= 0 then - Self.Stderr_Lock := @ - 1; + Self.Stderr_Lock := @ - 1; + if (condition and Glib.IOChannel.G_Io_In) /= 0 then Self.Process.Emit_Stderr_Available; - if Self.Stderr_Lock = 0 then - Self.Stderr_Event := Glib.Main.No_Source_Id; - end if; + elsif (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Self.Process.Emit_Standard_Error_Stream_Error + ("GIOChannel IO error"); end if; - if (condition and Glib.IOChannel.G_Io_Hup) /= 0 then - Self.Stderr_Lock := 0; + if Self.Stderr_Lock = 0 then Self.Stderr_Event := Glib.Main.No_Source_Id; - - if Self.Stdout_Event = Glib.Main.No_Source_Id then - On_Close_Channels (Self); - end if; end if; - return Self.Stderr_Lock; + if (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Channel_Error (Self); + end if; + + return Self.Stdout_Lock; end On_Stderr_Event; -------------------- @@ -181,19 +189,32 @@ package body Spawn.Channels is data : access Internal.Process_Reference) return Glib.Gboolean is pragma Unreferenced (source); - pragma Unreferenced (condition); Self : Channels renames data.Self.Channels; begin Self.Stdin_Lock := @ - 1; - Self.Process.Emit_Stdin_Available; + if (condition and Glib.IOChannel.G_Io_Out) /= 0 then + Self.Process.Emit_Stdin_Available; + + elsif (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Self.Process.Emit_Standard_Error_Stream_Error + ("GIOChannel IO error"); + end if; if Self.Stdin_Lock = 0 then Self.Stdin_Event := Glib.Main.No_Source_Id; end if; + if (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Channel_Error (Self); + end if; + return Self.Stdin_Lock; end On_Stdin_Event; @@ -211,23 +232,26 @@ package body Spawn.Channels is Self : Channels renames data.Self.Channels; begin - if (condition and Glib.IOChannel.G_Io_In) /= 0 then - Self.Stdout_Lock := @ - 1; + Self.Stdout_Lock := @ - 1; + if (condition and Glib.IOChannel.G_Io_In) /= 0 then Self.Process.Emit_Stdout_Available; - if Self.Stdout_Lock = 0 then - Self.Stdout_Event := Glib.Main.No_Source_Id; - end if; + elsif (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Self.Process.Emit_Standard_Output_Stream_Error + ("GIOChannel IO error"); end if; - if (condition and Glib.IOChannel.G_Io_Hup) /= 0 then - Self.Stdout_Lock := 0; + if Self.Stdout_Lock = 0 then Self.Stdout_Event := Glib.Main.No_Source_Id; + end if; - if Self.Stderr_Event = Glib.Main.No_Source_Id then - On_Close_Channels (Self); - end if; + if (condition and Glib.IOChannel.G_Io_Hup) /= 0 + or (condition and Glib.IOChannel.G_Io_Err) /= 0 + then + Channel_Error (Self); end if; return Self.Stdout_Lock; @@ -757,7 +781,9 @@ package body Spawn.Channels is (Self.Stderr_Parent, Self.Stderr_Event, Self.Stderr_Lock, - Glib.IOChannel.G_Io_In + Glib.IOChannel.G_Io_Hup, + Glib.IOChannel.G_Io_In + + Glib.IOChannel.G_Io_Hup + + Glib.IOChannel.G_Io_Err, On_Stderr_Event'Access, Self.Process.Reference'Unchecked_Access); end if; @@ -773,7 +799,9 @@ package body Spawn.Channels is (Self.Stdin_Parent, Self.Stdin_Event, Self.Stdin_Lock, - Glib.IOChannel.G_Io_Out, + Glib.IOChannel.G_Io_Out + + Glib.IOChannel.G_Io_Hup + + Glib.IOChannel.G_Io_Err, On_Stdin_Event'Access, Self.Process.Reference'Unchecked_Access); end Start_Stdin_Watch; @@ -788,7 +816,9 @@ package body Spawn.Channels is (Self.Stdout_Parent, Self.Stdout_Event, Self.Stdout_Lock, - Glib.IOChannel.G_Io_In + Glib.IOChannel.G_Io_Hup, + Glib.IOChannel.G_Io_In + + Glib.IOChannel.G_Io_Hup + + Glib.IOChannel.G_Io_Err, On_Stdout_Event'Access, Self.Process.Reference'Unchecked_Access); end Start_Stdout_Watch; diff --git a/source/spawn/spawn-channels__glib_posix.ads b/source/spawn/spawn-channels__glib_posix.ads index ec99cb3..d22718e 100644 --- a/source/spawn/spawn-channels__glib_posix.ads +++ b/source/spawn/spawn-channels__glib_posix.ads @@ -71,16 +71,25 @@ private Stdin_Child : Glib.Gint := -1; Stdin_Event : Glib.Main.G_Source_Id := Glib.Main.No_Source_Id; Stdin_Lock : Glib.Gboolean := 0; + -- Lock of the Stdin_Event field. Lock is managed as counter + -- to prevent reset of the Stdin_Event field by the nested IO + -- operation on the channel. Stdout_Parent : Glib.IOChannel.Giochannel := null; Stdout_Child : Glib.Gint := -1; Stdout_Event : Glib.Main.G_Source_Id := Glib.Main.No_Source_Id; Stdout_Lock : Glib.Gboolean := 0; + -- Lock of the Stdout_Event field. Lock is managed as counter + -- to prevent reset of the Stdout_Event field by the nested IO + -- operation on the channel. Stderr_Parent : Glib.IOChannel.Giochannel := null; Stderr_Child : Glib.Gint := -1; Stderr_Event : Glib.Main.G_Source_Id := Glib.Main.No_Source_Id; Stderr_Lock : Glib.Gboolean := 0; + -- Lock of the Stderr_Event field. Lock is managed as counter + -- to prevent reset of the Stderr_Event field by the nested IO + -- operation on the channel. PTY_Slave : Glib.Gint := -1; end record;