1 /* pinfo.cc: process table support
3 Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 #include "miscfuncs.h"
22 #include "perprocess.h"
26 #include "shared_info.h"
28 #include "cygmalloc.h"
31 #include "child_info.h"
33 class pinfo_basic: public _pinfo
39 pinfo_basic::pinfo_basic()
41 pid = dwProcessId = GetCurrentProcessId ();
42 GetModuleFileNameW (NULL, progname, sizeof (progname));
45 pinfo_basic myself_initial NO_COPY;
47 pinfo NO_COPY myself (static_cast<_pinfo *> (&myself_initial)); // Avoid myself != NULL checks
49 bool is_toplevel_proc;
51 /* Setup the pinfo structure for this process. There may already be a
52 _pinfo for this "pid" if h != NULL. */
55 pinfo::thisproc (HANDLE h)
60 cygheap->pid = cygwin_pid (myself_initial.pid);
62 init (cygheap->pid, PID_IN_USE, h ?: INVALID_HANDLE_VALUE);
63 procinfo->process_state |= PID_IN_USE;
64 procinfo->dwProcessId = myself_initial.pid;
65 procinfo->sendsig = myself_initial.sendsig;
66 wcscpy (procinfo->progname, myself_initial.progname);
67 debug_printf ("myself dwProcessId %u", procinfo->dwProcessId);
71 static pinfo NO_COPY myself_identity;
72 myself_identity.init (cygwin_pid (procinfo->dwProcessId), PID_EXECED, NULL);
73 procinfo->exec_sendsig = NULL;
74 procinfo->exec_dwProcessId = 0;
76 else if (!child_proc_info) /* child_proc_info is only set when this process
77 was started by another cygwin process */
78 procinfo->start_time = time (NULL); /* Register our starting time. */
79 else if (::cygheap->pid_handle)
81 ForceCloseHandle (::cygheap->pid_handle);
82 ::cygheap->pid_handle = NULL;
86 /* Initialize the process table entry for the current task.
87 This is not called for forked tasks, only execed ones. */
89 pinfo_init (char **envp, int envc)
93 environ_init (envp, envc);
94 /* spawn has already set up a pid structure for us so we'll use that */
95 myself->process_state |= PID_CYGPARENT;
99 /* Invent our own pid. */
101 myself.thisproc (NULL);
103 myself->pgid = myself->sid = myself->pid;
105 myself->uid = ILLEGAL_UID;
106 myself->gid = UNKNOWN_GID;
107 environ_init (NULL, 0); /* call after myself has been set up */
108 myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
109 debug_printf ("Set nice to %d", myself->nice);
112 myself->process_state |= PID_ACTIVE;
113 myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED);
114 debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid);
118 status_exit (DWORD x)
120 const char *find_first_notloaded_dll (path_conv &);
123 case STATUS_DLL_NOT_FOUND:
125 char posix_prog[NT_MAX_PATH];
127 RtlInitUnicodeString(&uc, myself->progname);
128 path_conv pc (&uc, PC_NOWARN);
129 mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1);
130 small_printf ("%s: error while loading shared libraries: %s: cannot open shared object file: No such file or directory\n",
131 posix_prog, find_first_notloaded_dll (pc));
135 case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* custom error value */
136 /* We've already printed the error message in pseudo-reloc.c */
139 case STATUS_ACCESS_VIOLATION:
142 case STATUS_ILLEGAL_INSTRUCTION:
146 debug_printf ("*** STATUS_%p\n", x);
149 return EXITCODE_SET | x;
152 # define self (*this)
154 pinfo::set_exit_code (DWORD x)
156 if (x >= 0xc0000000UL)
157 self->exitcode = status_exit (x);
159 self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
163 pinfo::maybe_set_exit_code_from_windows ()
165 DWORD x = 0xdeadbeef;
166 DWORD oexitcode = self->exitcode;
168 if (hProcess && !(self->exitcode & EXITCODE_SET))
170 WaitForSingleObject (hProcess, INFINITE); /* just to be safe, in case
171 process hasn't quite exited
172 after closing pipe */
173 GetExitCodeProcess (hProcess, &x);
176 sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p",
177 self->pid, oexitcode, x, self->exitcode);
181 pinfo::exit (DWORD n)
183 minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
184 sigproc_terminate (ES_FINAL);
185 lock_process until_exit (true);
186 cygthread::terminate ();
188 if (n != EXITCODE_NOSET)
189 self->exitcode = EXITCODE_SET | n;/* We're really exiting. Record the UNIX exit code. */
192 exit_state = ES_EXEC_EXIT;
193 maybe_set_exit_code_from_windows ();
196 if (myself->ctty > 0 && !iscons_dev (myself->ctty))
199 tty *t = cygwin_shared->tty[device::minor(myself->ctty)];
200 if (!t->slave_alive ())
204 /* FIXME: There is a potential race between an execed process and its
205 parent here. I hated to add a mutex just for that, though. */
207 fill_rusage (&r, GetCurrentProcess ());
208 add_rusage (&self->rusage_self, &r);
209 int exitcode = self->exitcode & 0xffff;
210 if (!self->cygstarted)
211 exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff);
212 sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode);
213 if (!TerminateProcess (GetCurrentProcess (), exitcode))
214 system_printf ("TerminateProcess failed, %E");
215 ExitProcess (exitcode);
220 pinfo::_pinfo_release ()
224 void *unmap_procinfo = procinfo;
226 UnmapViewOfFile (unmap_procinfo);
233 ForceCloseHandle1 (close_h, pinfo_shared_handle);
238 pinfo::init (pid_t n, DWORD flag, HANDLE h0)
240 shared_locations shloc;
242 if (myself && !(flag & PID_EXECED)
243 && (n == myself->pid || (DWORD) n == myself->dwProcessId))
251 int createit = flag & (PID_IN_USE | PID_EXECED);
252 DWORD access = FILE_MAP_READ
253 | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW)
254 ? FILE_MAP_WRITE : 0);
256 shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN;
260 if (h0 == INVALID_HANDLE_VALUE)
265 PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
266 PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, cygheap->user.sid(),
267 well_known_world_sid,
270 for (int i = 0; i < 20; i++)
273 if (flag & PID_EXECED)
274 mapsize = PINFO_REDIR_SIZE;
276 mapsize = sizeof (_pinfo);
278 procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, mapsize, &shloc,
279 sec_attribs, access);
292 switch (GetLastError ())
294 case ERROR_INVALID_HANDLE:
295 api_fatal ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
296 case ERROR_INVALID_ADDRESS:
299 debug_printf ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
304 bool created = shloc != SH_JUSTOPEN;
306 if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
307 && cygwin_pid (procinfo->dwProcessId) != procinfo->pid)
313 if (procinfo->process_state & PID_EXECED)
316 pid_t realpid = procinfo->pid;
317 debug_printf ("execed process windows pid %d, cygwin pid %d", n, realpid);
319 api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
327 /* In certain pathological cases, it is possible for the shared memory
328 region to exist for a while after a process has exited. This should
329 only be a brief occurrence, so rather than introduce some kind of
330 locking mechanism, just loop. */
331 if (!created && createit && (procinfo->process_state & (PID_EXITED | PID_REAPED)))
333 debug_printf ("looping because pid %d, procinfo->pid %d, "
334 "procinfo->dwProcessid %u has PID_EXITED|PID_REAPED set",
335 n, procinfo->pid, procinfo->dwProcessId);
341 else if (!(flag & PID_EXECED))
345 procinfo->process_state |= PID_IN_USE | PID_EXECED;
346 procinfo->pid = myself->pid;
349 h = h0; /* Success! */
361 ProtectHandle1 (h, pinfo_shared_handle);
373 PACL acl_buf = (PACL) alloca (1024);
374 SECURITY_DESCRIPTOR sd;
377 sec_acl (acl_buf, true, true, cygheap->user.sid (),
378 well_known_world_sid, FILE_MAP_READ);
379 RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
380 status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl_buf, FALSE);
381 if (!NT_SUCCESS (status))
382 debug_printf ("RtlSetDaclSecurityDescriptor %p", status);
383 else if ((status = NtSetSecurityObject (h, DACL_SECURITY_INFORMATION, &sd)))
384 debug_printf ("NtSetSecurityObject %p", status);
387 pinfo::pinfo (HANDLE parent, pinfo_minimal& from, pid_t pid):
388 pinfo_minimal (), destroy (false), procinfo (NULL), waiter_ready (false),
392 const char *duperr = NULL;
393 if (!DuplicateHandle (parent, herr = from.rd_proc_pipe, GetCurrentProcess (),
394 &rd_proc_pipe, 0, false, DUPLICATE_SAME_ACCESS))
395 duperr = "couldn't duplicate parent rd_proc_pipe handle %p for forked child %d after exec, %E";
396 else if (!DuplicateHandle (parent, herr = from.hProcess, GetCurrentProcess (),
397 &hProcess, 0, false, DUPLICATE_SAME_ACCESS))
398 duperr = "couldn't duplicate parent process handle %p for forked child %d after exec, %E";
402 DuplicateHandle (parent, from.h, GetCurrentProcess (), &h, 0, false,
403 DUPLICATE_SAME_ACCESS);
404 init (pid, PID_MAP_RW, h);
410 debug_printf (duperr, herr, pid);
412 /* Returning with procinfo == NULL. Any open handles will be closed by the
417 _pinfo::_ctty (char *buf)
420 strcpy (buf, "no ctty");
425 __small_sprintf (buf, "ctty %s", d.name);
431 _pinfo::set_ctty (fhandler_termios *fh, int flags)
433 debug_printf ("fh %p", fh);
434 debug_printf ("tc %p", fh->tc ());
435 if (!this || !fh->tc ()) try_to_debug ();
436 tty_min& tc = *fh->tc ();
437 debug_printf ("old %s, ctty device number %p, tc.ntty device number %p flags & O_NOCTTY %p", __ctty (), ctty, tc.ntty, flags & O_NOCTTY);
438 if (fh && &tc && (ctty <= 0 || ctty == tc.ntty) && !(flags & O_NOCTTY))
441 if (cygheap->ctty != fh->archetype)
443 debug_printf ("cygheap->ctty %p, archetype %p", cygheap->ctty, fh->archetype);
445 syscall_printf ("ctty was NULL");
448 syscall_printf ("ctty %p, usecount %d", cygheap->ctty,
449 cygheap->ctty->archetype_usecount (0));
450 cygheap->ctty->close ();
452 cygheap->ctty = (fhandler_termios *) fh->archetype;
455 fh->archetype_usecount (1);
457 cygheap->manage_console_count ("_pinfo::set_ctty", 1);
458 report_tty_counts (cygheap->ctty, "ctty", "");
463 syscall_printf ("attaching %s sid %d, pid %d, pgid %d, tty->pgid %d, tty->sid %d",
464 __ctty (), sid, pid, pgid, tc.getpgid (), tc.getsid ());
465 if (!cygwin_finished_initializing && !myself->cygstarted
466 && myself->pgid == myself->pid && tc.getpgid () && tc.getsid ())
468 myself->pgid = tc.getpgid ();
469 myself->sid = tc.getsid ();
472 pinfo p (tc.getsid ());
473 if (sid == pid && (!p || p->pid == pid || !p->exists ()))
476 debug_printf ("resetting %s sid. Was %d, now %d. pgid was %d, now %d.",
477 __ctty (), tc.getsid (), sid, tc.getpgid (), pgid);
479 paranoid_printf ("resetting %s sid. Was %d, now %d. pgid was %d, now %d.",
480 __ctty (), tc.getsid (), sid, tc.getpgid (), pgid);
482 /* We are the session leader */
488 if (tc.getpgid () == 0)
491 debug_printf ("cygheap->ctty now %p, archetype %p", cygheap->ctty, fh->archetype);
495 /* Test to determine if a process really exists and is processing signals.
500 return this && !(process_state & (PID_EXITED | PID_REAPED));
506 HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, false, dwProcessId);
513 commune_process (void *arg)
515 siginfo_t& si = *((siginfo_t *) arg);
517 char *path = tp.c_get ();
519 HANDLE& tothem = si._si_commune._si_write_handle;
520 HANDLE process_sync =
521 OpenSemaphore (SYNCHRONIZE, false, shared_name (path, "commune", si.si_pid));
522 if (process_sync) // FIXME: this test shouldn't be necessary
523 ProtectHandle (process_sync);
526 if (si._si_commune._si_code & PICOM_EXTRASTR)
527 si._si_commune._si_str = (char *) (&si + 1);
529 switch (si._si_commune._si_code)
533 sigproc_printf ("processing PICOM_CMDLINE");
535 const char *argv[__argc_safe + 1];
537 for (int i = 0; i < __argc_safe; i++)
539 if (IsBadStringPtr (__argv[i], INT32_MAX))
543 n += strlen (argv[i]) + 1;
545 argv[__argc_safe] = NULL;
546 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
548 /*__seterrno ();*/ // this is run from the signal thread, so don't set errno
549 sigproc_printf ("WritePipeOverlapped sizeof argv failed, %E");
552 for (const char **a = argv; *a; a++)
553 if (!WritePipeOverlapped (tothem, *a, strlen (*a) + 1, &nr, 1000L))
555 sigproc_printf ("WritePipeOverlapped arg %d failed, %E",
563 sigproc_printf ("processing PICOM_CWD");
564 unsigned int n = strlen (cygheap->cwd.get (path, 1, 1, NT_MAX_PATH)) + 1;
565 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
566 sigproc_printf ("WritePipeOverlapped sizeof cwd failed, %E");
567 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
568 sigproc_printf ("WritePipeOverlapped cwd failed, %E");
573 sigproc_printf ("processing PICOM_ROOT");
575 if (cygheap->root.exists ())
576 n = strlen (strcpy (path, cygheap->root.posix_path ())) + 1;
578 n = strlen (strcpy (path, "/")) + 1;
579 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
580 sigproc_printf ("WritePipeOverlapped sizeof root failed, %E");
581 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
582 sigproc_printf ("WritePipeOverlapped root failed, %E");
587 sigproc_printf ("processing PICOM_FDS");
591 while ((fd = cfd.next ()) >= 0)
594 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
595 sigproc_printf ("WritePipeOverlapped sizeof fds failed, %E");
597 while ((fd = cfd.next ()) >= 0)
598 if (!WritePipeOverlapped (tothem, &fd, sizeof fd, &nr, 1000L))
600 sigproc_printf ("WritePipeOverlapped fd %d failed, %E", fd);
605 case PICOM_PIPE_FHANDLER:
607 sigproc_printf ("processing PICOM_FDS");
608 HANDLE hdl = si._si_commune._si_pipe_fhandler;
611 while (cfd.next () >= 0)
612 if (cfd->get_handle () == hdl)
614 fhandler_pipe *fh = cfd;
616 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
617 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
618 else if (!WritePipeOverlapped (tothem, fh, n, &nr, 1000L))
619 sigproc_printf ("WritePipeOverlapped hdl failed, %E");
622 if (!n && !WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
623 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
628 sigproc_printf ("processing PICOM_FD");
629 int fd = si._si_commune._si_fd;
631 cygheap_fdget cfd (fd);
633 n = strlen (strcpy (path, "")) + 1;
635 n = strlen (cfd->get_proc_fd_name (path)) + 1;
636 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
637 sigproc_printf ("WritePipeOverlapped sizeof fd failed, %E");
638 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
639 sigproc_printf ("WritePipeOverlapped fd failed, %E");
645 DWORD res = WaitForSingleObject (process_sync, 5000);
646 if (res != WAIT_OBJECT_0)
647 sigproc_printf ("WFSO failed - %d, %E", res);
649 sigproc_printf ("synchronized with pid %d", si.si_pid);
650 ForceCloseHandle (process_sync);
652 CloseHandle (tothem);
653 _my_tls._ctinfo->auto_release ();
658 _pinfo::commune_request (__uint32_t code, ...)
664 HANDLE& hp = si._si_commune._si_process_handle;
665 HANDLE& fromthem = si._si_commune._si_read_handle;
666 HANDLE request_sync = NULL;
678 va_start (args, code);
679 si._si_commune._si_code = code;
682 case PICOM_PIPE_FHANDLER:
683 si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE);
687 si._si_commune._si_fd = va_arg (args, int);
695 char name_buf[MAX_PATH];
696 request_sync = CreateSemaphore (&sec_none_nih, 0, LONG_MAX,
697 shared_name (name_buf, "commune", myself->pid));
700 ProtectHandle (request_sync);
702 si.si_signo = __SIGCOMMUNE;
703 if (sig_send (this, si))
705 ForceCloseHandle (request_sync); /* don't signal semaphore since there was apparently no receiving process */
718 case PICOM_PIPE_FHANDLER:
719 if (!ReadPipeOverlapped (fromthem, &n, sizeof n, &nr, 500L)
729 res.s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
732 n && ReadPipeOverlapped (fromthem, p, n, &nr, 500L);
747 memset (&res, 0, sizeof (res));
753 ReleaseSemaphore (request_sync, 1, &res);
754 ForceCloseHandle (request_sync);
759 CloseHandle (fromthem);
764 _pinfo::pipe_fhandler (HANDLE hdl, size_t &n)
768 if (pid == myself->pid)
770 commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl);
772 return (fhandler_pipe *) cr.s;
776 _pinfo::fd (int fd, size_t &n)
781 if (pid != myself->pid)
783 commune_result cr = commune_request (PICOM_FD, fd);
789 cygheap_fdget cfd (fd);
793 s = cfd->get_proc_fd_name ((char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH));
800 _pinfo::fds (size_t &n)
805 if (pid != myself->pid)
807 commune_result cr = commune_request (PICOM_FDS);
815 cygheap_fdenum cfd (true);
816 while ((fd = cfd.next ()) >= 0)
819 s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
821 while ((fd = cfd.next ()) >= 0 && (char *) p - s < (int) n)
828 _pinfo::root (size_t& n)
833 if (pid != myself->pid)
835 commune_result cr = commune_request (PICOM_ROOT);
841 if (cygheap->root.exists ())
842 s = cstrdup (cygheap->root.posix_path ());
851 _pinfo::cwd (size_t& n)
856 if (pid != myself->pid)
858 commune_result cr = commune_request (PICOM_CWD);
864 s = (char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH);
865 cygheap->cwd.get (s, 1, 1, NT_MAX_PATH);
872 _pinfo::cmdline (size_t& n)
877 if (pid != myself->pid)
879 commune_result cr = commune_request (PICOM_CMDLINE);
886 for (char **a = __argv; *a; a++)
887 n += strlen (*a) + 1;
889 p = s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
890 for (char **a = __argv; *a; a++)
893 p = strchr (p, '\0') + 1;
899 /* This is the workhorse which waits for the write end of the pipe
900 created during new process creation. If the pipe is closed or a zero
901 is received on the pipe, it is assumed that the cygwin pid has exited.
902 Otherwise, various "signals" can be sent to the parent to inform the
903 parent to perform a certain action. */
905 proc_waiter (void *arg)
907 pinfo vchild = *(pinfo *) arg;
908 ((pinfo *) arg)->waiter_ready = true;
911 si.si_signo = SIGCHLD;
912 si.si_code = CLD_EXITED;
913 si.si_pid = vchild->pid;
914 #if 0 // FIXME: This is tricky to get right
915 si.si_utime = pchildren[rc]->rusage_self.ru_utime;
916 si.si_stime = pchildren[rc].rusage_self.ru_stime;
918 pid_t pid = vchild->pid;
919 bool its_me = vchild == myself;
926 if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
927 && GetLastError () != ERROR_BROKEN_PIPE)
929 system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
933 if (!its_me && have_execed_cygwin)
936 si.si_uid = vchild->uid;
943 /* Child exited. Do some cleanup and signal myself. */
944 vchild.maybe_set_exit_code_from_windows ();
945 if (WIFEXITED (vchild->exitcode))
946 si.si_code = CLD_EXITED;
947 else if (WCOREDUMP (vchild->exitcode))
948 si.si_code = CLD_DUMPED;
950 si.si_code = CLD_KILLED;
951 si.si_status = vchild->exitcode;
952 vchild->process_state = PID_EXITED;
953 /* This should always be last. Do not use vchild-> beyond this point */
959 if (ISSTATE (myself, PID_NOCLDSTOP)) // FIXME: No need for this flag to be in _pinfo any longer
961 /* Child stopped. Signal myself. */
962 si.si_code = CLD_STOPPED;
967 system_printf ("unknown value %d on proc pipe", buf);
971 if (its_me && ch_spawn.signal_myself_exited ())
974 /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
975 to avoid the proc_subproc lock since the signal thread will eventually
976 be calling proc_subproc and could unnecessarily block. */
977 sig_send (myself_nowait, si);
979 /* If we're just stopped or got a continue signal, keep looping.
980 Otherwise, return this thread to the pool. */
982 sigproc_printf ("looping");
987 sigproc_printf ("exiting wait thread for pid %d", pid);
988 vchild.wait_thread = NULL;
989 _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */
994 #define warn_printf api_fatal
996 #define warn_printf system_printf
999 _pinfo::dup_proc_pipe (HANDLE hProcess)
1001 DWORD flags = DUPLICATE_SAME_ACCESS;
1002 HANDLE orig_wr_proc_pipe = wr_proc_pipe;
1003 /* Can't set DUPLICATE_CLOSE_SOURCE for exec case because we could be
1004 execing a non-cygwin process and we need to set the exit value before the
1006 if (this != myself || is_toplevel_proc)
1007 flags |= DUPLICATE_CLOSE_SOURCE;
1008 bool res = DuplicateHandle (GetCurrentProcess (), wr_proc_pipe,
1009 hProcess, &wr_proc_pipe, 0, FALSE, flags);
1010 if (!res && WaitForSingleObject (hProcess, 0) != WAIT_OBJECT_0)
1012 wr_proc_pipe = orig_wr_proc_pipe;
1013 warn_printf ("something failed for pid %d: res %d, hProcess %p, wr_proc_pipe %p vs. %p, %E",
1014 res, pid, hProcess, wr_proc_pipe, orig_wr_proc_pipe);
1018 wr_proc_pipe_owner = dwProcessId;
1019 sigproc_printf ("duped wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
1022 return orig_wr_proc_pipe;
1025 /* function to set up the process pipe and kick off proc_waiter */
1029 /* If rd_proc_pipe != NULL we're in an execed process which already has
1030 grabbed the read end of the pipe from the previous cygwin process running
1034 /* FIXME: execed processes should be able to wait for pids that were started
1035 by the process which execed them. */
1036 if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
1038 system_printf ("Couldn't create pipe tracker for pid %d, %E",
1043 if (!(*this)->dup_proc_pipe (hProcess))
1045 system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
1050 preserve (); /* Preserve the shared memory associated with the pinfo */
1052 waiter_ready = false;
1053 /* Fire up a new thread to track the subprocess */
1054 cygthread *h = new cygthread (proc_waiter, this, "waitproc");
1056 sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
1060 sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_proc_pipe %p",
1061 (*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
1068 _pinfo::sync_proc_pipe ()
1070 if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
1071 while (wr_proc_pipe_owner != GetCurrentProcessId ())
1075 /* function to send a "signal" to the parent when something interesting happens
1078 _pinfo::alert_parent (char sig)
1082 /* Send something to our parent. If the parent has gone away, close the pipe.
1083 Don't send if this is an exec stub.
1085 FIXME: Is there a race here if we run this while another thread is attempting
1087 if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || have_execed)
1092 if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
1094 else if (GetLastError () != ERROR_BROKEN_PIPE)
1095 debug_printf ("sending %d notification to parent failed, %E", sig);
1099 HANDLE closeit = wr_proc_pipe;
1100 wr_proc_pipe = INVALID_HANDLE_VALUE;
1101 CloseHandle (closeit);
1114 close_h = rd_proc_pipe;
1115 rd_proc_pipe = NULL;
1116 ForceCloseHandle1 (close_h, rd_proc_pipe);
1122 ForceCloseHandle1 (close_h, childhProc);
1128 <sect1 id="func-cygwin-winpid-to-pid">
1129 <title>cygwin_winpid_to_pid</title>
1131 <funcsynopsis><funcprototype>
1132 <funcdef>extern "C" pid_t
1133 <function>cygwin_winpid_to_pid</function>
1135 <paramdef>int <parameter>winpid</parameter></paramdef>
1136 </funcprototype></funcsynopsis>
1138 <para>Given a windows pid, converts to the corresponding Cygwin
1139 pid, if any. Returns -1 if windows pid does not correspond to
1140 a cygwin pid.</para>
1142 <title>Example use of cygwin_winpid_to_pid</title>
1144 extern "C" cygwin_winpid_to_pid (int winpid);
1146 mypid = cygwin_winpid_to_pid (windows_pid);
1154 cygwin_winpid_to_pid (int winpid)
1156 pinfo p (cygwin_pid (winpid));
1165 #define slop_pidlist 200
1166 #define size_pidlist(i) (sizeof (pidlist[0]) * ((i) + 1))
1167 #define size_pinfolist(i) (sizeof (pinfolist[0]) * ((i) + 1))
1181 void no_close_p_handle () {h = NULL;}
1182 _onreturn (HANDLE& _h): h (&_h) {}
1186 winpids::add (DWORD& nelem, bool winpid, DWORD pid)
1188 pid_t cygpid = cygwin_pid (pid);
1190 if (nelem >= npidlist)
1192 npidlist += slop_pidlist;
1193 pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist + 1));
1194 pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist + 1));
1197 pinfo& p = pinfolist[nelem];
1198 memset (&p, 0, sizeof (p));
1200 /* Open a process to prevent a subsequent exit from invalidating the
1201 shared memory region. */
1202 p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, pid);
1203 _onreturn onreturn (p.hProcess);
1205 /* If we couldn't open the process then we don't have rights to it and should
1206 make a copy of the shared memory area if it exists (it may not). */
1209 perform_copy = true;
1211 perform_copy = make_copy;
1213 p.init (cygpid, PID_NOREDIR | pinfo_access, NULL);
1215 /* If we're just looking for winpids then don't do any special cygwin "stuff* */
1219 /* !p means that we couldn't find shared memory for this pid. Probably means
1220 that it isn't a cygwin process. */
1225 p.init (cygpid, PID_NOREDIR, NULL);
1230 /* Scan list of previously recorded pids to make sure that this pid hasn't
1231 shown up before. This can happen when a process execs. */
1232 for (unsigned i = 0; i < nelem; i++)
1233 if (pinfolist[i]->pid == p->pid)
1235 if ((_pinfo *) p != (_pinfo *) myself)
1243 If p is "false" then, eventually any opened process handle will be closed and
1244 the function will exit without adding anything to the pid list.
1246 If p is "true" then we've discovered a cygwin process.
1248 Handle "myself" differently. Don't copy it and close/zero the handle we
1250 If not performing a copy, then keep the process handle open for the duration
1251 of the life of the procinfo region to potential races when a new process uses
1253 Otherwise, malloc some memory for a copy of the shared memory.
1255 If the malloc failed, then "oh well". Just keep the shared memory around
1256 and eventually close the handle when the winpids goes out of scope.
1258 If malloc succeeds, copy the procinfo we just grabbed into the new region,
1259 release the shared memory and allow the handle to be closed when this
1262 Oh, and add the pid to the list and bump the number of elements. */
1266 if (p == (_pinfo *) myself)
1267 /* handle specially. Close the handle but (eventually) don't
1268 deallocate procinfo in release call */;
1269 else if (!perform_copy)
1270 onreturn.no_close_p_handle (); /* Don't close the handle until release */
1273 _pinfo *pnew = (_pinfo *) malloc (sizeof (*p.procinfo));
1275 onreturn.no_close_p_handle ();
1278 *pnew = *p.procinfo;
1286 pidlist[nelem++] = !p ? pid : p->dwProcessId;
1290 winpids::enum_processes (bool winpid)
1293 DWORD cygwin_pid_nelem = 0;
1298 DIRECTORY_BASIC_INFORMATION dbi;
1299 WCHAR buf[2][NAME_MAX + 1];
1301 HANDLE dir = get_shared_parent_dir ();
1302 BOOLEAN restart = TRUE;
1306 status = NtQueryDirectoryObject (dir, &f, sizeof f, TRUE, restart,
1308 if (NT_SUCCESS (status))
1311 f.dbi.ObjectName.Buffer[f.dbi.ObjectName.Length / sizeof (WCHAR)]
1313 if (wcsncmp (f.dbi.ObjectName.Buffer, L"cygpid.", 7) == 0)
1315 DWORD pid = wcstoul (f.dbi.ObjectName.Buffer + 7, NULL, 10);
1316 add (nelem, false, pid);
1320 while (NT_SUCCESS (status));
1321 cygwin_pid_nelem = nelem;
1325 static DWORD szprocs;
1326 static SYSTEM_PROCESSES *procs;
1329 procs = (SYSTEM_PROCESSES *) malloc (sizeof (*procs) + (szprocs = 200 * sizeof (*procs)));
1334 res = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
1335 procs, szprocs, NULL);
1339 if (res == STATUS_INFO_LENGTH_MISMATCH)
1340 procs = (SYSTEM_PROCESSES *) realloc (procs, szprocs += 200 * sizeof (*procs));
1343 system_printf ("error %p reading system process information", res);
1348 SYSTEM_PROCESSES *px = procs;
1354 for (unsigned i = 0; i < cygwin_pid_nelem; ++i)
1355 if (pidlist[i] == px->ProcessId)
1361 add (nelem, true, px->ProcessId);
1363 if (!px->NextEntryDelta)
1365 px = (SYSTEM_PROCESSES *) ((char *) px + px->NextEntryDelta);
1373 winpids::set (bool winpid)
1376 npids = enum_processes (winpid);
1383 winpids::enum_init (bool winpid)
1385 return enum_processes (winpid);
1392 for (unsigned i = 0; i < npids; i++)
1393 if (pinfolist[i] == (_pinfo *) myself)
1395 else if (pinfolist[i].hProcess)
1396 pinfolist[i].release ();
1397 else if ((p = pinfolist[i]))
1399 pinfolist[i].procinfo = NULL;
1404 winpids::~winpids ()