public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: processes: use dedicated Cygwin PID rather than Windows PID
@ 2019-02-01 19:07 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2019-02-01 19:07 UTC (permalink / raw)
  To: cygwin-cvs

https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=b5e1003722cb14235c4f166be72c09acdffc62ea

commit b5e1003722cb14235c4f166be72c09acdffc62ea
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Thu Jan 31 21:19:03 2019 +0100

    Cygwin: processes: use dedicated Cygwin PID rather than Windows PID
    
    Using the Windows PID as Cygwin PID has a few drawbacks:
    
    - the PIDs on Windows get reused quickly.  Some POSIX applications choke
      on that, so we need extra code to avoid too quick PID reuse.
    
    - The code to avoid PID reuse keeps parent process handles and
      (depending on a build option) child processes open unnecessarily.
    
    - After an execve, the process has a split personality:  Its Windows PID
      is a new PID, while its Cygwin PID is the PID of the execve caller
      process.  This requires to keep two procinfo shared sections open, the
      second just to redirect process info requests to the first, correct
      one.
    
    This patch changes the way Cygwin PIDs are generated:
    
    - Cygwin PIDs are generated independently of the Windows PID, in a way
      expected by POSIX processes.  The PIDs are created incrementally in
      the range between 2 and 65535, round-robin.
    
    - On startup of the first Cygwin process, choose a semi-random start PID
      for the first process in the lower PID range to make the PIDs slightly
      unpredictable.  This may not be necessary but it seems kind of inviting
      to know that the first Cygwin process always starts with PID 2.
    
    - Every process not only creates the shared procinfo section, but also a
      symlink in the NT namespace, symlinking the Windows PID to the Cygwin
      PID.  This drops the need for the extra procinfo section after execve.
    
    - Don't keep other process handles around unnecessarily.
    
    - Simplify the code creating/opening the shared procinfo section and
      make a clear distinction between interfaces getting a Cygwin PID and
      interfaces getting a Windows PID.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/dcrt0.cc                 |  27 +----
 winsup/cygwin/fork.cc                  |  33 -----
 winsup/cygwin/include/cygwin/version.h |   3 +-
 winsup/cygwin/include/sys/cygwin.h     |   3 +-
 winsup/cygwin/pinfo.cc                 | 212 ++++++++++++++++++++-------------
 winsup/cygwin/pinfo.h                  |  22 ++--
 winsup/cygwin/release/3.0              |   3 +
 winsup/cygwin/shared.cc                |   5 +
 winsup/cygwin/shared_info.h            |   3 +-
 winsup/cygwin/spawn.cc                 |   2 +-
 winsup/doc/new-features.xml            |   5 +
 11 files changed, 162 insertions(+), 156 deletions(-)

diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 463df31..5cdf01c 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -687,28 +687,11 @@ child_info_spawn::handle_spawn ()
 
   if (child_proc_info->parent)
     {
-      if (type == _CH_EXEC)
-	{
-	  /* Keep pointer to parent open if we've execed so that pid will not be
-	     reused.  Try to Urther reduce permissions. */
-	  HANDLE new_parent;
-
-	  if (DuplicateHandle (GetCurrentProcess (), child_proc_info->parent,
-			       GetCurrentProcess (), &new_parent,
-			       SYNCHRONIZE, FALSE, 0))
-	    {
-	      CloseHandle (child_proc_info->parent);
-	      child_proc_info->parent = new_parent;
-	    }
-	}
-      else
-	{
-	  /* Otherwise, we no longer need this handle so close it.  Need to do
-	     this after debug_fixup_after_fork_exec or DEBUGGING handling of
-	     handles might get confused. */
-	  CloseHandle (child_proc_info->parent);
-	  child_proc_info->parent = NULL;
-	}
+      /* We no longer need this handle so close it.  Need to do
+	 this after debug_fixup_after_fork_exec or DEBUGGING handling of
+	 handles might get confused. */
+      CloseHandle (child_proc_info->parent);
+      child_proc_info->parent = NULL;
     }
 
   signal_fixup_after_exec ();
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index d8c4ac4..c083f7a 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -209,35 +209,6 @@ frok::child (volatile char * volatile here)
   return 0;
 }
 
-#define NO_SLOW_PID_REUSE
-#ifndef NO_SLOW_PID_REUSE
-static void
-slow_pid_reuse (HANDLE h)
-{
-  static NO_COPY HANDLE last_fork_procs[NPIDS_HELD];
-  static NO_COPY unsigned nfork_procs;
-
-  if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
-    nfork_procs = 0;
-  /* Keep a list of handles to child processes sitting around to prevent
-     Windows from reusing the same pid n times in a row.  Having the same pids
-     close in succesion confuses bash.  Keeping a handle open will stop
-     windows from reusing the same pid.  */
-  if (last_fork_procs[nfork_procs])
-    ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
-  if (DuplicateHandle (GetCurrentProcess (), h,
-		       GetCurrentProcess (), &last_fork_procs[nfork_procs],
-		       0, FALSE, DUPLICATE_SAME_ACCESS))
-    ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
-  else
-    {
-      last_fork_procs[nfork_procs] = NULL;
-      system_printf ("couldn't create last_fork_proc, %E");
-    }
-  nfork_procs++;
-}
-#endif
-
 int __stdcall
 frok::parent (volatile char * volatile stack_here)
 {
@@ -437,10 +408,6 @@ frok::parent (volatile char * volatile stack_here)
       goto cleanup;
     }
 
-#ifndef NO_SLOW_PID_REUSE
-  slow_pid_reuse (hchild);
-#endif
-
   /* CHILD IS STOPPED */
   debug_printf ("child is alive (but stopped)");
 
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index b5ba93f..8926d49 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -506,12 +506,13 @@ details. */
   333: Add timerfd_create, timerfd_gettime, timerfd_settime.
   334: Remove matherr.
   335: Change size of utsname, change uname output.
+  336: New Cygwin PID algorithm (yeah, not really an API change)
 
   Note that we forgot to bump the api for ualarm, strtoll, strtoull,
   sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 335
+#define CYGWIN_VERSION_API_MINOR 336
 
 /* There is also a compatibity version number associated with the shared memory
    regions.  It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h
index c5da87c..480d8ea 100644
--- a/winsup/cygwin/include/sys/cygwin.h
+++ b/winsup/cygwin/include/sys/cygwin.h
@@ -269,8 +269,7 @@ enum
   PID_INITIALIZING     = 0x00800, /* Set until ready to receive signals. */
   PID_NEW	       = 0x01000, /* Available. */
   PID_ALLPIDS	       = 0x02000, /* used by pinfo scanner */
-  PID_EXECED	       = 0x04000, /* redirect to original pid info block */
-  PID_NOREDIR	       = 0x08000, /* don't redirect if execed */
+  PID_PROCINFO	       = 0x08000, /* caller just asks for process info */
   PID_EXITED	       = 0x40000000, /* Free entry. */
   PID_REAPED	       = 0x80000000  /* Reaped */
 };
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 90dfd2b..98168c7 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -58,8 +58,7 @@ pinfo::thisproc (HANDLE h)
   DWORD flags = PID_IN_USE | PID_ACTIVE;
   if (!h)
     {
-      h = INVALID_HANDLE_VALUE;
-      cygheap->pid = cygwin_pid (myself_initial.pid);
+      cygheap->pid = create_cygwin_pid ();
       flags |= PID_NEW;
     }
 
@@ -68,16 +67,10 @@ pinfo::thisproc (HANDLE h)
   procinfo->dwProcessId = myself_initial.pid;
   procinfo->sendsig = myself_initial.sendsig;
   wcscpy (procinfo->progname, myself_initial.progname);
+  create_winpid_symlink (procinfo->pid, procinfo->dwProcessId);
+  procinfo->exec_sendsig = NULL;
+  procinfo->exec_dwProcessId = 0;
   debug_printf ("myself dwProcessId %u", procinfo->dwProcessId);
-  if (h != INVALID_HANDLE_VALUE)
-    {
-      /* here if execed */
-      static pinfo NO_COPY myself_identity;
-      myself_identity.init (cygwin_pid (procinfo->dwProcessId), PID_EXECED, NULL);
-      procinfo->exec_sendsig = NULL;
-      procinfo->exec_dwProcessId = 0;
-      myself_identity->ppid = procinfo->pid;
-    }
 }
 
 /* Initialize the process table entry for the current task.
@@ -109,7 +102,8 @@ pinfo_init (char **envp, int envc)
   myself->process_state |= PID_ACTIVE;
   myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED);
   myself.preserve ();
-  debug_printf ("pid %d, pgid %d, process_state %y", myself->pid, myself->pgid, myself->process_state);
+  debug_printf ("pid %d, pgid %d, process_state %y",
+		myself->pid, myself->pgid, myself->process_state);
 }
 
 DWORD
@@ -152,7 +146,7 @@ pinfo::status_exit (DWORD x)
 	 reason (but note, the environment *in* CMD is broken and shortened).
 	 This occurs at a point where there's no return to the exec'ing parent
 	 process, so we have to find some way to inform the user what happened.
-	 
+
 	 FIXME: For now, just return with SIGBUS set.  Maybe it's better to add
 	 a lengthy small_printf instead. */
       x = SIGBUS;
@@ -229,6 +223,106 @@ pinfo::exit (DWORD n)
 }
 # undef self
 
+/* Return next free Cygwin PID between 2 and 65535, round-robin.  Each new
+   PID is checked that it doesn't collide with an existing PID.  For that,
+   just check if the "cygpid.PID" section exists. */
+pid_t
+create_cygwin_pid ()
+{
+  pid_t pid = 0;
+  WCHAR sym_name[24];
+  UNICODE_STRING sym_str;
+  OBJECT_ATTRIBUTES attr;
+  HANDLE sym_hdl;
+  NTSTATUS status;
+
+  do
+    {
+      do
+	{
+	  pid = ((uint32_t) InterlockedIncrement (&cygwin_shared->pid_src))
+		% 65536;
+	}
+      while (pid < 2);
+      __small_swprintf (sym_name, L"cygpid.%u", pid);
+      RtlInitUnicodeString (&sym_str, sym_name);
+      InitializeObjectAttributes (&attr, &sym_str, OBJ_CASE_INSENSITIVE,
+				  get_shared_parent_dir (), NULL);
+      /* We just want to know if the section (and thus the process) still
+         exists.  Instead of actually opening the section, try to open
+	 it as symlink.  NtOpenSymbolicLinkObject will always returns an
+	 error:
+	 - STATUS_OBJECT_NAME_NOT_FOUND if the section doesn't exist,
+	   so the slot is free and we can use this pid.
+	 - STATUS_OBJECT_TYPE_MISMATCH if the section exists, so we have
+	   to skip this pid and loop to try the next one.
+	  As side-effect we never have to close the section handle and thus
+	  we don't influence the lifetime of the section. */
+      status = NtOpenSymbolicLinkObject (&sym_hdl, SYMBOLIC_LINK_QUERY, &attr);
+    }
+  while (status == STATUS_OBJECT_TYPE_MISMATCH);
+  return pid;
+}
+
+/* Convert Windows WINPID into Cygwin PID.  Utilize the "winpid.WINPID"
+   symlinks created for each process.  The symlink contains the Cygwin
+   PID as target.  Return 0 if no "winpid.WINPID" symlink exists for
+   this WINPID. */
+pid_t
+cygwin_pid (DWORD dwProcessId)
+{
+  WCHAR sym_name[24];
+  WCHAR pid_name[12];
+  UNICODE_STRING sym_str;
+  UNICODE_STRING pid_str;
+  OBJECT_ATTRIBUTES attr;
+  HANDLE sym_hdl;
+  NTSTATUS status;
+
+  __small_swprintf (sym_name, L"winpid.%u", dwProcessId);
+  RtlInitUnicodeString (&sym_str, sym_name);
+  InitializeObjectAttributes (&attr, &sym_str, OBJ_CASE_INSENSITIVE,
+			      get_shared_parent_dir (), NULL);
+  status = NtOpenSymbolicLinkObject (&sym_hdl, SYMBOLIC_LINK_QUERY, &attr);
+  if (!NT_SUCCESS (status))
+    return 0;
+  RtlInitEmptyUnicodeString (&pid_str, pid_name,
+			     sizeof pid_name - sizeof (WCHAR));
+  status = NtQuerySymbolicLinkObject (sym_hdl, &pid_str, NULL);
+  NtClose (sym_hdl);
+  if (!NT_SUCCESS (status))
+    {
+      system_printf ("NtOpenSymbolicLinkObject: %y, PID %u, ret 0",
+		     status, dwProcessId);
+      return 0;
+    }
+  pid_str.Buffer[pid_str.Length / sizeof (WCHAR)] = L'\0';
+  pid_t ret = (pid_t) wcstoul (pid_str.Buffer, NULL, 10);
+  return ret;
+}
+
+/* Create "winpid.WINPID" symlinks with the Cygwin PID of that process as
+   target.  This is used to find the Cygwin PID for a given Windows WINPID. */
+inline void
+pinfo::create_winpid_symlink (pid_t cygpid, DWORD winpid)
+{
+  WCHAR sym_name[24];
+  WCHAR pid_name[24];
+  UNICODE_STRING sym_str;
+  UNICODE_STRING pid_str;
+  OBJECT_ATTRIBUTES attr;
+
+  __small_swprintf (sym_name, L"winpid.%u",
+		    procinfo->dwProcessId ?: myself_initial.pid);
+  RtlInitUnicodeString (&sym_str, sym_name);
+  __small_swprintf (pid_name, L"%u", procinfo->pid);
+  RtlInitUnicodeString (&pid_str, pid_name);
+  InitializeObjectAttributes (&attr, &sym_str, OBJ_CASE_INSENSITIVE,
+			      get_shared_parent_dir (), NULL);
+  NtCreateSymbolicLinkObject (&winpid_hdl, SYMBOLIC_LINK_ALL_ACCESS,
+			      &attr, &pid_str);
+}
+
 inline void
 pinfo::_pinfo_release ()
 {
@@ -252,20 +346,18 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0)
 {
   shared_locations shloc;
   h = NULL;
-  if (myself && !(flag & PID_EXECED)
-      && (n == myself->pid || (DWORD) n == myself->dwProcessId))
+  if (myself && n == myself->pid)
     {
       procinfo = myself;
       destroy = 0;
       return;
     }
 
-  int createit = flag & (PID_IN_USE | PID_EXECED);
+  int createit = (flag & PID_IN_USE);
   DWORD access = FILE_MAP_READ
-		 | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW)
-		    ? FILE_MAP_WRITE : 0);
+		 | (flag & (PID_IN_USE | PID_MAP_RW) ? FILE_MAP_WRITE : 0);
   if (!h0 || myself.h)
-    shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN;
+    shloc = (flag & PID_IN_USE) ? SH_JUSTCREATE : SH_JUSTOPEN;
   else
     {
       shloc = SH_MYSELF;
@@ -281,14 +373,8 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0)
 
   for (int i = 0; i < 20; i++)
     {
-      DWORD mapsize;
-      if (flag & PID_EXECED)
-	mapsize = PINFO_REDIR_SIZE;
-      else
-	mapsize = sizeof (_pinfo);
-
-      procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, mapsize, &shloc,
-					 sec_attribs, access);
+      procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, sizeof (_pinfo),
+					 &shloc, sec_attribs, access);
       if (!h0)
 	{
 	  if (createit)
@@ -311,33 +397,10 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0)
 
       bool created = shloc != SH_JUSTOPEN;
 
-      /* Detect situation where a transitional memory block is being retrieved.
-	 If the block has been allocated with PINFO_REDIR_SIZE but not yet
-	 updated with a PID_EXECED state then we'll retry.  */
-      if (!created && !(flag & PID_NEW) && !procinfo->ppid)
-	{
-	  /* Fetching process info for /proc or ps?  just ignore this one. */
-	  if (flag & PID_NOREDIR)
-	    break;
-	  /* FIXME: Do we ever hit this case?  And if so, in what situation? */
-	  system_printf ("This shouldn't happen:\n"
-			 "    me: (%d, %d, %d, %W)\n"
-			 "    pid %d\n"
-			 "    process_state %y\n"
-			 "    cygstarted %d\n"
-			 "    dwProcessId %d\n"
-			 "    name %W",
-			 myself->pid, myself->dwProcessId, myself->cygstarted,
-			 myself->progname,
-			 procinfo->pid, procinfo->process_state,
-			 procinfo->cygstarted, procinfo->dwProcessId,
-			 procinfo->progname);
-	  /* If not populated, wait 2 seconds for procinfo to become populated.
-	     Would like to wait with finer granularity but that is not easily
-	     doable.  */
-	  for (int i = 0; i < 200 && !procinfo->ppid; i++)
-	    Sleep (10);
-	}
+      /* Just fetching info for ps or /proc, don't do anything rash. */
+      if (!created && !(flag & PID_NEW) && !procinfo->ppid
+	  && (flag & PID_PROCINFO))
+	break;
 
       if (!created && createit && (procinfo->process_state & PID_REAPED))
 	{
@@ -346,32 +409,18 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0)
 				   shared memory */
 	}
 
-      if ((procinfo->process_state & PID_REAPED)
-	  || ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
-	      && cygwin_pid (procinfo->dwProcessId) != procinfo->pid))
+      if (procinfo->process_state & PID_REAPED)
 	{
 	  set_errno (ESRCH);
 	  break;
 	}
 
-      if (procinfo->process_state & PID_EXECED)
-	{
-	  pid_t realpid = procinfo->pid;
-	  debug_printf ("execed process windows pid %u, cygwin pid %d", n, realpid);
-	  if (realpid == n)
-	    api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
-
-	  n = realpid;
-	  CloseHandle (h0);
-	  h0 = NULL;
-	  goto loop;
-	}
-
       /* In certain pathological cases, it is possible for the shared memory
 	 region to exist for a while after a process has exited.  This should
 	 only be a brief occurrence, so rather than introduce some kind of
 	 locking mechanism, just loop.  */
-      if (!created && createit && (procinfo->process_state & (PID_EXITED | PID_REAPED)))
+      if (!created && createit
+	  && (procinfo->process_state & (PID_EXITED | PID_REAPED)))
 	{
 	  debug_printf ("looping because pid %d, procinfo->pid %d, "
 			"procinfo->dwProcessid %u has PID_EXITED|PID_REAPED set",
@@ -381,15 +430,8 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0)
 
       if (flag & PID_NEW)
 	procinfo->start_time = time (NULL);
-      if (!created)
-	/* nothing */;
-      else if (!(flag & PID_EXECED))
+      if (created)
 	procinfo->pid = n;
-      else
-	{
-	  procinfo->process_state |= PID_IN_USE | PID_EXECED;
-	  procinfo->pid = myself->pid;
-	}
 
       h = h0;	/* Success! */
       break;
@@ -529,7 +571,7 @@ _pinfo::set_ctty (fhandler_termios *fh, int flags)
 bool __reg1
 _pinfo::exists ()
 {
-  return process_state && !(process_state & (PID_EXITED | PID_REAPED | PID_EXECED));
+  return process_state && !(process_state & (PID_EXITED | PID_REAPED));
 }
 
 bool
@@ -1279,6 +1321,8 @@ void
 pinfo::release ()
 {
   _pinfo_release ();
+  if (winpid_hdl)
+    NtClose (winpid_hdl);
   HANDLE close_h;
   if (rd_proc_pipe)
     {
@@ -1389,7 +1433,7 @@ winpids::add (DWORD& nelem, bool winpid, DWORD pid)
 	 make a copy of the shared memory area when it exists (it may not).  */
       perform_copy = onreturn ? make_copy : true;
 
-      p.init (cygpid, PID_NOREDIR | pinfo_access, NULL);
+      p.init (cygpid, PID_PROCINFO | pinfo_access, NULL);
     }
 
   /* If we're just looking for winpids then don't do any special cygwin "stuff* */
@@ -1403,9 +1447,9 @@ winpids::add (DWORD& nelem, bool winpid, DWORD pid)
      that it isn't a cygwin process. */
   if (!p)
     {
-      if (!pinfo_access)
+      if (!pinfo_access || !cygpid)
 	return;
-      p.init (cygpid, PID_NOREDIR, NULL);
+      p.init (cygpid, PID_PROCINFO, NULL);
       if (!p)
 	return;
     }
@@ -1491,7 +1535,7 @@ winpids::enum_processes (bool winpid)
 	{
 	  restart = FALSE;
 	  f.dbi.ObjectName.Buffer[f.dbi.ObjectName.Length / sizeof (WCHAR)] = L'\0';
-	  if (wcsncmp (f.dbi.ObjectName.Buffer, L"cygpid.", 7) == 0)
+	  if (wcsncmp (f.dbi.ObjectName.Buffer, L"winpid.", 7) == 0)
 	    {
 	    DWORD pid = wcstoul (f.dbi.ObjectName.Buffer + 7, NULL, 10);
 	    add (nelem, false, pid);
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index c4881c7..81e10d3 100644
--- a/winsup/cygwin/pinfo.h
+++ b/winsup/cygwin/pinfo.h
@@ -53,8 +53,6 @@ public:
 
   DWORD exitcode;	/* set when process exits */
 
-#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->exitcode - (char *) myself.procinfo)
-
   /* > 0 if started by a cygwin process */
   DWORD cygstarted;
 
@@ -147,22 +145,25 @@ public:
 class pinfo: public pinfo_minimal
 {
   bool destroy;
+  HANDLE winpid_hdl;
   _pinfo *procinfo;
 public:
   bool waiter_ready;
   class cygthread *wait_thread;
 
   void __reg3 init (pid_t, DWORD, HANDLE);
-  pinfo (_pinfo *x = NULL): pinfo_minimal (), destroy (false), procinfo (x),
-		     waiter_ready (false), wait_thread (NULL) {}
-  pinfo (pid_t n, DWORD flag = 0): pinfo_minimal (), destroy (false),
-				   procinfo (NULL), waiter_ready (false),
-				   wait_thread (NULL)
+  pinfo (_pinfo *x = NULL)
+  : pinfo_minimal (), destroy (false), winpid_hdl (NULL), procinfo (x),
+    waiter_ready (false), wait_thread (NULL) {}
+  pinfo (pid_t n, DWORD flag = 0)
+  : pinfo_minimal (), destroy (false), winpid_hdl (NULL), procinfo (NULL),
+    waiter_ready (false), wait_thread (NULL)
   {
     init (n, flag, NULL);
   }
   pinfo (HANDLE, pinfo_minimal&, pid_t);
   void __reg2 thisproc (HANDLE);
+  void create_winpid_symlink (pid_t, DWORD);
   inline void _pinfo_release ();
   void release ();
   bool __reg1 wait ();
@@ -239,11 +240,8 @@ public:
   void release ();
 };
 
-extern __inline pid_t
-cygwin_pid (pid_t pid)
-{
-  return pid;
-}
+pid_t create_cygwin_pid ();
+pid_t cygwin_pid (DWORD);
 
 void __stdcall pinfo_init (char **, int);
 extern pinfo myself;
diff --git a/winsup/cygwin/release/3.0 b/winsup/cygwin/release/3.0
index f4433c3..907405a 100644
--- a/winsup/cygwin/release/3.0
+++ b/winsup/cygwin/release/3.0
@@ -61,6 +61,9 @@ What changed:
 - Kerberos/MSV1_0 S4U authentication replaces two old methods:
   Creating a token from scratch and Cygwin LSA authentication package.
 
+- Cygwin PIDs have been decoupled from Windows PID.  Cygwin PIDs are
+  now incrementally dealt in the range from 2 up to 65535, POSIX-like.
+
 
 Bug Fixes
 ---------
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index dd16f14..e87f2f9 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -323,12 +323,17 @@ shared_info::initialize ()
   spinlock sversion (version, CURR_SHARED_MAGIC);
   if (!sversion)
     {
+      LUID luid;
+
       cb = sizeof (*this);
       get_session_parent_dir ();	/* Create session dir if first process. */
       init_obcaseinsensitive ();	/* Initialize obcaseinsensitive */
       tty.init ();			/* Initialize tty table  */
       mt.initialize ();			/* Initialize shared tape information */
       loadavg.initialize ();		/* Initialize loadavg information */
+      NtAllocateLocallyUniqueId (&luid);/* Initialize pid_src to a low    */
+      InterlockedExchange (&pid_src,	/* random value to make start pid */
+		   luid.LowPart % 2048);/* less predictably               */
       /* Defer debug output printing the installation root and installation key
 	 up to this point.  Debug output except for system_printf requires
 	 the global shared memory to exist. */
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index f331a3a..1a5648b 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -33,7 +33,7 @@ public:
 /* Data accessible to all tasks */
 
 
-#define CURR_SHARED_MAGIC 0x9b1c0f25U
+#define CURR_SHARED_MAGIC 0x6758de88U
 
 #define USER_VERSION   1
 
@@ -50,6 +50,7 @@ class shared_info
   DWORD obcaseinsensitive;
   mtinfo mt;
   loadavginfo loadavg;
+  LONG pid_src;
 
   void initialize ();
   void init_obcaseinsensitive ();
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 37db526..58e2696 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -709,7 +709,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
 	::cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
 
       if (mode != _P_OVERLAY)
-	cygpid = cygwin_pid (pi.dwProcessId);
+	cygpid = create_cygwin_pid ();
       else
 	cygpid = myself->pid;
 
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index d620d1c..4bbf5fb 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -100,6 +100,11 @@ Kerberos/MSV1_0 S4U authentication replaces two old methods:
 Creating a token from scratch and Cygwin LSA authentication package.
 </para></listitem>
 
+<listitem><para>
+Cygwin PIDs have been decoupled from Windows PID.  Cygwin PIDs are now
+incrementally dealt in the range from 2 up to 65535, POSIX-like.
+</para></listitem>
+
 </itemizedlist>
 
 </sect2>


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-02-01 19:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-01 19:07 [newlib-cygwin] Cygwin: processes: use dedicated Cygwin PID rather than Windows PID Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).