On Thu, 17 Jul 2025 23:14:21 +0900
Takashi Yano wrote:
> As a starting point, I tried tntroducing locking. It almost works
> as expected, however, sometimes my STC in my first report is hangs
> if N is large e.g. 100. The patch is as attached.
> 
> What am I missing?

Patch revised.

-- 
Takashi Yano <[email protected]>
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index cb58b6eed..100c1246e 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -273,6 +273,7 @@ struct system_call_handle
 };
 
 child_info_spawn NO_COPY ch_spawn;
+static NO_COPY SRWLOCK ch_spawn_lock = SRWLOCK_INIT;
 
 extern "C" void __posix_spawn_sem_release (void *sem, int error);
 
@@ -333,6 +334,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
 
   __try
     {
+      AcquireSRWLockExclusive (&ch_spawn_lock);
       child_info_types chtype;
       if (mode == _P_OVERLAY)
        chtype = _CH_EXEC;
@@ -354,13 +356,17 @@ child_info_spawn::worker (const char *prog_arg, const 
char *const *argv,
        {
          set_errno (err);
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
 
       res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec);
 
       if (res)
-       __leave;
+       {
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
+         __leave;
+       }
 
       if (!real_path.iscygexec () && ::cygheap->cwd.get_error ())
        {
@@ -369,6 +375,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
                        ::cygheap->cwd.get_error_desc ());
          set_errno (::cygheap->cwd.get_error ());
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
 
@@ -382,6 +389,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
                             real_path.iscygexec ()))
        {
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
 
@@ -492,6 +500,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        {
          set_errno (ENAMETOOLONG);
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
 
@@ -512,6 +521,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        {
          set_errno (E2BIG);
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
       set (chtype, real_path.iscygexec ());
@@ -728,6 +738,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
            ::cygheap->user.reimpersonate ();
 
          res = -1;
+          ReleaseSRWLockExclusive (&ch_spawn_lock);
          __leave;
        }
 
@@ -781,6 +792,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
              if (get_errno () != ENOMEM)
                set_errno (EAGAIN);
              res = -1;
+             ReleaseSRWLockExclusive (&ch_spawn_lock);
              __leave;
            }
          child->dwProcessId = pi.dwProcessId;
@@ -816,6 +828,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
              CloseHandle (pi.hProcess);
              ForceCloseHandle (pi.hThread);
              res = -1;
+             ReleaseSRWLockExclusive (&ch_spawn_lock);
              __leave;
            }
        }
@@ -845,6 +858,10 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
           wait for it to exit in maybe_set_exit_code_from_windows(). */
        synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : 
true;
 
+      pid_t ch_pid = cygpid;
+      bool ch_iscygwin = iscygwin ();
+      this->cleanup ();
+      ReleaseSRWLockExclusive (&ch_spawn_lock);
       switch (mode)
        {
        case _P_OVERLAY:
@@ -860,7 +877,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
            }
          else
            {
-             if (iscygwin ())
+             if (ch_iscygwin)
                close_all_files (true);
              if (!my_wr_proc_pipe
                  && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
@@ -891,7 +908,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        case _P_WAIT:
        case _P_SYSTEM:
          system_call.arm ();
-         if (waitpid (cygpid, &res, 0) != cygpid)
+         if (waitpid (ch_pid, &res, 0) != ch_pid)
            res = -1;
          term_spawn_worker.cleanup ();
          break;
@@ -901,7 +918,7 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
        case _P_NOWAIT:
        case _P_NOWAITO:
        case _P_VFORK:
-         res = cygpid;
+         res = ch_pid;
          break;
        default:
          break;
@@ -909,6 +926,8 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
     }
   __except (NO_ERROR)
     {
+      this->cleanup ();
+      ReleaseSRWLockExclusive (&ch_spawn_lock);
       if (get_errno () == ENOMEM)
        set_errno (E2BIG);
       else
@@ -917,7 +936,6 @@ child_info_spawn::worker (const char *prog_arg, const char 
*const *argv,
     }
   __endtry
   term_spawn_worker.close_handle_set ();
-  this->cleanup ();
   if (envblock)
     free (envblock);
 
-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to