Make_Independent decrements Wait_Count, which caused a race condition -- if the
timing is just wrong, it causes Make_Passive to find Wait_Count = 0, which
eventually causes the program to hang. This patch prevents hanging by
decrementing Wait_Count only if nonzero.
No test is available, because it's large, and only fails intermittently.
Tested on x86_64-pc-linux-gnu, committed on trunk
2011-08-29 Bob Duff <[email protected]>
* s-tasuti.adb (Make_Passive): Work around race condition in
Make_Independent, which can cause Wait_Count to be zero. So instead of
asserting that Wait_Count > 0, and then decrementing it, decrement it
only if Wait_Count > 0.
* s-taskin.ads (Wait_Count, Alive_Count, Awake_Count): All of these
should be nonnegative, so declare them Natural instead of Integer.
Index: s-tasuti.adb
===================================================================
--- s-tasuti.adb (revision 178155)
+++ s-tasuti.adb (working copy)
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2009, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2011, Free Software Foundation, Inc. --
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -504,12 +504,14 @@
(Debug.Trace
(Self_ID, "Make_Passive: Phase 1, parent waiting", 'M'));
- -- If parent is in Master_Completion_Sleep, it
- -- cannot be on a terminate alternative, hence
- -- it cannot have Awake_Count of zero.
+ -- If parent is in Master_Completion_Sleep, it cannot be on a
+ -- terminate alternative, hence it cannot have Wait_Count of
+ -- zero. ???Except that the race condition in Make_Independent can
+ -- cause Wait_Count to be zero, so we need to check for that.
- pragma Assert (P.Common.Wait_Count > 0);
- P.Common.Wait_Count := P.Common.Wait_Count - 1;
+ if P.Common.Wait_Count > 0 then
+ P.Common.Wait_Count := P.Common.Wait_Count - 1;
+ end if;
if P.Common.Wait_Count = 0 then
Wakeup (P, Master_Completion_Sleep);
Index: s-taskin.ads
===================================================================
--- s-taskin.ads (revision 178155)
+++ s-taskin.ads (working copy)
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2010, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2011, Free Software Foundation, Inc. --
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -566,7 +566,7 @@
-- Protection: Set by Activator before Self is activated, and only read
-- and modified by Self after that.
- Wait_Count : Integer;
+ Wait_Count : Natural;
-- This count is used by a task that is waiting for other tasks. At all
-- other times, the value should be zero. It is used differently in
-- several different states. Since a task cannot be in more than one of
@@ -942,13 +942,13 @@
-- not write this field until the master is complete, the
-- synchronization should be adequate to prevent races.
- Alive_Count : Integer := 0;
+ Alive_Count : Natural := 0;
-- Number of tasks directly dependent on this task (including itself)
-- that are still "alive", i.e. not terminated.
--
-- Protection: Self.L
- Awake_Count : Integer := 0;
+ Awake_Count : Natural := 0;
-- Number of tasks directly dependent on this task (including itself)
-- still "awake", i.e., are not terminated and not waiting on a
-- terminate alternative.