1 /* pinfo.cc: process table support
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "miscfuncs.h"
19 #include "perprocess.h"
22 #include "shared_info.h"
24 #include "cygmalloc.h"
27 #include "child_info.h"
30 class pinfo_basic
: public _pinfo
36 pinfo_basic::pinfo_basic ()
38 dwProcessId
= GetCurrentProcessId ();
39 PWCHAR pend
= wcpncpy (progname
, global_progname
,
40 sizeof (progname
) / sizeof (WCHAR
) - 1);
42 /* Default uid/gid are needed very early to initialize shared user info. */
47 pinfo_basic myself_initial NO_COPY
;
49 pinfo NO_COPY
myself (static_cast<_pinfo
*> (&myself_initial
)); // Avoid myself != NULL checks
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 DWORD flags
= PID_IN_USE
| PID_ACTIVE
;
61 /* Forked process or process started from non-Cygwin parent needs a pid. */
64 cygheap
->pid
= create_cygwin_pid ();
66 h
= INVALID_HANDLE_VALUE
;
68 /* spawnve'd process got pid in parent, cygheap->pid has been set in
69 child_info_spawn::handle_spawn. */
71 init (cygheap
->pid
, flags
, h
);
72 procinfo
->process_state
|= PID_IN_USE
;
73 procinfo
->dwProcessId
= myself_initial
.dwProcessId
;
74 procinfo
->sendsig
= myself_initial
.sendsig
;
75 wcscpy (procinfo
->progname
, myself_initial
.progname
);
77 create_winpid_symlink ();
78 procinfo
->exec_sendsig
= NULL
;
79 procinfo
->exec_dwProcessId
= 0;
80 debug_printf ("myself dwProcessId %u", procinfo
->dwProcessId
);
83 /* Initialize the process table entry for the current task.
84 This is not called for forked tasks, only execed ones. */
86 pinfo_init (char **envp
, int envc
)
90 environ_init (envp
, envc
);
91 /* spawn has already set up a pid structure for us so we'll use that */
92 myself
->process_state
|= PID_CYGPARENT
;
96 /* Invent our own pid. */
98 myself
.thisproc (NULL
);
99 myself
->pgid
= myself
->sid
= myself
->pid
;
100 myself
->ctty
= CTTY_UNINITIALIZED
;
101 myself
->uid
= ILLEGAL_UID
;
102 myself
->gid
= ILLEGAL_GID
;
103 environ_init (NULL
, 0); /* call after myself has been set up */
104 myself
->nice
= winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
105 myself
->ppid
= 1; /* always set last */
106 debug_printf ("Set nice to %d", myself
->nice
);
109 myself
->process_state
|= PID_ACTIVE
;
110 myself
->process_state
&= ~(PID_INITIALIZING
| PID_EXITED
| PID_REAPED
);
111 if (being_debugged ())
112 myself
->process_state
|= PID_DEBUGGED
;
114 debug_printf ("pid %d, pgid %d, process_state %y",
115 myself
->pid
, myself
->pgid
, myself
->process_state
);
119 pinfo::status_exit (DWORD x
)
123 case STATUS_DLL_NOT_FOUND
:
127 pc
.check ("/dev/null", PC_POSIX
);
131 RtlInitUnicodeString(&uc
, procinfo
->progname
);
132 pc
.check (&uc
, PC_POSIX
);
134 small_printf ("%s: error while loading shared libraries: %s: cannot "
135 "open shared object file: No such file or directory\n",
136 pc
.get_posix (), find_first_notloaded_dll (pc
));
140 case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION
: /* custom error value */
141 /* We've already printed the error message in pseudo-reloc.c */
144 case STATUS_ACCESS_VIOLATION
:
147 case STATUS_ILLEGAL_INSTRUCTION
:
150 case STATUS_NO_MEMORY
:
151 /* If the PATH environment variable is longer than about 30K and the full
152 Windows environment is > 32K, startup of an exec'ed process fails with
153 STATUS_NO_MEMORY. This happens with all Cygwin executables, as well
154 as, for instance, notepad, but it does not happen with CMD for some
155 reason (but note, the environment *in* CMD is broken and shortened).
156 This occurs at a point where there's no return to the exec'ing parent
157 process, so we have to find some way to inform the user what happened.
159 FIXME: For now, just return with SIGBUS set. Maybe it's better to add
160 a lengthy small_printf instead. */
163 case STATUS_CONTROL_C_EXIT
:
167 debug_printf ("*** STATUS_%y\n", x
);
170 return EXITCODE_SET
| x
;
173 # define self (*this)
175 pinfo::set_exit_code (DWORD x
)
177 if (x
>= 0xc0000000UL
)
178 self
->exitcode
= status_exit (x
);
180 self
->exitcode
= EXITCODE_SET
| (sigExeced
?: (x
& 0xff) << 8);
184 pinfo::maybe_set_exit_code_from_windows ()
186 DWORD x
= 0xdeadbeef;
187 DWORD oexitcode
= self
->exitcode
;
189 if (hProcess
&& !(self
->exitcode
& EXITCODE_SET
))
191 WaitForSingleObject (hProcess
, INFINITE
); /* just to be safe, in case
192 process hasn't quite exited
193 after closing pipe */
194 GetExitCodeProcess (hProcess
, &x
);
197 sigproc_printf ("pid %d, exit value - old %y, windows %y, cygwin %y",
198 self
->pid
, oexitcode
, x
, self
->exitcode
);
202 pinfo::exit (DWORD n
)
204 debug_only_printf ("winpid %d, exit %d", GetCurrentProcessId (), n
);
206 lock_process
until_exit (true);
207 cygthread::terminate ();
209 if (n
!= EXITCODE_NOSET
)
210 self
->exitcode
= EXITCODE_SET
| n
;/* We're really exiting. Record the UNIX exit code. */
212 maybe_set_exit_code_from_windows (); /* may block */
213 exit_state
= ES_FINAL
;
215 if (CTTY_IS_VALID (myself
->ctty
) && !iscons_dev (myself
->ctty
))
218 tty
*t
= cygwin_shared
->tty
[device::minor(myself
->ctty
)];
219 if (!t
->slave_alive ())
223 /* FIXME: There is a potential race between an execed process and its
224 parent here. I hated to add a mutex just for that, though. */
226 fill_rusage (&r
, GetCurrentProcess ());
227 add_rusage (&self
->rusage_self
, &r
);
228 int exitcode
= self
->exitcode
& 0xffff;
229 if (!self
->cygstarted
)
230 exitcode
= ((exitcode
& 0xff) << 8) | ((exitcode
>> 8) & 0xff);
231 sigproc_printf ("Calling dlls.cleanup_forkables n %y, exitcode %y", n
, exitcode
);
232 dlls
.cleanup_forkables ();
233 sigproc_printf ("Calling ExitProcess n %y, exitcode %y", n
, exitcode
);
234 if (!TerminateProcess (GetCurrentProcess (), exitcode
))
235 system_printf ("TerminateProcess failed, %E");
236 ExitProcess (exitcode
);
240 /* Return next free Cygwin PID between 2 and 65535, round-robin. Each new
241 PID is checked that it doesn't collide with an existing PID. For that,
242 just check if the "cygpid.PID" section exists. */
248 UNICODE_STRING sym_str
;
249 OBJECT_ATTRIBUTES attr
;
257 pid
= ((uint32_t) InterlockedIncrement (&cygwin_shared
->pid_src
))
261 __small_swprintf (sym_name
, L
"cygpid.%u", pid
);
262 RtlInitUnicodeString (&sym_str
, sym_name
);
263 InitializeObjectAttributes (&attr
, &sym_str
, OBJ_CASE_INSENSITIVE
,
264 get_shared_parent_dir (), NULL
);
265 /* We just want to know if the section (and thus the process) still
266 exists. Instead of actually opening the section, try to open
267 it as symlink. NtOpenSymbolicLinkObject will always returns an
269 - STATUS_OBJECT_NAME_NOT_FOUND if the section doesn't exist,
270 so the slot is free and we can use this pid.
271 - STATUS_OBJECT_TYPE_MISMATCH if the section exists, so we have
272 to skip this pid and loop to try the next one.
273 As side-effect we never have to close the section handle and thus
274 we don't influence the lifetime of the section. */
275 status
= NtOpenSymbolicLinkObject (&sym_hdl
, SYMBOLIC_LINK_QUERY
, &attr
);
277 while (status
== STATUS_OBJECT_TYPE_MISMATCH
);
281 /* Convert Windows WINPID into Cygwin PID. Utilize the "winpid.WINPID"
282 symlinks created for each process. The symlink contains the Cygwin
283 PID as target. Return 0 if no "winpid.WINPID" symlink exists for
286 cygwin_pid (DWORD dwProcessId
)
290 UNICODE_STRING sym_str
;
291 UNICODE_STRING pid_str
;
292 OBJECT_ATTRIBUTES attr
;
296 __small_swprintf (sym_name
, L
"winpid.%u", dwProcessId
);
297 RtlInitUnicodeString (&sym_str
, sym_name
);
298 InitializeObjectAttributes (&attr
, &sym_str
, OBJ_CASE_INSENSITIVE
,
299 get_shared_parent_dir (), NULL
);
300 status
= NtOpenSymbolicLinkObject (&sym_hdl
, SYMBOLIC_LINK_QUERY
, &attr
);
301 if (!NT_SUCCESS (status
))
303 RtlInitEmptyUnicodeString (&pid_str
, pid_name
,
304 sizeof pid_name
- sizeof (WCHAR
));
305 status
= NtQuerySymbolicLinkObject (sym_hdl
, &pid_str
, NULL
);
307 if (!NT_SUCCESS (status
))
309 system_printf ("NtOpenSymbolicLinkObject: %y, PID %u, ret 0",
310 status
, dwProcessId
);
313 pid_str
.Buffer
[pid_str
.Length
/ sizeof (WCHAR
)] = L
'\0';
314 pid_t ret
= (pid_t
) wcstoul (pid_str
.Buffer
, NULL
, 10);
318 /* Create "winpid.WINPID" symlinks with the Cygwin PID of that process as
319 target. This is used to find the Cygwin PID for a given Windows WINPID. */
321 pinfo::create_winpid_symlink ()
325 UNICODE_STRING sym_str
;
326 UNICODE_STRING pid_str
;
327 OBJECT_ATTRIBUTES attr
;
329 __small_swprintf (sym_name
, L
"winpid.%u", procinfo
->dwProcessId
);
330 RtlInitUnicodeString (&sym_str
, sym_name
);
331 __small_swprintf (pid_name
, L
"%u", procinfo
->pid
);
332 RtlInitUnicodeString (&pid_str
, pid_name
);
333 InitializeObjectAttributes (&attr
, &sym_str
, OBJ_CASE_INSENSITIVE
,
334 get_shared_parent_dir (),
335 everyone_sd (SYMBOLIC_LINK_QUERY
));
336 NtCreateSymbolicLinkObject (&winpid_hdl
, SYMBOLIC_LINK_ALL_ACCESS
,
341 pinfo::_pinfo_release ()
345 void *unmap_procinfo
= procinfo
;
347 UnmapViewOfFile (unmap_procinfo
);
354 ForceCloseHandle1 (close_h
, pinfo_shared_handle
);
359 pinfo::init (pid_t n
, DWORD flag
, HANDLE h0
)
361 shared_locations shloc
;
363 if (myself
&& n
== myself
->pid
)
370 int createit
= (flag
& PID_IN_USE
);
371 DWORD access
= FILE_MAP_READ
372 | (flag
& (PID_IN_USE
| PID_MAP_RW
) ? FILE_MAP_WRITE
: 0);
374 shloc
= (flag
& PID_IN_USE
) ? SH_JUSTCREATE
: SH_JUSTOPEN
;
378 if (h0
== INVALID_HANDLE_VALUE
)
383 PSECURITY_ATTRIBUTES sa_buf
= (PSECURITY_ATTRIBUTES
) alloca (1024);
384 PSECURITY_ATTRIBUTES sec_attribs
= sec_user_nih (sa_buf
, cygheap
->user
.sid(),
385 well_known_world_sid
,
388 for (int i
= 0; i
< 20; i
++)
392 procinfo
= (_pinfo
*) open_shared (L
"cygpid", n
, h0
, sizeof (_pinfo
),
393 shloc
, created
, sec_attribs
, access
);
406 if (GetLastError () == ERROR_INVALID_HANDLE
)
407 api_fatal ("MapViewOfFileEx h0 %p, i %d failed, %E", h0
, i
);
409 debug_printf ("MapViewOfFileEx h0 %p, i %d failed, %E", h0
, i
);
414 /* Just fetching info for ps or /proc, don't do anything rash. */
415 if (!created
&& !(flag
& PID_NEW
) && !procinfo
->ppid
416 && (flag
& PID_PROCINFO
))
419 if (!created
&& createit
&& (procinfo
->process_state
& PID_REAPED
))
421 memset (procinfo
, 0, sizeof (*procinfo
));
422 created
= true; /* Lie that we created this - just reuse old
426 if (procinfo
->process_state
& PID_REAPED
)
432 /* In certain pathological cases, it is possible for the shared memory
433 region to exist for a while after a process has exited. This should
434 only be a brief occurrence, so rather than introduce some kind of
435 locking mechanism, just loop. */
436 if (!created
&& createit
437 && (procinfo
->process_state
& (PID_EXITED
| PID_REAPED
)))
439 debug_printf ("looping because pid %d, procinfo->pid %d, "
440 "procinfo->dwProcessid %u has PID_EXITED|PID_REAPED set",
441 n
, procinfo
->pid
, procinfo
->dwProcessId
);
446 procinfo
->start_time
= time (NULL
);
450 h
= h0
; /* Success! */
462 ProtectHandle1 (h
, pinfo_shared_handle
);
469 if (shloc
== SH_MYSELF
)
470 cygheap
->shared_regions
.myself_shared_addr
= procinfo
;
476 PACL acl_buf
= (PACL
) alloca (1024);
477 SECURITY_DESCRIPTOR sd
;
480 sec_acl (acl_buf
, true, true, cygheap
->user
.sid (),
481 well_known_world_sid
, FILE_MAP_READ
);
482 RtlCreateSecurityDescriptor (&sd
, SECURITY_DESCRIPTOR_REVISION
);
483 status
= RtlSetDaclSecurityDescriptor (&sd
, TRUE
, acl_buf
, FALSE
);
484 if (!NT_SUCCESS (status
))
485 debug_printf ("RtlSetDaclSecurityDescriptor %y", status
);
486 else if ((status
= NtSetSecurityObject (h
, DACL_SECURITY_INFORMATION
, &sd
)))
487 debug_printf ("NtSetSecurityObject %y", status
);
491 pinfo_minimal::set_inheritance (bool inherit
)
493 DWORD i_flag
= inherit
? HANDLE_FLAG_INHERIT
: 0;
495 SetHandleInformation (rd_proc_pipe
, HANDLE_FLAG_INHERIT
, i_flag
);
496 SetHandleInformation (hProcess
, HANDLE_FLAG_INHERIT
, i_flag
);
497 SetHandleInformation (h
, HANDLE_FLAG_INHERIT
, i_flag
);
500 pinfo::pinfo (HANDLE parent
, pinfo_minimal
& from
, pid_t pid
):
501 pinfo_minimal (), destroy (false), procinfo (NULL
), waiter_ready (false),
504 /* cygheap_exec_info::record_children set the inheritance of the required
505 child handles so just copy them over... */
506 rd_proc_pipe
= from
.rd_proc_pipe
;
507 hProcess
= from
.hProcess
;
509 /* ...and reset their inheritance. */
510 set_inheritance (false);
511 init (pid
, PID_MAP_RW
, h
);
515 _pinfo::_ctty (char *buf
)
517 if (!CTTY_IS_VALID (ctty
))
518 stpcpy (buf
, "no ctty");
523 __small_sprintf (buf
, "ctty %s", d
.name ());
529 _pinfo::set_ctty (fhandler_termios
*fh
, int flags
)
531 tty_min
& tc
= *fh
->tc ();
532 debug_printf ("old %s, ctty device number %y, tc.ntty device number %y flags & O_NOCTTY %y", __ctty (), ctty
, tc
.ntty
, flags
& O_NOCTTY
);
533 if (fh
&& (!CTTY_IS_VALID (ctty
) || ctty
== tc
.ntty
) && !(flags
& O_NOCTTY
))
535 if (tc
.getsid () && tc
.getsid () != sid
&& ctty
== CTTY_RELEASED
)
536 ; /* Do nothing if another session is associated with the TTY. */
540 if (cygheap
->ctty
!= fh
->archetype
)
542 debug_printf ("cygheap->ctty %p, archetype %p",
543 cygheap
->ctty
, fh
->archetype
);
545 syscall_printf ("ctty was NULL");
548 syscall_printf ("ctty %p, usecount %d", cygheap
->ctty
,
549 cygheap
->ctty
->archetype_usecount (0));
550 cygheap
->ctty
->close ();
552 cygheap
->ctty
= (fhandler_termios
*) fh
->archetype
;
555 fh
->archetype_usecount (1);
557 report_tty_counts (cygheap
->ctty
, "ctty", "");
563 syscall_printf ("attaching %s sid %d, pid %d, pgid %d, tty->pgid %d, tty->sid %d",
564 __ctty (), sid
, pid
, pgid
, tc
.getpgid (), tc
.getsid ());
565 if (!cygwin_finished_initializing
&& !myself
->cygstarted
566 && pgid
== pid
&& tc
.getpgid () && tc
.getsid ()
567 /* Even GDB starts app via CreateProcess which changes cygstarted.
568 This results in setting the wrong pgid here, so just skip this
570 && !being_debugged ())
571 pgid
= tc
.getpgid ();
573 /* May actually need to do this:
575 if (sid == pid && !tc.getsid () || !procinfo (tc.getsid ())->exists)
577 but testing for process existence is expensive so we avoid it until
578 an obvious bug surfaces. */
579 if (sid
== pid
&& !tc
.getsid ())
581 if (CTTY_IS_VALID (ctty
))
584 if ((!tc
.getpgid () || being_debugged ()) && pgid
== pid
)
587 debug_printf ("cygheap->ctty now %p, archetype %p", cygheap
->ctty
, fh
? fh
->archetype
: NULL
);
588 return CTTY_IS_VALID (ctty
);
591 /* Test to determine if a process really exists and is processing signals.
596 return process_state
&& !(process_state
& (PID_EXITED
| PID_REAPED
));
602 HANDLE h
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, false,
609 static commune_result
610 commune_process_siginfo ()
612 commune_result res
= { 0 };
614 res
.pnd
= sig_send (myself
, __SIGPENDINGALL
, NULL
);
615 res
.blk
= cygheap
->compute_sigblkmask ();
616 for (int sig
= 1; sig
< NSIG
; ++sig
)
617 if (global_sigs
[sig
].sa_handler
== SIG_IGN
)
618 res
.ign
|= SIGTOMASK (sig
);
623 commune_process (void *arg
)
625 siginfo_t
& si
= *((siginfo_t
*) arg
);
627 char *path
= tp
.c_get ();
629 HANDLE
& tothem
= si
._si_commune
._si_write_handle
;
630 HANDLE process_sync
=
631 OpenSemaphore (SYNCHRONIZE
, false, shared_name (path
, "commune", si
.si_pid
));
632 if (process_sync
) // FIXME: this test shouldn't be necessary
633 ProtectHandle (process_sync
);
636 if (si
._si_commune
._si_code
& PICOM_EXTRASTR
)
637 si
._si_commune
._si_str
= (char *) (&si
+ 1);
639 switch (si
._si_commune
._si_code
)
643 sigproc_printf ("processing PICOM_CMDLINE");
645 int argc
= __argv0_orig
? 1 : __argc_safe
;
646 const char *argv
[argc
+ 1];
648 for (int i
= 0; i
< argc
; i
++)
650 argv
[i
] = __argv
[i
] ?: "";
651 n
+= strlen (argv
[i
]) + 1;
654 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
655 sigproc_printf ("WritePipeOverlapped sizeof argv failed, %E");
656 else for (int i
= 0; i
< argc
; i
++)
657 if (!WritePipeOverlapped (tothem
, __argv
[i
],
658 strlen (__argv
[i
]) + 1, &nr
, 1000L))
660 sigproc_printf ("WritePipeOverlapped arg %d failed, %E", i
);
667 sigproc_printf ("processing PICOM_CWD");
668 unsigned int n
= strlen (cygheap
->cwd
.get (path
, 1, 1, NT_MAX_PATH
)) + 1;
669 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
670 sigproc_printf ("WritePipeOverlapped sizeof cwd failed, %E");
671 else if (!WritePipeOverlapped (tothem
, path
, n
, &nr
, 1000L))
672 sigproc_printf ("WritePipeOverlapped cwd failed, %E");
677 sigproc_printf ("processing PICOM_ROOT");
679 if (cygheap
->root
.exists ())
680 n
= strlen (strcpy (path
, cygheap
->root
.posix_path ())) + 1;
682 n
= strlen (strcpy (path
, "/")) + 1;
683 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
684 sigproc_printf ("WritePipeOverlapped sizeof root failed, %E");
685 else if (!WritePipeOverlapped (tothem
, path
, n
, &nr
, 1000L))
686 sigproc_printf ("WritePipeOverlapped root failed, %E");
691 sigproc_printf ("processing PICOM_SIGINFO");
692 commune_result cr
= commune_process_siginfo ();
693 if (!WritePipeOverlapped (tothem
, &cr
, sizeof cr
, &nr
, 1000L))
694 sigproc_printf ("WritePipeOverlapped siginfo failed, %E");
699 sigproc_printf ("processing PICOM_FDS");
703 while ((fd
= cfd
.next ()) >= 0)
706 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
707 sigproc_printf ("WritePipeOverlapped sizeof fds failed, %E");
709 while ((fd
= cfd
.next ()) >= 0)
710 if (!WritePipeOverlapped (tothem
, &fd
, sizeof fd
, &nr
, 1000L))
712 sigproc_printf ("WritePipeOverlapped fd %d failed, %E", fd
);
717 case PICOM_PIPE_FHANDLER
:
719 sigproc_printf ("processing PICOM_PIPE_FHANDLER");
720 int64_t unique_id
= si
._si_commune
._si_pipe_unique_id
;
723 while (cfd
.next () >= 0)
724 if (cfd
->get_unique_id () == unique_id
)
726 fhandler_pipe
*fh
= cfd
;
728 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
729 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
730 else if (!WritePipeOverlapped (tothem
, fh
, n
, &nr
, 1000L))
731 sigproc_printf ("WritePipeOverlapped hdl failed, %E");
734 if (!n
&& !WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
735 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
738 case PICOM_FILE_PATHCONV
:
740 sigproc_printf ("processing PICOM_FILE_PATHCONV");
741 int fd
= si
._si_commune
._si_fd
;
742 uint32_t flags
= si
._si_commune
._si_flags
;
744 cygheap_fdget
cfd (fd
);
746 && (!(flags
& FFH_LINKAT
)
747 || (cfd
->get_flags () & (O_TMPFILE
| O_EXCL
))
748 != (O_TMPFILE
| O_EXCL
)))
750 fhandler_base
*fh
= cfd
;
751 void *ser_buf
= fh
->pc
.serialize (fh
->get_handle (), n
);
752 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
753 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
754 else if (!WritePipeOverlapped (tothem
, ser_buf
, n
, &nr
, 1000L))
755 sigproc_printf ("WritePipeOverlapped hdl failed, %E");
758 else if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
759 sigproc_printf ("WritePipeOverlapped sizeof hdl failed, %E");
764 sigproc_printf ("processing PICOM_FD");
765 int fd
= si
._si_commune
._si_fd
;
767 cygheap_fdget
cfd (fd
);
769 n
= strlen (strcpy (path
, "")) + 1;
771 n
= strlen (cfd
->get_proc_fd_name (path
)) + 1;
772 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
773 sigproc_printf ("WritePipeOverlapped sizeof fd failed, %E");
774 else if (!WritePipeOverlapped (tothem
, path
, n
, &nr
, 1000L))
775 sigproc_printf ("WritePipeOverlapped fd failed, %E");
780 sigproc_printf ("processing PICOM_ENVIRON");
782 char **env
= environ
;
784 for (char **e
= env
; *e
; e
++)
785 n
+= strlen (*e
) + 1;
786 if (!WritePipeOverlapped (tothem
, &n
, sizeof n
, &nr
, 1000L))
787 sigproc_printf ("WritePipeOverlapped sizeof argv failed, %E");
789 for (char **e
= env
; *e
; e
++)
790 if (!WritePipeOverlapped (tothem
, *e
, strlen (*e
) + 1, &nr
, 1000L))
792 sigproc_printf ("WritePipeOverlapped arg %d failed, %E",
801 DWORD res
= WaitForSingleObject (process_sync
, 5000);
802 if (res
!= WAIT_OBJECT_0
)
803 sigproc_printf ("WFSO failed - %u, %E", res
);
805 sigproc_printf ("synchronized with pid %d", si
.si_pid
);
806 ForceCloseHandle (process_sync
);
808 CloseHandle (tothem
);
809 _my_tls
._ctinfo
->auto_release ();
814 _pinfo::commune_request (__uint32_t code
, ...)
817 commune_result res
= { 0 };
820 HANDLE
& hp
= si
._si_commune
._si_process_handle
;
821 HANDLE
& fromthem
= si
._si_commune
._si_read_handle
;
822 HANDLE request_sync
= NULL
;
829 if (ISSTATE (this, PID_NOTCYGWIN
))
835 va_start (args
, code
);
836 si
._si_commune
._si_code
= code
;
839 case PICOM_PIPE_FHANDLER
:
840 si
._si_commune
._si_pipe_unique_id
= va_arg (args
, int64_t);
844 case PICOM_FILE_PATHCONV
:
845 si
._si_commune
._si_fd
= va_arg (args
, int);
846 si
._si_commune
._si_flags
= va_arg (args
, uint32_t);
853 char name_buf
[MAX_PATH
];
854 request_sync
= CreateSemaphore (&sec_none_nih
, 0, INT32_MAX
,
855 shared_name (name_buf
, "commune", myself
->pid
));
858 ProtectHandle (request_sync
);
860 si
.si_signo
= __SIGCOMMUNE
;
861 if (sig_send (this, si
))
863 ForceCloseHandle (request_sync
); /* don't signal semaphore since there was apparently no receiving process */
877 case PICOM_PIPE_FHANDLER
:
878 case PICOM_FILE_PATHCONV
:
879 if (!ReadPipeOverlapped (fromthem
, &n
, sizeof n
, &nr
, 1000L)
889 res
.s
= (char *) cmalloc_abort (HEAP_COMMUNE
, n
);
892 n
&& ReadPipeOverlapped (fromthem
, p
, n
, &nr
, 1000L);
904 if (!ReadPipeOverlapped (fromthem
, &res
, sizeof res
, &nr
, 1000L)
915 memset (&res
, 0, sizeof (res
));
921 ReleaseSemaphore (request_sync
, 1, &res
);
922 ForceCloseHandle (request_sync
);
927 CloseHandle (fromthem
);
932 _pinfo::pipe_fhandler (int64_t unique_id
, size_t &n
)
936 if (pid
== myself
->pid
)
938 commune_result cr
= commune_request (PICOM_PIPE_FHANDLER
, unique_id
);
940 return (fhandler_pipe
*) cr
.s
;
944 _pinfo::file_pathconv (int fd
, uint32_t flags
, size_t &n
)
948 if (pid
== myself
->pid
)
950 commune_result cr
= commune_request (PICOM_FILE_PATHCONV
, fd
, flags
);
952 return (void *) cr
.s
;
956 _pinfo::fd (int fd
, size_t &n
)
961 if (pid
!= myself
->pid
)
963 commune_result cr
= commune_request (PICOM_FD
, fd
);
969 cygheap_fdget
cfd (fd
);
973 s
= cfd
->get_proc_fd_name ((char *) cmalloc_abort (HEAP_COMMUNE
, NT_MAX_PATH
));
980 _pinfo::fds (size_t &n
)
985 if (pid
!= myself
->pid
)
987 commune_result cr
= commune_request (PICOM_FDS
);
995 cygheap_fdenum
cfd (true);
996 while ((fd
= cfd
.next ()) >= 0)
999 s
= (char *) cmalloc_abort (HEAP_COMMUNE
, n
);
1001 while ((fd
= cfd
.next ()) >= 0 && (char *) p
- s
< (int) n
)
1008 _pinfo::root (size_t& n
)
1013 if (pid
!= myself
->pid
&& !ISSTATE (this, PID_NOTCYGWIN
))
1015 commune_result cr
= commune_request (PICOM_ROOT
);
1021 if (cygheap
->root
.exists ())
1022 s
= cstrdup (cygheap
->root
.posix_path ());
1031 _pinfo::siginfo (sigset_t
&pnd
, sigset_t
&blk
, sigset_t
&ign
)
1037 if (pid
!= myself
->pid
&& !ISSTATE (this, PID_NOTCYGWIN
))
1038 cr
= commune_request (PICOM_SIGINFO
);
1040 cr
= commune_process_siginfo ();
1048 open_commune_proc_parms (DWORD pid
, PRTL_USER_PROCESS_PARAMETERS prupp
)
1052 PROCESS_BASIC_INFORMATION pbi
;
1055 proc
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
| PROCESS_VM_READ
,
1059 status
= NtQueryInformationProcess (proc
, ProcessBasicInformation
,
1060 &pbi
, sizeof pbi
, NULL
);
1061 if (NT_SUCCESS (status
)
1062 && ReadProcessMemory (proc
, pbi
.PebBaseAddress
, &lpeb
, sizeof lpeb
, NULL
)
1063 && ReadProcessMemory (proc
, lpeb
.ProcessParameters
, prupp
, sizeof *prupp
,
1071 _pinfo::cwd (size_t& n
)
1076 if (ISSTATE (this, PID_NOTCYGWIN
))
1078 RTL_USER_PROCESS_PARAMETERS rupp
;
1079 HANDLE proc
= open_commune_proc_parms (dwProcessId
, &rupp
);
1086 PWCHAR cwd
= tp
.w_get ();
1088 if (ReadProcessMemory (proc
, rupp
.CurrentDirectoryName
.Buffer
,
1089 cwd
, rupp
.CurrentDirectoryName
.Length
,
1092 /* Drop trailing backslash, add trailing \0 in passing. */
1093 cwd
[rupp
.CurrentDirectoryName
.Length
/ sizeof (WCHAR
) - 1]
1095 s
= (char *) cmalloc_abort (HEAP_COMMUNE
, NT_MAX_PATH
);
1096 mount_table
->conv_to_posix_path (cwd
, s
, 0);
1101 else if (pid
!= myself
->pid
)
1103 commune_result cr
= commune_request (PICOM_CWD
);
1109 s
= (char *) cmalloc_abort (HEAP_COMMUNE
, NT_MAX_PATH
);
1110 cygheap
->cwd
.get (s
, 1, 1, NT_MAX_PATH
);
1117 _pinfo::cmdline (size_t& n
)
1122 if (ISSTATE (this, PID_NOTCYGWIN
))
1124 RTL_USER_PROCESS_PARAMETERS rupp
;
1125 HANDLE proc
= open_commune_proc_parms (dwProcessId
, &rupp
);
1132 PWCHAR cmdline
= tp
.w_get ();
1134 if (ReadProcessMemory (proc
, rupp
.CommandLine
.Buffer
, cmdline
,
1135 rupp
.CommandLine
.Length
, NULL
))
1137 /* Add trailing \0. */
1138 cmdline
[rupp
.CommandLine
.Length
/ sizeof (WCHAR
)]
1140 n
= sys_wcstombs_alloc (&s
, HEAP_COMMUNE
, cmdline
,
1141 rupp
.CommandLine
.Length
1143 /* Quotes & Spaces post-processing. */
1144 bool in_quote
= false;
1145 for (char *c
= s
; *c
; ++c
)
1147 in_quote
= !in_quote
;
1148 else if (*c
== ' ' && !in_quote
)
1153 else if (pid
!= myself
->pid
)
1155 commune_result cr
= commune_request (PICOM_CMDLINE
);
1162 int argc
= __argv0_orig
? 1 : __argc_safe
;
1164 for (int i
= 0; i
< argc
; ++i
)
1165 n
+= strlen (__argv
[i
]) + 1;
1167 p
= s
= (char *) cmalloc_abort (HEAP_COMMUNE
, n
);
1168 for (int i
= 0; i
< argc
; ++i
)
1169 p
= stpcpy (p
, __argv
[i
]) + 1;
1176 _pinfo::environ (size_t& n
)
1181 if (ISSTATE (this, PID_NOTCYGWIN
))
1183 RTL_USER_PROCESS_PARAMETERS rupp
;
1184 HANDLE proc
= open_commune_proc_parms (dwProcessId
, &rupp
);
1189 MEMORY_BASIC_INFORMATION mbi
;
1192 if (!VirtualQueryEx (proc
, rupp
.Environment
, &mbi
, sizeof(mbi
)))
1199 envsize
= (ptrdiff_t) mbi
.RegionSize
1200 - ((ptrdiff_t) rupp
.Environment
- (ptrdiff_t) mbi
.BaseAddress
);
1201 envblock
= (PWCHAR
) cmalloc_abort (HEAP_COMMUNE
, envsize
);
1203 if (ReadProcessMemory (proc
, rupp
.Environment
, envblock
, envsize
, &read
))
1204 env
= win32env_to_cygenv (envblock
, false);
1208 else if (pid
!= myself
->pid
)
1210 commune_result cr
= commune_request (PICOM_ENVIRON
);
1221 for (char **e
= env
; *e
; e
++)
1222 n
+= strlen (*e
) + 1;
1225 p
= s
= (char *) cmalloc_abort (HEAP_COMMUNE
, n
);
1226 for (char **e
= env
; *e
; e
++)
1227 p
= stpcpy (p
, *e
) + 1;
1231 /* This is the workhorse which waits for the write end of the pipe
1232 created during new process creation. If the pipe is closed or a zero
1233 is received on the pipe, it is assumed that the cygwin pid has exited.
1234 Otherwise, various "signals" can be sent to the parent to inform the
1235 parent to perform a certain action. */
1237 proc_waiter (void *arg
)
1239 pinfo vchild
= *(pinfo
*) arg
;
1240 ((pinfo
*) arg
)->waiter_ready
= true;
1243 si
.si_signo
= SIGCHLD
;
1244 si
.si_code
= CLD_EXITED
;
1245 si
.si_pid
= vchild
->pid
;
1246 #if 0 // FIXME: This is tricky to get right
1247 si
.si_utime
= pchildren
[rc
]->rusage_self
.ru_utime
;
1248 si
.si_stime
= pchildren
[rc
].rusage_self
.ru_stime
;
1250 pid_t pid
= vchild
->pid
;
1251 bool its_me
= vchild
== myself
;
1258 if (!ReadFile (vchild
.rd_proc_pipe
, &buf
, 1, &nb
, NULL
)
1259 && GetLastError () != ERROR_BROKEN_PIPE
)
1261 system_printf ("error on read of child wait pipe %p, %E", vchild
.rd_proc_pipe
);
1265 if (!its_me
&& have_execed_cygwin
)
1268 si
.si_uid
= vchild
->uid
;
1275 /* Child exited. Do some cleanup and signal myself. */
1276 vchild
.maybe_set_exit_code_from_windows ();
1277 if (WIFEXITED (vchild
->exitcode
))
1278 si
.si_code
= CLD_EXITED
;
1279 else if (WCOREDUMP (vchild
->exitcode
))
1280 si
.si_code
= CLD_DUMPED
;
1282 si
.si_code
= CLD_KILLED
;
1283 si
.si_status
= vchild
->exitcode
;
1284 vchild
->process_state
= PID_EXITED
;
1285 /* This should always be last. Do not use vchild-> beyond this point */
1291 if (ISSTATE (myself
, PID_NOCLDSTOP
)) // FIXME: No need for this flag to be in _pinfo any longer
1293 /* Child stopped. Signal myself. */
1294 si
.si_code
= CLD_STOPPED
;
1299 system_printf ("unknown value %d on proc pipe", buf
);
1303 if (its_me
&& ch_spawn
.signal_myself_exited ())
1306 /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
1307 to avoid the proc_subproc lock since the signal thread will eventually
1308 be calling proc_subproc and could unnecessarily block. */
1309 sig_send (myself_nowait
, si
);
1311 /* If we're just stopped or got a continue signal, keep looping.
1312 Otherwise, return this thread to the pool. */
1314 sigproc_printf ("looping");
1319 sigproc_printf ("exiting wait thread for pid %d", pid
);
1320 vchild
.wait_thread
= NULL
;
1321 _my_tls
._ctinfo
->auto_release (); /* automatically return the cygthread to the cygthread pool */
1325 /* function to set up the process pipe and kick off proc_waiter */
1329 preserve (); /* Preserve the shared memory associated with the pinfo */
1331 waiter_ready
= false;
1332 /* Fire up a new thread to track the subprocess */
1333 cygthread
*h
= new cygthread (proc_waiter
, this, "waitproc");
1335 sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid
);
1339 sigproc_printf ("created tracking thread for pid %d, winpid %y, rd_proc_pipe %p",
1340 (*this)->pid
, (*this)->dwProcessId
, rd_proc_pipe
);
1346 /* function to send a "signal" to the parent when something interesting happens
1349 _pinfo::alert_parent (char sig
)
1353 /* Send something to our parent. If the parent has gone away, close the pipe.
1354 Don't send if this is an exec stub.
1356 FIXME: Is there a race here if we run this while another thread is attempting
1358 if (my_wr_proc_pipe
)
1360 if (WriteFile (my_wr_proc_pipe
, &sig
, 1, &nb
, NULL
))
1362 else if (GetLastError () != ERROR_BROKEN_PIPE
)
1363 debug_printf ("sending %d notification to parent failed, %E", sig
);
1367 HANDLE closeit
= my_wr_proc_pipe
;
1368 my_wr_proc_pipe
= NULL
;
1369 ForceCloseHandle1 (closeit
, wr_proc_pipe
);
1380 NtClose (winpid_hdl
);
1384 close_h
= rd_proc_pipe
;
1385 rd_proc_pipe
= NULL
;
1386 ForceCloseHandle1 (close_h
, rd_proc_pipe
);
1392 ForceCloseHandle1 (close_h
, childhProc
);
1398 <sect1 id="func-cygwin-winpid-to-pid">
1399 <title>cygwin_winpid_to_pid</title>
1401 <funcsynopsis><funcprototype>
1402 <funcdef>extern "C" pid_t
1403 <function>cygwin_winpid_to_pid</function>
1405 <paramdef>int <parameter>winpid</parameter></paramdef>
1406 </funcprototype></funcsynopsis>
1408 <para>Given a windows pid, converts to the corresponding Cygwin
1409 pid, if any. Returns -1 if windows pid does not correspond to
1410 a cygwin pid.</para>
1412 <title>Example use of cygwin_winpid_to_pid</title>
1414 extern "C" cygwin_winpid_to_pid (int winpid);
1416 mypid = cygwin_winpid_to_pid (windows_pid);
1424 cygwin_winpid_to_pid (int winpid
)
1426 pinfo
p (cygwin_pid (winpid
));
1435 #define slop_pidlist 200
1436 #define size_pidlist(i) (sizeof (pidlist[0]) * ((i) + 1))
1437 #define size_pinfolist(i) (sizeof (pinfolist[0]) * ((i) + 1))
1449 void no_close_handle (pinfo
& p
)
1454 _onreturn (): h (NULL
) {}
1455 void operator = (HANDLE h0
) {h
= h0
;}
1456 operator HANDLE () const {return h
;}
1460 winpids::add (DWORD
& nelem
, bool winpid
, DWORD pid
)
1462 pid_t cygpid
= cygwin_pid (pid
);
1464 if (nelem
>= npidlist
)
1466 npidlist
+= slop_pidlist
;
1467 pidlist
= (DWORD
*) realloc (pidlist
, size_pidlist (npidlist
+ 1));
1468 pinfolist
= (pinfo
*) realloc ((void *) pinfolist
, size_pinfolist (npidlist
+ 1));
1472 pinfo
& p
= pinfolist
[nelem
];
1473 memset ((void *) &p
, 0, sizeof (p
));
1476 if (cygpid
== myself
->pid
)
1479 perform_copy
= false;
1483 /* Open a process to prevent a subsequent exit from invalidating the
1484 shared memory region. */
1485 onreturn
= OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION
, false, pid
);
1487 /* If we couldn't open the process then we don't have rights to it
1488 and should make a copy of the shared memory area when it exists
1490 perform_copy
= onreturn
? make_copy
: true;
1492 p
.init (cygpid
, PID_PROCINFO
| pinfo_access
, NULL
);
1494 /* Did we catch the process during exec? Try to fix. */
1495 if (p
&& p
->dwProcessId
!= pid
)
1496 pid
= p
->dwProcessId
;
1498 /* If we're just looking for winpids then don't do any special cygwin "stuff* */
1501 perform_copy
= true;
1505 /* !p means that we couldn't find shared memory for this pid. Probably means
1506 that it isn't a cygwin process. */
1509 if (!pinfo_access
|| !cygpid
)
1511 p
.init (cygpid
, PID_PROCINFO
, NULL
);
1517 /* Scan list of previously recorded pids to make sure that this pid hasn't
1518 shown up before. This can happen when a process execs. */
1519 for (unsigned i
= 0; i
< nelem
; i
++)
1520 if (pidlist
[i
] == pid
)
1522 if (p
&& (_pinfo
*) p
!= (_pinfo
*) myself
)
1526 /* If p is "false" then, eventually any opened process handle will be closed
1527 and the function will exit without adding anything to the pid list.
1529 If p is "true" then we've discovered a cygwin process.
1531 Handle "myself" differently. Don't copy it and close/zero the handle we
1532 just opened to it. If not performing a copy, then keep the process handle
1533 open for the duration of the life of the procinfo region to potential
1534 races when a new process uses this pid. Otherwise, malloc some memory
1535 for a copy of the shared memory.
1537 If malloc failed, then "oh well". Just keep the shared memory around
1538 and eventually close the handle when the winpids goes out of scope.
1540 If malloc succeeds, copy the procinfo we just grabbed into the new region,
1541 release the shared memory and allow the handle to be closed when this
1542 function returns. */
1545 if (p
== (_pinfo
*) myself
)
1546 /* handle specially. Close the handle but (eventually) don't
1547 deallocate procinfo in release call */;
1548 else if (!perform_copy
)
1549 onreturn
.no_close_handle (p
); /* Don't close the handle until release */
1552 _pinfo
*pnew
= (_pinfo
*) malloc (sizeof (*p
.procinfo
));
1554 onreturn
.no_close_handle (p
);
1557 *pnew
= *p
.procinfo
;
1562 p
->dwProcessId
= pid
;
1566 /* Add pid to the list and bump the number of elements. */
1568 pidlist
[nelem
++] = pid
;
1572 winpids::enum_processes (bool winpid
)
1580 HANDLE dir
= get_shared_parent_dir ();
1581 BOOLEAN restart
= TRUE
;
1582 bool last_run
= false;
1584 PDIRECTORY_BASIC_INFORMATION dbi_buf
= (PDIRECTORY_BASIC_INFORMATION
)
1588 status
= NtQueryDirectoryObject (dir
, dbi_buf
, 65536, FALSE
, restart
,
1590 if (!NT_SUCCESS (status
))
1592 debug_printf ("NtQueryDirectoryObject, status %y", status
);
1595 if (status
!= STATUS_MORE_ENTRIES
)
1598 for (PDIRECTORY_BASIC_INFORMATION dbi
= dbi_buf
;
1599 dbi
->ObjectName
.Length
> 0;
1602 if (wcsncmp (dbi
->ObjectName
.Buffer
, L
"winpid.", 7) == 0)
1604 DWORD pid
= wcstoul (dbi
->ObjectName
.Buffer
+ 7, NULL
, 10);
1605 add (nelem
, false, pid
);
1612 static DWORD szprocs
;
1613 static PSYSTEM_PROCESS_INFORMATION procs
;
1617 PSYSTEM_PROCESS_INFORMATION new_p
= (PSYSTEM_PROCESS_INFORMATION
)
1618 realloc (procs
, szprocs
+= 200 * sizeof (*procs
));
1621 system_printf ("out of memory reading system process "
1626 NTSTATUS status
= NtQuerySystemInformation (SystemProcessInformation
,
1627 procs
, szprocs
, NULL
);
1628 if (NT_SUCCESS (status
))
1631 if (status
!= STATUS_INFO_LENGTH_MISMATCH
)
1633 system_printf ("error %y reading system process information",
1639 PSYSTEM_PROCESS_INFORMATION px
= procs
;
1642 if (px
->UniqueProcessId
)
1643 add (nelem
, true, (DWORD
) (uintptr_t) px
->UniqueProcessId
);
1644 if (!px
->NextEntryOffset
)
1646 px
= (PSYSTEM_PROCESS_INFORMATION
) ((char *) px
+ px
->NextEntryOffset
);
1653 winpids::set (bool winpid
)
1655 npids
= enum_processes (winpid
);
1661 winpids::enum_init (bool winpid
)
1663 return enum_processes (winpid
);
1670 for (unsigned i
= 0; i
< npids
; i
++)
1671 if (pinfolist
[i
] == (_pinfo
*) myself
)
1673 else if (pinfolist
[i
].hProcess
)
1674 pinfolist
[i
].release ();
1675 else if ((p
= pinfolist
[i
]))
1677 pinfolist
[i
].procinfo
= NULL
;
1682 winpids::~winpids ()