The following changes are importants:

- It is possible to have multiple tasks waiting for a child process
  to terminate.

- When a child terminates, a single wait call will receive the
  corresponding process id.

- A call to wait will handle new incoming child processes.

Tested on x86_64-pc-linux-gnu, committed on trunk

2014-11-20  Pascal Obry  <o...@adacore.com>

        * initialize.c (ProcListCS): New extern variable (critical section).
        (ProcListEvt): New extern variable (handle).
        (__gnat_initialize)[Win32]: Initialize the ProcListCS critical
        section object and the ProcListEvt event.
        * final.c (__gnat_finalize)[Win32]: Properly finalize the
        ProcListCS critical section and the ProcListEvt event.
        * adaint.c (ProcListEvt): New Win32 event handle.
        (EnterCS): New routine to enter the critical section when dealing with
        child processes chain list.
        (LeaveCS): As above to exit from the critical section.
        (SignalListChanged): Routine to signal that the chain process list has
        been updated.
        (add_handle): Use EnterCS/LeaveCS, also call SignalListChanged when the
        handle has been added.
        (__gnat_win32_remove_handle): Use EnterCS/LeaveCS,
        also call SignalListChanged if the handle has been found and removed.
        (remove_handle): Routine removed, implementation merged with the above.
        (win32_wait): Use EnterCS/LeaveCS for the critical section. Properly
        copy the PID list locally to ensure that even if the list is updated
        the local copy remains valid. Add into the hl (handle list) the
        ProcListEvt handle. This handle is used to signal that a change has
        been made into the process chain list. This is to ensure that a waiting
        call can be resumed to take into account new processes. We also make
        sure that if the handle was not found into the list we start over
        the wait call. Indeed another concurrent call to win32_wait()
        could already have handled this process.

Index: final.c
===================================================================
--- final.c     (revision 217828)
+++ final.c     (working copy)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2011, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2014, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT 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- *
@@ -40,11 +40,29 @@
    at all, the intention is that this be replaced by system specific code
    where finalization is required.  */
 
+#if defined (__MINGW32__)
+#include "mingw32.h"
+#include <windows.h>
+
+extern CRITICAL_SECTION ProcListCS;
+extern HANDLE ProcListEvt;
+
 void
 __gnat_finalize (void)
 {
+  /* delete critical section and event handle used for the
+     processes chain list */
+  DeleteCriticalSection(&ProcListCS);
+  CloseHandle (ProcListEvt);
 }
 
+#else
+void
+__gnat_finalize (void)
+{
+}
+#endif
+
 #ifdef __cplusplus
 }
 #endif
Index: initialize.c
===================================================================
--- initialize.c        (revision 217828)
+++ initialize.c        (working copy)
@@ -74,6 +74,8 @@
 
 extern int gnat_argc;
 extern char **gnat_argv;
+extern CRITICAL_SECTION ProcListCS;
+extern HANDLE ProcListEvt;
 
 #ifdef GNAT_UNICODE_SUPPORT
 
@@ -138,6 +140,11 @@
       given that we have set Max_Digits etc with this in mind */
    __gnat_init_float ();
 
+   /* Initialize the critical section and event handle for the win32_wait()
+      implementation, see adaint.c */
+   InitializeCriticalSection (&ProcListCS);
+   ProcListEvt = CreateEvent (NULL, FALSE, FALSE, NULL);
+
 #ifdef GNAT_UNICODE_SUPPORT
    /* Set current code page for filenames handling. */
    {
Index: adaint.c
===================================================================
--- adaint.c    (revision 217836)
+++ adaint.c    (working copy)
@@ -2311,21 +2311,30 @@
    for locking and unlocking tasks since we do not support multiple
    threads on this configuration (Cert run time on native Windows). */
 
-static void dummy (void)
+static void EnterCS (void) {}
+static void LeaveCS (void) {}
+static void SignalListChanged (void) {}
+
+#else
+
+CRITICAL_SECTION ProcListCS;
+HANDLE ProcListEvt;
+
+static void EnterCS (void)
 {
+  EnterCriticalSection(&ProcListCS);
 }
 
-void (*Lock_Task) ()   = &dummy;
-void (*Unlock_Task) () = &dummy;
+static void LeaveCS (void)
+{
+  LeaveCriticalSection(&ProcListCS);
+}
 
-#else
+static void SignalListChanged (void)
+{
+  SetEvent (ProcListEvt);
+}
 
-#define Lock_Task system__soft_links__lock_task
-extern void (*Lock_Task) (void);
-
-#define Unlock_Task system__soft_links__unlock_task
-extern void (*Unlock_Task) (void);
-
 #endif
 
 static HANDLE *HANDLES_LIST = NULL;
@@ -2335,7 +2344,7 @@
 add_handle (HANDLE h, int pid)
 {
   /* -------------------- critical section -------------------- */
-  (*Lock_Task) ();
+  EnterCS();
 
   if (plist_length == plist_max_length)
     {
@@ -2350,15 +2359,20 @@
   PID_LIST[plist_length] = pid;
   ++plist_length;
 
-  (*Unlock_Task) ();
+  SignalListChanged();
+  LeaveCS();
   /* -------------------- critical section -------------------- */
 }
 
-static void
-remove_handle (HANDLE h, int pid)
+int
+__gnat_win32_remove_handle (HANDLE h, int pid)
 {
   int j;
+  int found = 0;
 
+  /* -------------------- critical section -------------------- */
+  EnterCS();
+
   for (j = 0; j < plist_length; j++)
     {
       if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
@@ -2367,21 +2381,18 @@
           --plist_length;
           HANDLES_LIST[j] = HANDLES_LIST[plist_length];
           PID_LIST[j] = PID_LIST[plist_length];
+          found = 1;
           break;
         }
     }
-}
 
-void
-__gnat_win32_remove_handle (HANDLE h, int pid)
-{
+  LeaveCS();
   /* -------------------- critical section -------------------- */
-  (*Lock_Task) ();
 
-  remove_handle(h, pid);
+  if (found)
+    SignalListChanged();
 
-  (*Unlock_Task) ();
-  /* -------------------- critical section -------------------- */
+  return found;
 }
 
 static void
@@ -2466,36 +2477,71 @@
   DWORD exitcode, pid;
   HANDLE *hl;
   HANDLE h;
+  int *pidl;
   DWORD res;
   int hl_len;
+  int found;
 
-  /* -------------------- critical section -------------------- */
-  (*Lock_Task) ();
+ START_WAIT:
 
   if (plist_length == 0)
     {
       errno = ECHILD;
-      (*Unlock_Task) ();
       return -1;
     }
 
+  /* -------------------- critical section -------------------- */
+  EnterCS();
+
   hl_len = plist_length;
 
+#ifdef CERT
   hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
-
   memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
+  pidl = (int *) xmalloc (sizeof (int) * hl_len);
+  memmove (pidl, PID_LIST, sizeof (int) * hl_len);
+#else
+  /* Note that index 0 contains the event hanlde that is signaled when the
+     process list has changed */
+  hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len + 1);
+  hl[0] = ProcListEvt;
+  memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
+  pidl = (int *) xmalloc (sizeof (int) * hl_len + 1);
+  memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
+  hl_len++;
+#endif
 
+  LeaveCS();
+  /* -------------------- critical section -------------------- */
+
   res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
+
+  /* if the ProcListEvt has been signaled then the list of processes has been
+     updated to add or remove a handle, just loop over */
+
+  if (res - WAIT_OBJECT_0 == 0)
+    {
+      free (hl);
+      free (pidl);
+      goto START_WAIT;
+    }
+
   h = hl[res - WAIT_OBJECT_0];
-
   GetExitCodeProcess (h, &exitcode);
-  pid = PID_LIST [res - WAIT_OBJECT_0];
-  remove_handle (h, -1);
+  pid = pidl [res - WAIT_OBJECT_0];
 
-  (*Unlock_Task) ();
-  /* -------------------- critical section -------------------- */
+  found = __gnat_win32_remove_handle (h, -1);
+
   free (hl);
+  free (pidl);
 
+  /* if not found another process waiting has already handled this process */
+
+  if (!found)
+    {
+      goto START_WAIT;
+    }
+
   *status = (int) exitcode;
   return (int) pid;
 }
Index: adaint.h
===================================================================
--- adaint.h    (revision 217828)
+++ adaint.h    (working copy)
@@ -299,7 +299,7 @@
 #if defined (_WIN32)
 /* Interface to delete a handle from internally maintained list of child
    process handles on Windows */
-extern void
+extern int
 __gnat_win32_remove_handle (HANDLE h, int pid);
 #endif
 

Reply via email to