1 /* pinfo.cc: process table support
3 Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011, 2012 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));
43 /* Default uid/gid are needed very early to initialize shared user info. */
48 pinfo_basic myself_initial NO_COPY;
50 pinfo NO_COPY myself (static_cast<_pinfo *> (&myself_initial)); // Avoid myself != NULL checks
52 bool is_toplevel_proc;
54 /* Setup the pinfo structure for this process. There may already be a
55 _pinfo for this "pid" if h != NULL. */
58 pinfo::thisproc (HANDLE h)
63 cygheap->pid = cygwin_pid (myself_initial.pid);
65 init (cygheap->pid, PID_IN_USE, h ?: INVALID_HANDLE_VALUE);
66 procinfo->process_state |= PID_IN_USE;
67 procinfo->dwProcessId = myself_initial.pid;
68 procinfo->sendsig = myself_initial.sendsig;
69 wcscpy (procinfo->progname, myself_initial.progname);
70 debug_printf ("myself dwProcessId %u", procinfo->dwProcessId);
74 static pinfo NO_COPY myself_identity;
75 myself_identity.init (cygwin_pid (procinfo->dwProcessId), PID_EXECED, NULL);
76 procinfo->exec_sendsig = NULL;
77 procinfo->exec_dwProcessId = 0;
79 else if (!child_proc_info) /* child_proc_info is only set when this process
80 was started by another cygwin process */
81 procinfo->start_time = time (NULL); /* Register our starting time. */
82 else if (::cygheap->pid_handle)
84 ForceCloseHandle (::cygheap->pid_handle);
85 ::cygheap->pid_handle = NULL;
89 /* Initialize the process table entry for the current task.
90 This is not called for forked tasks, only execed ones. */
92 pinfo_init (char **envp, int envc)
96 environ_init (envp, envc);
97 /* spawn has already set up a pid structure for us so we'll use that */
98 myself->process_state |= PID_CYGPARENT;
102 /* Invent our own pid. */
104 myself.thisproc (NULL);
106 myself->pgid = myself->sid = myself->pid;
108 myself->uid = ILLEGAL_UID;
109 myself->gid = UNKNOWN_GID;
110 environ_init (NULL, 0); /* call after myself has been set up */
111 myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
112 debug_printf ("Set nice to %d", myself->nice);
115 myself->process_state |= PID_ACTIVE;
116 myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED);
117 debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid);
121 status_exit (DWORD x)
123 const char *find_first_notloaded_dll (path_conv &);
126 case STATUS_DLL_NOT_FOUND:
128 char posix_prog[NT_MAX_PATH];
130 RtlInitUnicodeString(&uc, myself->progname);
131 path_conv pc (&uc, PC_NOWARN);
132 mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1);
133 small_printf ("%s: error while loading shared libraries: %s: cannot open shared object file: No such file or directory\n",
134 posix_prog, find_first_notloaded_dll (pc));
138 case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* custom error value */
139 /* We've already printed the error message in pseudo-reloc.c */
142 case STATUS_ACCESS_VIOLATION:
145 case STATUS_ILLEGAL_INSTRUCTION:
149 debug_printf ("*** STATUS_%p\n", x);
152 return EXITCODE_SET | x;
155 # define self (*this)
157 pinfo::set_exit_code (DWORD x)
159 if (x >= 0xc0000000UL)
160 self->exitcode = status_exit (x);
162 self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
166 pinfo::maybe_set_exit_code_from_windows ()
168 DWORD x = 0xdeadbeef;
169 DWORD oexitcode = self->exitcode;
171 if (hProcess && !(self->exitcode & EXITCODE_SET))
173 WaitForSingleObject (hProcess, INFINITE); /* just to be safe, in case
174 process hasn't quite exited
175 after closing pipe */
176 GetExitCodeProcess (hProcess, &x);
179 sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p",
180 self->pid, oexitcode, x, self->exitcode);
184 pinfo::exit (DWORD n)
186 minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
187 sigproc_terminate (ES_FINAL);
188 lock_process until_exit (true);
189 cygthread::terminate ();
191 if (n != EXITCODE_NOSET)
192 self->exitcode = EXITCODE_SET | n;/* We're really exiting. Record the UNIX exit code. */
195 exit_state = ES_EXEC_EXIT;
196 maybe_set_exit_code_from_windows ();
199 if (myself->ctty > 0 && !iscons_dev (myself->ctty))
202 tty *t = cygwin_shared->tty[device::minor(myself->ctty)];
203 if (!t->slave_alive ())
207 /* FIXME: There is a potential race between an execed process and its
208 parent here. I hated to add a mutex just for that, though. */
210 fill_rusage (&r, GetCurrentProcess ());
211 add_rusage (&self->rusage_self, &r);
212 int exitcode = self->exitcode & 0xffff;
213 if (!self->cygstarted)
214 exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff);
215 sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode);
216 if (!TerminateProcess (GetCurrentProcess (), exitcode))
217 system_printf ("TerminateProcess failed, %E");
218 ExitProcess (exitcode);
223 pinfo::_pinfo_release ()
227 void *unmap_procinfo = procinfo;
229 UnmapViewOfFile (unmap_procinfo);
236 ForceCloseHandle1 (close_h, pinfo_shared_handle);
241 pinfo::init (pid_t n, DWORD flag, HANDLE h0)
243 shared_locations shloc;
245 if (myself && !(flag & PID_EXECED)
246 && (n == myself->pid || (DWORD) n == myself->dwProcessId))
254 int createit = flag & (PID_IN_USE | PID_EXECED);
255 DWORD access = FILE_MAP_READ
256 | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW)
257 ? FILE_MAP_WRITE : 0);
259 shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN;
263 if (h0 == INVALID_HANDLE_VALUE)
268 PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
269 PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, cygheap->user.sid(),
270 well_known_world_sid,
273 for (int i = 0; i < 20; i++)
276 if (flag & PID_EXECED)
277 mapsize = PINFO_REDIR_SIZE;
279 mapsize = sizeof (_pinfo);
281 procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, mapsize, &shloc,
282 sec_attribs, access);
295 switch (GetLastError ())
297 case ERROR_INVALID_HANDLE:
298 api_fatal ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
299 case ERROR_INVALID_ADDRESS:
302 debug_printf ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
307 bool created = shloc != SH_JUSTOPEN;
309 if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
310 && cygwin_pid (procinfo->dwProcessId) != procinfo->pid)
316 if (procinfo->process_state & PID_EXECED)
319 pid_t realpid = procinfo->pid;
320 debug_printf ("execed process windows pid %d, cygwin pid %d", n, realpid);
322 api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
330 /* In certain pathological cases, it is possible for the shared memory
331 region to exist for a while after a process has exited. This should
332 only be a brief occurrence, so rather than introduce some kind of
333 locking mechanism, just loop. */
334 if (!created && createit && (procinfo->process_state & (PID_EXITED | PID_REAPED)))
336 debug_printf ("looping because pid %d, procinfo->pid %d, "
337 "procinfo->dwProcessid %u has PID_EXITED|PID_REAPED set",
338 n, procinfo->pid, procinfo->dwProcessId);
344 else if (!(flag & PID_EXECED))
348 procinfo->process_state |= PID_IN_USE | PID_EXECED;
349 procinfo->pid = myself->pid;
352 h = h0; /* Success! */
364 ProtectHandle1 (h, pinfo_shared_handle);
376 PACL acl_buf = (PACL) alloca (1024);
377 SECURITY_DESCRIPTOR sd;
380 sec_acl (acl_buf, true, true, cygheap->user.sid (),
381 well_known_world_sid, FILE_MAP_READ);
382 RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
383 status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl_buf, FALSE);
384 if (!NT_SUCCESS (status))
385 debug_printf ("RtlSetDaclSecurityDescriptor %p", status);
386 else if ((status = NtSetSecurityObject (h, DACL_SECURITY_INFORMATION, &sd)))
387 debug_printf ("NtSetSecurityObject %p", status);
390 pinfo::pinfo (HANDLE parent, pinfo_minimal& from, pid_t pid):
391 pinfo_minimal (), destroy (false), procinfo (NULL), waiter_ready (false),
395 const char *duperr = NULL;
396 if (!DuplicateHandle (parent, herr = from.rd_proc_pipe, GetCurrentProcess (),
397 &rd_proc_pipe, 0, false, DUPLICATE_SAME_ACCESS))
398 duperr = "couldn't duplicate parent rd_proc_pipe handle %p for forked child %d after exec, %E";
399 else if (!DuplicateHandle (parent, herr = from.hProcess, GetCurrentProcess (),
400 &hProcess, 0, false, DUPLICATE_SAME_ACCESS))
401 duperr = "couldn't duplicate parent process handle %p for forked child %d after exec, %E";
405 DuplicateHandle (parent, from.h, GetCurrentProcess (), &h, 0, false,
406 DUPLICATE_SAME_ACCESS);
407 init (pid, PID_MAP_RW, h);
413 debug_printf (duperr, herr, pid);
415 /* Returning with procinfo == NULL. Any open handles will be closed by the
420 _pinfo::_ctty (char *buf)
423 strcpy (buf, "no ctty");
428 __small_sprintf (buf, "ctty %s", d.name);
434 _pinfo::set_ctty (fhandler_termios *fh, int flags)
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 && pgid == pid && tc.getpgid () && tc.getsid ())
468 pgid = tc.getpgid ();
471 /* May actually need to do this:
473 if (sid == pid && !tc.getsid () || !procinfo (tc.getsid ())->exists)
475 but testing for process existence is expensive so we avoid it until
476 an obvious bug surfaces. */
477 if (sid == pid && !tc.getsid ())
481 if (!tc.getpgid () && pgid == pid)
484 debug_printf ("cygheap->ctty now %p, archetype %p", cygheap->ctty, fh->archetype);
488 /* Test to determine if a process really exists and is processing signals.
493 return this && !(process_state & (PID_EXITED | PID_REAPED));
499 HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, false, dwProcessId);
506 commune_process (void *arg)
508 siginfo_t& si = *((siginfo_t *) arg);
510 char *path = tp.c_get ();
512 HANDLE& tothem = si._si_commune._si_write_handle;
513 HANDLE process_sync =
514 OpenSemaphore (SYNCHRONIZE, false, shared_name (path, "commune", si.si_pid));
515 if (process_sync) // FIXME: this test shouldn't be necessary
516 ProtectHandle (process_sync);
519 if (si._si_commune._si_code & PICOM_EXTRASTR)
520 si._si_commune._si_str = (char *) (&si + 1);
522 switch (si._si_commune._si_code)
526 sigproc_printf ("processing PICOM_CMDLINE");
528 const char *argv[__argc_safe + 1];
530 for (int i = 0; i < __argc_safe; i++)
532 if (IsBadStringPtr (__argv[i], INT32_MAX))
536 n += strlen (argv[i]) + 1;
538 argv[__argc_safe] = NULL;
539 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
541 /*__seterrno ();*/ // this is run from the signal thread, so don't set errno
542 sigproc_printf ("WritePipeOverlapped sizeof argv failed, %E");
545 for (const char **a = argv; *a; a++)
546 if (!WritePipeOverlapped (tothem, *a, strlen (*a) + 1, &nr, 1000L))
548 sigproc_printf ("WritePipeOverlapped arg %d failed, %E",
556 sigproc_printf ("processing PICOM_CWD");
557 unsigned int n = strlen (cygheap->cwd.get (path, 1, 1, NT_MAX_PATH)) + 1;
558 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
559 sigproc_printf ("WritePipeOverlapped sizeof cwd failed, %E");
560 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
561 sigproc_printf ("WritePipeOverlapped cwd failed, %E");
566 sigproc_printf ("processing PICOM_ROOT");
568 if (cygheap->root.exists ())
569 n = strlen (strcpy (path, cygheap->root.posix_path ())) + 1;
571 n = strlen (strcpy (path, "/")) + 1;
572 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
573 sigproc_printf ("WritePipeOverlapped sizeof root failed, %E");
574 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
575 sigproc_printf ("WritePipeOverlapped root failed, %E");
580 sigproc_printf ("processing PICOM_FDS");
584 while ((fd = cfd.next ()) >= 0)
587 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
588 sigproc_printf ("WritePipeOverlapped sizeof fds failed, %E");
590 while ((fd = cfd.next ()) >= 0)
591 if (!WritePipeOverlapped (tothem, &fd, sizeof fd, &nr, 1000L))
593 sigproc_printf ("WritePipeOverlapped fd %d failed, %E", fd);
598 case PICOM_PIPE_FHANDLER:
600 sigproc_printf ("processing PICOM_FDS");
601 HANDLE hdl = si._si_commune._si_pipe_fhandler;
604 while (cfd.next () >= 0)
605 if (cfd->get_handle () == hdl)
607 fhandler_pipe *fh = cfd;
609 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
610 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
611 else if (!WritePipeOverlapped (tothem, fh, n, &nr, 1000L))
612 sigproc_printf ("WritePipeOverlapped hdl failed, %E");
615 if (!n && !WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
616 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
621 sigproc_printf ("processing PICOM_FD");
622 int fd = si._si_commune._si_fd;
624 cygheap_fdget cfd (fd);
626 n = strlen (strcpy (path, "")) + 1;
628 n = strlen (cfd->get_proc_fd_name (path)) + 1;
629 if (!WritePipeOverlapped (tothem, &n, sizeof n, &nr, 1000L))
630 sigproc_printf ("WritePipeOverlapped sizeof fd failed, %E");
631 else if (!WritePipeOverlapped (tothem, path, n, &nr, 1000L))
632 sigproc_printf ("WritePipeOverlapped fd failed, %E");
638 DWORD res = WaitForSingleObject (process_sync, 5000);
639 if (res != WAIT_OBJECT_0)
640 sigproc_printf ("WFSO failed - %d, %E", res);
642 sigproc_printf ("synchronized with pid %d", si.si_pid);
643 ForceCloseHandle (process_sync);
645 CloseHandle (tothem);
646 _my_tls._ctinfo->auto_release ();
651 _pinfo::commune_request (__uint32_t code, ...)
657 HANDLE& hp = si._si_commune._si_process_handle;
658 HANDLE& fromthem = si._si_commune._si_read_handle;
659 HANDLE request_sync = NULL;
671 va_start (args, code);
672 si._si_commune._si_code = code;
675 case PICOM_PIPE_FHANDLER:
676 si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE);
680 si._si_commune._si_fd = va_arg (args, int);
688 char name_buf[MAX_PATH];
689 request_sync = CreateSemaphore (&sec_none_nih, 0, LONG_MAX,
690 shared_name (name_buf, "commune", myself->pid));
693 ProtectHandle (request_sync);
695 si.si_signo = __SIGCOMMUNE;
696 if (sig_send (this, si))
698 ForceCloseHandle (request_sync); /* don't signal semaphore since there was apparently no receiving process */
711 case PICOM_PIPE_FHANDLER:
712 if (!ReadPipeOverlapped (fromthem, &n, sizeof n, &nr, 500L)
722 res.s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
725 n && ReadPipeOverlapped (fromthem, p, n, &nr, 500L);
740 memset (&res, 0, sizeof (res));
746 ReleaseSemaphore (request_sync, 1, &res);
747 ForceCloseHandle (request_sync);
752 CloseHandle (fromthem);
757 _pinfo::pipe_fhandler (HANDLE hdl, size_t &n)
761 if (pid == myself->pid)
763 commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl);
765 return (fhandler_pipe *) cr.s;
769 _pinfo::fd (int fd, size_t &n)
774 if (pid != myself->pid)
776 commune_result cr = commune_request (PICOM_FD, fd);
782 cygheap_fdget cfd (fd);
786 s = cfd->get_proc_fd_name ((char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH));
793 _pinfo::fds (size_t &n)
798 if (pid != myself->pid)
800 commune_result cr = commune_request (PICOM_FDS);
808 cygheap_fdenum cfd (true);
809 while ((fd = cfd.next ()) >= 0)
812 s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
814 while ((fd = cfd.next ()) >= 0 && (char *) p - s < (int) n)
821 _pinfo::root (size_t& n)
826 if (pid != myself->pid)
828 commune_result cr = commune_request (PICOM_ROOT);
834 if (cygheap->root.exists ())
835 s = cstrdup (cygheap->root.posix_path ());
844 _pinfo::cwd (size_t& n)
849 if (pid != myself->pid)
851 commune_result cr = commune_request (PICOM_CWD);
857 s = (char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH);
858 cygheap->cwd.get (s, 1, 1, NT_MAX_PATH);
865 _pinfo::cmdline (size_t& n)
870 if (pid != myself->pid)
872 commune_result cr = commune_request (PICOM_CMDLINE);
879 for (char **a = __argv; *a; a++)
880 n += strlen (*a) + 1;
882 p = s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
883 for (char **a = __argv; *a; a++)
886 p = strchr (p, '\0') + 1;
892 /* This is the workhorse which waits for the write end of the pipe
893 created during new process creation. If the pipe is closed or a zero
894 is received on the pipe, it is assumed that the cygwin pid has exited.
895 Otherwise, various "signals" can be sent to the parent to inform the
896 parent to perform a certain action. */
898 proc_waiter (void *arg)
900 pinfo vchild = *(pinfo *) arg;
901 ((pinfo *) arg)->waiter_ready = true;
904 si.si_signo = SIGCHLD;
905 si.si_code = CLD_EXITED;
906 si.si_pid = vchild->pid;
907 #if 0 // FIXME: This is tricky to get right
908 si.si_utime = pchildren[rc]->rusage_self.ru_utime;
909 si.si_stime = pchildren[rc].rusage_self.ru_stime;
911 pid_t pid = vchild->pid;
912 bool its_me = vchild == myself;
919 if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
920 && GetLastError () != ERROR_BROKEN_PIPE)
922 system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
926 if (!its_me && have_execed_cygwin)
929 si.si_uid = vchild->uid;
936 /* Child exited. Do some cleanup and signal myself. */
937 vchild.maybe_set_exit_code_from_windows ();
938 if (WIFEXITED (vchild->exitcode))
939 si.si_code = CLD_EXITED;
940 else if (WCOREDUMP (vchild->exitcode))
941 si.si_code = CLD_DUMPED;
943 si.si_code = CLD_KILLED;
944 si.si_status = vchild->exitcode;
945 vchild->process_state = PID_EXITED;
946 /* This should always be last. Do not use vchild-> beyond this point */
952 if (ISSTATE (myself, PID_NOCLDSTOP)) // FIXME: No need for this flag to be in _pinfo any longer
954 /* Child stopped. Signal myself. */
955 si.si_code = CLD_STOPPED;
960 system_printf ("unknown value %d on proc pipe", buf);
964 if (its_me && ch_spawn.signal_myself_exited ())
967 /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
968 to avoid the proc_subproc lock since the signal thread will eventually
969 be calling proc_subproc and could unnecessarily block. */
970 sig_send (myself_nowait, si);
972 /* If we're just stopped or got a continue signal, keep looping.
973 Otherwise, return this thread to the pool. */
975 sigproc_printf ("looping");
980 sigproc_printf ("exiting wait thread for pid %d", pid);
981 vchild.wait_thread = NULL;
982 _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */
987 #define warn_printf api_fatal
989 #define warn_printf system_printf
992 _pinfo::dup_proc_pipe (HANDLE hProcess)
994 DWORD flags = DUPLICATE_SAME_ACCESS;
995 HANDLE orig_wr_proc_pipe = wr_proc_pipe;
996 /* Can't set DUPLICATE_CLOSE_SOURCE for exec case because we could be
997 execing a non-cygwin process and we need to set the exit value before the
999 if (this != myself || is_toplevel_proc)
1000 flags |= DUPLICATE_CLOSE_SOURCE;
1001 bool res = DuplicateHandle (GetCurrentProcess (), wr_proc_pipe,
1002 hProcess, &wr_proc_pipe, 0, FALSE, flags);
1003 if (!res && WaitForSingleObject (hProcess, 0) != WAIT_OBJECT_0)
1005 wr_proc_pipe = orig_wr_proc_pipe;
1006 warn_printf ("something failed for pid %d: res %d, hProcess %p, wr_proc_pipe %p vs. %p, %E",
1007 res, pid, hProcess, wr_proc_pipe, orig_wr_proc_pipe);
1011 wr_proc_pipe_owner = dwProcessId;
1012 sigproc_printf ("duped wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
1015 return orig_wr_proc_pipe;
1018 /* function to set up the process pipe and kick off proc_waiter */
1022 /* If rd_proc_pipe != NULL we're in an execed process which already has
1023 grabbed the read end of the pipe from the previous cygwin process running
1027 /* FIXME: execed processes should be able to wait for pids that were started
1028 by the process which execed them. */
1029 if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
1031 system_printf ("Couldn't create pipe tracker for pid %d, %E",
1036 if (!(*this)->dup_proc_pipe (hProcess))
1038 system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
1043 preserve (); /* Preserve the shared memory associated with the pinfo */
1045 waiter_ready = false;
1046 /* Fire up a new thread to track the subprocess */
1047 cygthread *h = new cygthread (proc_waiter, this, "waitproc");
1049 sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
1053 sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_proc_pipe %p",
1054 (*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
1061 _pinfo::sync_proc_pipe ()
1063 if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
1064 while (wr_proc_pipe_owner != GetCurrentProcessId ())
1068 /* function to send a "signal" to the parent when something interesting happens
1071 _pinfo::alert_parent (char sig)
1075 /* Send something to our parent. If the parent has gone away, close the pipe.
1076 Don't send if this is an exec stub.
1078 FIXME: Is there a race here if we run this while another thread is attempting
1080 if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || have_execed)
1085 if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
1087 else if (GetLastError () != ERROR_BROKEN_PIPE)
1088 debug_printf ("sending %d notification to parent failed, %E", sig);
1092 HANDLE closeit = wr_proc_pipe;
1093 wr_proc_pipe = INVALID_HANDLE_VALUE;
1094 CloseHandle (closeit);
1107 close_h = rd_proc_pipe;
1108 rd_proc_pipe = NULL;
1109 ForceCloseHandle1 (close_h, rd_proc_pipe);
1115 ForceCloseHandle1 (close_h, childhProc);
1121 <sect1 id="func-cygwin-winpid-to-pid">
1122 <title>cygwin_winpid_to_pid</title>
1124 <funcsynopsis><funcprototype>
1125 <funcdef>extern "C" pid_t
1126 <function>cygwin_winpid_to_pid</function>
1128 <paramdef>int <parameter>winpid</parameter></paramdef>
1129 </funcprototype></funcsynopsis>
1131 <para>Given a windows pid, converts to the corresponding Cygwin
1132 pid, if any. Returns -1 if windows pid does not correspond to
1133 a cygwin pid.</para>
1135 <title>Example use of cygwin_winpid_to_pid</title>
1137 extern "C" cygwin_winpid_to_pid (int winpid);
1139 mypid = cygwin_winpid_to_pid (windows_pid);
1147 cygwin_winpid_to_pid (int winpid)
1149 pinfo p (cygwin_pid (winpid));
1158 #define slop_pidlist 200
1159 #define size_pidlist(i) (sizeof (pidlist[0]) * ((i) + 1))
1160 #define size_pinfolist(i) (sizeof (pinfolist[0]) * ((i) + 1))
1174 void no_close_p_handle () {h = NULL;}
1175 _onreturn (HANDLE& _h): h (&_h) {}
1179 winpids::add (DWORD& nelem, bool winpid, DWORD pid)
1181 pid_t cygpid = cygwin_pid (pid);
1183 if (nelem >= npidlist)
1185 npidlist += slop_pidlist;
1186 pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist + 1));
1187 pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist + 1));
1190 pinfo& p = pinfolist[nelem];
1191 memset (&p, 0, sizeof (p));
1193 /* Open a process to prevent a subsequent exit from invalidating the
1194 shared memory region. */
1195 p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, pid);
1196 _onreturn onreturn (p.hProcess);
1198 /* If we couldn't open the process then we don't have rights to it and should
1199 make a copy of the shared memory area if it exists (it may not). */
1202 perform_copy = true;
1204 perform_copy = make_copy;
1206 p.init (cygpid, PID_NOREDIR | pinfo_access, NULL);
1208 /* If we're just looking for winpids then don't do any special cygwin "stuff* */
1212 /* !p means that we couldn't find shared memory for this pid. Probably means
1213 that it isn't a cygwin process. */
1218 p.init (cygpid, PID_NOREDIR, NULL);
1223 /* Scan list of previously recorded pids to make sure that this pid hasn't
1224 shown up before. This can happen when a process execs. */
1225 for (unsigned i = 0; i < nelem; i++)
1226 if (pinfolist[i]->pid == p->pid)
1228 if ((_pinfo *) p != (_pinfo *) myself)
1236 If p is "false" then, eventually any opened process handle will be closed and
1237 the function will exit without adding anything to the pid list.
1239 If p is "true" then we've discovered a cygwin process.
1241 Handle "myself" differently. Don't copy it and close/zero the handle we
1243 If not performing a copy, then keep the process handle open for the duration
1244 of the life of the procinfo region to potential races when a new process uses
1246 Otherwise, malloc some memory for a copy of the shared memory.
1248 If the malloc failed, then "oh well". Just keep the shared memory around
1249 and eventually close the handle when the winpids goes out of scope.
1251 If malloc succeeds, copy the procinfo we just grabbed into the new region,
1252 release the shared memory and allow the handle to be closed when this
1255 Oh, and add the pid to the list and bump the number of elements. */
1259 if (p == (_pinfo *) myself)
1260 /* handle specially. Close the handle but (eventually) don't
1261 deallocate procinfo in release call */;
1262 else if (!perform_copy)
1263 onreturn.no_close_p_handle (); /* Don't close the handle until release */
1266 _pinfo *pnew = (_pinfo *) malloc (sizeof (*p.procinfo));
1268 onreturn.no_close_p_handle ();
1271 *pnew = *p.procinfo;
1279 pidlist[nelem++] = !p ? pid : p->dwProcessId;
1283 winpids::enum_processes (bool winpid)
1286 DWORD cygwin_pid_nelem = 0;
1291 DIRECTORY_BASIC_INFORMATION dbi;
1292 WCHAR buf[2][NAME_MAX + 1];
1294 HANDLE dir = get_shared_parent_dir ();
1295 BOOLEAN restart = TRUE;
1299 status = NtQueryDirectoryObject (dir, &f, sizeof f, TRUE, restart,
1301 if (NT_SUCCESS (status))
1304 f.dbi.ObjectName.Buffer[f.dbi.ObjectName.Length / sizeof (WCHAR)]
1306 if (wcsncmp (f.dbi.ObjectName.Buffer, L"cygpid.", 7) == 0)
1308 DWORD pid = wcstoul (f.dbi.ObjectName.Buffer + 7, NULL, 10);
1309 add (nelem, false, pid);
1313 while (NT_SUCCESS (status));
1314 cygwin_pid_nelem = nelem;
1318 static DWORD szprocs;
1319 static PSYSTEM_PROCESSES procs;
1323 procs = (PSYSTEM_PROCESSES)
1324 malloc (sizeof (*procs) + (szprocs = 200 * sizeof (*procs)));
1327 system_printf ("out of memory reading system process "
1336 NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
1337 procs, szprocs, NULL);
1338 if (NT_SUCCESS (status))
1341 if (status == STATUS_INFO_LENGTH_MISMATCH)
1343 PSYSTEM_PROCESSES new_p;
1345 new_p = (PSYSTEM_PROCESSES)
1346 realloc (procs, szprocs += 200 * sizeof (*procs));
1349 system_printf ("out of memory reading system process "
1357 system_printf ("error %p reading system process information",
1363 PSYSTEM_PROCESSES px = procs;
1369 for (unsigned i = 0; i < cygwin_pid_nelem; ++i)
1370 if (pidlist[i] == px->ProcessId)
1376 add (nelem, true, px->ProcessId);
1378 if (!px->NextEntryDelta)
1380 px = (PSYSTEM_PROCESSES) ((char *) px + px->NextEntryDelta);
1388 winpids::set (bool winpid)
1391 npids = enum_processes (winpid);
1398 winpids::enum_init (bool winpid)
1400 return enum_processes (winpid);
1407 for (unsigned i = 0; i < npids; i++)
1408 if (pinfolist[i] == (_pinfo *) myself)
1410 else if (pinfolist[i].hProcess)
1411 pinfolist[i].release ();
1412 else if ((p = pinfolist[i]))
1414 pinfolist[i].procinfo = NULL;
1419 winpids::~winpids ()