newlib-cygwin/winsup/cygwin/fork.cc

754 lines
21 KiB
C++
Raw Normal View History

2000-02-18 03:38:33 +08:00
/* fork.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
2000-02-18 03:38:33 +08:00
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
2000-02-18 03:38:33 +08:00
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include "security.h"
#include "fhandler.h"
Add "path.h" include throughout, where needed. Use new path_conv methods and operators to simplify testing for directory and attributes, throughout. * path.h (path_conv::exists): New method. (path_conv::has_attribute): Ditto. (path_conv::isdir): Ditto. (path_conv::DWORD &): New operator. (path_conv::int &): Ditto. * dir.cc (rmdir): Eliminate a goto. * dtable.cc (dtable::build_fhandler): Accept opt and suffix info for path_conv.check. Return fh == NULL on path_conv error. Pass unit to set_name as appropriate. (dtable::reset_unix_path_name): New method. * dtable.h (dtable): Declare new method. Reflect arg changes to build_fhandler. * fhandler.cc (fhandler_disk_dummy_name): Eliminate. (fhandler_base::set_name): Expect paths to be NULL. Build unix_path_name from win32_path_name when it is a device. (fhandler_base::reset_unix_path_name): New method. (fhandler_base::raw_read): Report EISDIR when ERROR_INVALID_FUNCTION or ERROR_INVALID_PARAMETER and reading a directory. (fhandler_disk_file::fstat): Don't call stat_dev since we should now never be calling fhandler_disk_file methods with devices. (fhandler_base::fhandler_base): Clear {unix,win32}_path_name. (fhandler_base::~fhandler_base): Always free {unix,win32}_path_name. (fhandler_disk_file::fhandler_disk_file): Remove set_no_free_names kludge. (fhandler_disk_file::open): Ditto. * fhandler.h (fhandler_base::no_free_names): Eliminate. (fhandler_base::set_no_free_names): Ditto. * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Don't set unix_path_name here. * path.cc (fchdir): Lock fd table throughout. Use new dtable::reset_unix_path_name method to reset path. * syscalls.cc (stat_worker): Reorganize to always call fstat method. Pass path_conv method to fhandler_*::open. (chroot): Elminate a goto.
2001-10-01 12:10:07 +08:00
#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
#include "sigproc.h"
#include "pinfo.h"
* Makefile.in: Add cygheap.o. * child_info.h: Add specific exec class. * cygheap.h: New file. Contains declarations for cygwin heap. * cygheap.cc: New file. Implements cygwin heap functions. * dcrt0.cc (quoted): Simplify due to new method for passing arguments between cygwin programs. (alloc_stack_hard_way): Attempt to handle overlapped stack. (dll_crt0_1): Move child_info processing here. Accomodate new method for passing arguments between cygwin programs. Initialize cygwin heap. Establish __argc and __argv variables. (_dll_crt0): Move most of child_info processing to dll_crt0_1. (cygwin_dll_init): Remove duplication. * dtable.cc (dtable::extend): Allocate dtable using cygwin heap. (dtable::build_fhandler): Ditto for fhandler type being constructed. (dtable::dup_worker): Free new fhandler from cygwin heap on error. (dtable::select_*): Don't assume that this == fdtab. (dtable::linearize_fd_array): Delete. (dtable::delinearize_fd_array): Delete. (dtable::fixup_after_exec): New file. (dtable::vfork_child_dup): Use cygwin heap. (dtable::vfork_parent_restore): Ditto. * dtable.h: Remove obsolete methods. Add new method. * environ.cc (posify): Eliminate already_posix parameter and logic. (envsize): New function. (_addenv): Use envsize. (environ_init): Accept an argument pointing to an existing environment list. If supplied, allocate space for this in the the program's heap. * fhandler.cc (fhandler_base::operator =): Move here from fhandler.h. Use cygwin heap to allocate filenames. (fhandler_base::set_name): Allocate/free names from cygwin heap. (fhandler_base::linearize): Delete. (fhandler_base::de_linearize): Delete. (fhandler_base::operator delete): Free from cygwin heap. (fhandler_base::~fhandler_base): Ditto. * fhandler.h: Accomodate elimination of *linearize and other changes above. * fhandler_console.cc (fhandler_console::fixup_after_exec): Rename from de_linearize. * heap.h: New file. * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Use cygwin heap for name. fhandler_tty::fixup_after_exec): Rename from de_linearize. * fork.cc (fork): Call cygheap_fixup_in_child. * heap.cc: Use declarations in heap.h. * malloc.cc: Sprinkle assertions throughout to catch attempts to free/realloc something from the cygwin heap. * path.cc: Throughout, eliminate use of per-thread cache for cwd. Use cwd_* functions rather than cwd_* variables to access cwd_win32 and cwd_posix. (cwd_win32): New function. (cwd_posix): New function. (cwd_hash): New function. (cwd_fixup_after_exec): New function. * path.h: Accomodate path.cc changes. * pinfo.cc (pinfo_init): Accept a pointer to an environment table. Pass this to environ_init. Eliminate old 'title' tests. * pinfo.h: Accomodate above change in argument. * spawn.cc (struct av): New method for building argv list. (av::unshift): New method. (spawn_guts): Allocate everything that the child process needs in the cygwin heap and pass a pointer to this to the child. Build argv list using new method. Eliminate delinearize stuff. * thread.h: Eliminate _cwd_win32 and _cwd_posix buffers. * winsup.h: Eliminate obsolete functions. Add envsize() declaration.
2000-09-03 12:16:35 +08:00
#include "cygheap.h"
#include "child_info.h"
#define NEED_VFORK
#include "perthread.h"
#include "perprocess.h"
#include "dll_init.h"
2000-02-18 03:38:33 +08:00
#ifdef DEBUGGING
static int npid;
static int npid_max;
static pid_t fork_pids[100];
#endif
2000-02-18 03:38:33 +08:00
/* Timeout to wait for child to start, parent to init child, etc. */
/* FIXME: Once things stabilize, bump up to a few minutes. */
#define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */
#define dll_data_start &_data_start__
#define dll_data_end &_data_end__
#define dll_bss_start &_bss_start__
#define dll_bss_end &_bss_end__
void
per_thread::set (void *s)
* Makefile.in: Add cygheap.o. * child_info.h: Add specific exec class. * cygheap.h: New file. Contains declarations for cygwin heap. * cygheap.cc: New file. Implements cygwin heap functions. * dcrt0.cc (quoted): Simplify due to new method for passing arguments between cygwin programs. (alloc_stack_hard_way): Attempt to handle overlapped stack. (dll_crt0_1): Move child_info processing here. Accomodate new method for passing arguments between cygwin programs. Initialize cygwin heap. Establish __argc and __argv variables. (_dll_crt0): Move most of child_info processing to dll_crt0_1. (cygwin_dll_init): Remove duplication. * dtable.cc (dtable::extend): Allocate dtable using cygwin heap. (dtable::build_fhandler): Ditto for fhandler type being constructed. (dtable::dup_worker): Free new fhandler from cygwin heap on error. (dtable::select_*): Don't assume that this == fdtab. (dtable::linearize_fd_array): Delete. (dtable::delinearize_fd_array): Delete. (dtable::fixup_after_exec): New file. (dtable::vfork_child_dup): Use cygwin heap. (dtable::vfork_parent_restore): Ditto. * dtable.h: Remove obsolete methods. Add new method. * environ.cc (posify): Eliminate already_posix parameter and logic. (envsize): New function. (_addenv): Use envsize. (environ_init): Accept an argument pointing to an existing environment list. If supplied, allocate space for this in the the program's heap. * fhandler.cc (fhandler_base::operator =): Move here from fhandler.h. Use cygwin heap to allocate filenames. (fhandler_base::set_name): Allocate/free names from cygwin heap. (fhandler_base::linearize): Delete. (fhandler_base::de_linearize): Delete. (fhandler_base::operator delete): Free from cygwin heap. (fhandler_base::~fhandler_base): Ditto. * fhandler.h: Accomodate elimination of *linearize and other changes above. * fhandler_console.cc (fhandler_console::fixup_after_exec): Rename from de_linearize. * heap.h: New file. * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Use cygwin heap for name. fhandler_tty::fixup_after_exec): Rename from de_linearize. * fork.cc (fork): Call cygheap_fixup_in_child. * heap.cc: Use declarations in heap.h. * malloc.cc: Sprinkle assertions throughout to catch attempts to free/realloc something from the cygwin heap. * path.cc: Throughout, eliminate use of per-thread cache for cwd. Use cwd_* functions rather than cwd_* variables to access cwd_win32 and cwd_posix. (cwd_win32): New function. (cwd_posix): New function. (cwd_hash): New function. (cwd_fixup_after_exec): New function. * path.h: Accomodate path.cc changes. * pinfo.cc (pinfo_init): Accept a pointer to an environment table. Pass this to environ_init. Eliminate old 'title' tests. * pinfo.h: Accomodate above change in argument. * spawn.cc (struct av): New method for building argv list. (av::unshift): New method. (spawn_guts): Allocate everything that the child process needs in the cygwin heap and pass a pointer to this to the child. Build argv list using new method. Eliminate delinearize stuff. * thread.h: Eliminate _cwd_win32 and _cwd_posix buffers. * winsup.h: Eliminate obsolete functions. Add envsize() declaration.
2000-09-03 12:16:35 +08:00
{
if (s == PER_THREAD_FORK_CLEAR)
{
tls = TlsAlloc ();
s = NULL;
}
TlsSetValue (get_tls (), s);
}
2000-02-18 03:38:33 +08:00
static void
stack_base (child_info_fork &ch)
{
MEMORY_BASIC_INFORMATION m;
memset (&m, 0, sizeof m);
if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
system_printf ("couldn't get memory info, %E");
ch.stacktop = m.AllocationBase;
ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize;
ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m;
debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",
ch.stackbottom, ch.stacktop, &m, ch.stacksize,
(DWORD) ch.stackbottom - (DWORD) ch.stacktop);
}
/* Copy memory from parent to child.
The result is a boolean indicating success. */
static int
fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
{
va_list args;
char *low;
int pass = 0;
va_start (args, what);
while ((low = va_arg (args, char *)))
{
char *high = va_arg (args, char *);
DWORD todo = wincap.chunksize () ?: high - low;
2000-02-18 03:38:33 +08:00
char *here;
for (here = low; here < high; here += todo)
{
DWORD done = 0;
if (here + todo > high)
todo = high - here;
int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);
debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,
low, high, res);
if (!res || todo != done)
{
if (!res)
__seterrno ();
/* If this happens then there is a bug in our fork
implementation somewhere. */
system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",
what, pass, low, high, done, pi.dwProcessId);
2000-02-18 03:38:33 +08:00
goto err;
}
}
pass++;
}
debug_printf ("done");
return 1;
err:
2000-02-18 03:38:33 +08:00
TerminateProcess (pi.hProcess, 1);
set_errno (EAGAIN);
return 0;
}
/* Wait for child to finish what it's doing and signal us.
We don't want to wait forever here.If there's a problem somewhere
it'll hang the entire system (since all forks are mutex'd). If we
time out, set errno = EAGAIN and hope the app tries again. */
static int
sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
BOOL hang_child, const char *s)
{
/* We also add the child process handle to the wait. If the child fails
to initialize (eg. because of a missing dll). Then this
handle will become signalled. This stops a *looong* timeout wait.
*/
HANDLE w4[2];
debug_printf ("waiting for child. reason: %s, hang_child %d", s,
hang_child);
2000-02-18 03:38:33 +08:00
w4[1] = pi.hProcess;
w4[0] = subproc_ready;
DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);
if (rc == WAIT_OBJECT_0 ||
WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
/* That's ok */;
else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
if (rc != WAIT_FAILED)
system_printf ("WaitForMultipleObjects timed out");
else
system_printf ("WaitForMultipleObjects failed, %E");
set_errno (EAGAIN);
syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");
TerminateProcess (pi.hProcess, 1);
return 0;
}
else
{
/* Child died. Clean up and exit. */
DWORD errcode;
GetExitCodeProcess (pi.hProcess, &errcode);
/* Fix me. This is not enough. The fork should not be considered
* to have failed if the process was essentially killed by a signal.
*/
if (errcode != STATUS_CONTROL_C_EXIT)
{
system_printf ("child %d(%p) died before initialization with status code %p",
pi.dwProcessId, pi.hProcess, errcode);
system_printf ("*** child state %s", s);
#ifdef DEBUGGING
abort ();
#endif
}
set_errno (EAGAIN);
syscall_printf ("Child died before subproc_ready signalled");
return 0;
}
debug_printf ("child signalled me");
return 1;
}
static int
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
2000-02-18 03:38:33 +08:00
{
SetEvent (forker_finished);
debug_printf ("signalled child");
return 1;
2000-02-18 03:38:33 +08:00
}
/* Notify parent that it is time for the next step.
Note that this has to be a macro since the parent may be messing with
our stack. */
static void __stdcall
sync_with_parent(const char *s, bool hang_self)
2000-02-18 03:38:33 +08:00
{
debug_printf ("signalling parent: %s", s);
/* Tell our parent we're waiting. */
if (!SetEvent (child_proc_info->subproc_ready))
api_fatal ("fork child - SetEvent for %s failed, %E", s);
if (hang_self)
{
HANDLE h = child_proc_info->forker_finished;
/* Wait for the parent to fill in our stack and heap.
Don't wait forever here. If our parent dies we don't want to clog
the system. If the wait fails, we really can't continue so exit. */
DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
debug_printf ("awake");
switch (psync_rc)
{
case WAIT_TIMEOUT:
api_fatal ("WFSO timed out for %s", s);
break;
case WAIT_FAILED:
if (GetLastError () == ERROR_INVALID_HANDLE &&
WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED)
break;
api_fatal ("WFSO failed for %s, fork_finished %p, %E", s,
2001-11-05 14:09:15 +08:00
child_proc_info->forker_finished);
break;
default:
debug_printf ("no problems");
break;
}
}
2000-02-18 03:38:33 +08:00
}
static int __stdcall
fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
2000-02-18 03:38:33 +08:00
{
debug_printf ("child is running. pid %d, ppid %d, stack here %p",
myself->pid, myself->ppid, __builtin_frame_address (0));
/* Restore the inheritance state as in parent
Don't call setuid here! The flags are already set. */
if (cygheap->user.impersonated)
{
debug_printf ("Impersonation of child, token: %d", cygheap->user.token);
if (cygheap->user.token == INVALID_HANDLE_VALUE)
RevertToSelf (); // probably not needed
else if (!ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonate for forked child failed: %E");
}
2000-02-18 03:38:33 +08:00
sync_with_parent ("after longjmp.", TRUE);
ProtectHandle (hParent);
sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d\n", hParent,
first_dll, load_dlls);
2000-02-18 03:38:33 +08:00
#ifdef DEBUGGING
char c;
if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
try_to_debug ();
char buf[80];
/* This is useful for debugging fork problems. Use gdb to attach to
the pid reported here. */
if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
{
small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
Sleep (atoi(buf));
}
#endif
2000-02-18 03:38:33 +08:00
/* If we've played with the stack, stacksize != 0. That means that
fork() was invoked from other than the main thread. Make sure that
when the "main" thread exits it calls do_exit, like a normal process.
Exit with a status code of 0. */
if (child_proc_info->stacksize)
{
((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
}
2000-02-18 03:38:33 +08:00
set_file_api_mode (current_codepage);
MALLOC_CHECK;
2000-02-18 03:38:33 +08:00
debug_fixup_after_fork ();
* exceptions.cc (set_console_handler): Don't allocate console_handler_thread_waiter. It is obsolete. (ctrl_c_handler): Don't use console_handler_thread_waiter. * path.cc (hash_path_name): Fix handling of relative names. Make case insensitive. * path.h (suffix_info): Use initializers. * pinfo.h (_pinfo): Avoid initializers for null case. * resource.cc (fill_rusage): Zero rest of rusage structure. * security.cc (set_process_privileges): Don't reopen parent process. Just use hMainProc. * signal.cc (signal): Track when a signal handler has been used. (sigaction): Ditto. * sigproc.cc (pchildren): Use default initializer. (zombies): Ditto. (sigproc_terminate): Avoid closing handles that will be closed on exit anyway. (wait_sig): Send signal to "parent" on EXECing, not FORKing. (wait_subproc): Send SIGCHLD here rather than in proc_wait to avoid potential muto conflicts. * sigproc.h (sigthread): Don't initialize to zero. It's the default. * spawn.cc (spawn_guts): Fill in resources from exec parent prior to termination. * sync.h (muto): Don't initialize to zero. * syscalls.cc (close_all_files): Use one lock around entire loop and call fhandler close/release stuff directly. (_read): Don't use ready_for_read if there are not signal handlers active. * dcrt0.cc (dll_crt0_1): Fix display of "title". (do_exit): Use pinfo exit method to exit. (__api_fatal): Ditto. * exceptions.cc (signal_exit): Ditto. * fork.cc (fork_child): Remove debugging stuff. Use pinfo_fixup_after fork in place of exec_fixup_after_fork. * pinfo.cc (pinfo_fixup_after_fork): New method. (pinfo_fixup_in_spawned_child): Ditto. (_pinfo::exit): New method. (_pinfo::init): Remove recursion. Detect pathological case where pinfo structure already exists for new pid. * pinfo.h (_pinfo): Reorganize slightly. Add new method and new function declarations. * sigproc.cc (proc_exists): Previous simplification was a little to simple. Try harder to detect if a process exists. (proc_terminate): Use PID_EXITED setting to determine if process is still around. (WFSO): Remove debugging statement. (WFMO): Ditto. * spawn.cc (exec_fixup_after_fork): Eliminate. (spawn_guts): Always set old_title to NULL. Is it really needed? Move hexec_proc to pinfo.cc. Call pinfo_fixup_in_spawned_child to eliminate handle link after a spawn. * include/sys/cygwin.h: Remove PID_NOT_IN_USE. Add PID_EXITED.
2000-10-15 09:37:07 +08:00
pinfo_fixup_after_fork ();
cygheap->fdtab.fixup_after_fork (hParent);
signal_fixup_after_fork ();
MALLOC_CHECK;
if (fixup_mmaps_after_fork (hParent))
api_fatal ("recreate_mmaps_after_fork_failed");
/* If we haven't dynamically loaded any dlls, just signal
the parent. Otherwise, load all the dlls, tell the parent
that we're done, and wait for the parent to fill in the.
loaded dlls' data/bss. */
if (!load_dlls)
sync_with_parent ("performed fork fixup.", FALSE);
else
2000-02-18 03:38:33 +08:00
{
dlls.load_after_fork (hParent, first_dll);
sync_with_parent ("loaded dlls", TRUE);
2000-02-18 03:38:33 +08:00
}
ForceCloseHandle (hParent);
(void) ForceCloseHandle (child_proc_info->subproc_ready);
(void) ForceCloseHandle (child_proc_info->forker_finished);
2002-02-28 Robert Collins <rbtcollins@hotmail.com> * Merged cygwin_daemon into head minus the new shm and ipc exports. 2002-02-28 Robert Collins <rbtcollins@hotmail.com> * fhandler_tty.cc (fhandler_tty_slave::open): More debugging. (fhandler_tty_slave::read): Fix printf type for the handle. * tty.cc (tty::common_init): Add a FIXME for security. 2002-01-29 Robert Collins <rbtcollins@hotmail.com> * Makefile.in (OBJS): Remove duplicate localtime.o. 2002-01-17 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (check_and_dup_handle): Consolidate the two variants for simplicity. Add Some basic debug output. (client_request_attach_tty::serve): Use the new debug_printf for clarity. Mark the duplicated handles as inheritable - fixup_after_fork() doesn't reopen tty's. 2002-01-16 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (transport): Correct scope. (client_request_attach_tty::serve): Add more debug information. Fix erroneous use of transport instead of conn. * cygserver_transport_pipes.cc (transport_layer_pipes::close): More debug. (transport_layer_pipes::read): Ditto. (transport_layer_pipes::write): Ditto. (transport_layer_pipes::impersonate_client): Ditto. Mon Oct 8 7:41:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (server_request::process): Rename client_request_shm_get to client_request_shm. * cygserver_process.cc (process_cache::add): Rename to add_task. Use process_cleanup instead of process_request. (process_cache::remove_process): New method. (process::process): Initialize new members. (process::~process): New member. (process::cleanup): New method. (process::add_cleanup_routine): New method. (process_request::process): Rename to process_cleanup. Call the process object's cleanup method and then delete it. (process_process_param::request_loop): Remove the signalling process. * cygserver_shm.cc: Globally rename client_request_shm_get to client_request_shm. (client_request_shm_get::serve): Handle attach request counting. * cygserver_shm.h: Globally rename client_request_shm_get to client_request_shm. (class shm_cleanup): New class. * shm.cc: Globally rename client_request_shm_get to client_request_shm. (client_request_shm::client_request_shm): New constructor for attach requests. (shmat): Use it. * include/cygwin/cygserver_process.h (class process_request): Rename to process_cleanup. (class cleanup_routine): New class. (class process): New members and methods to allow calling back when the process terminates. Thu Oct 4 14:12:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (request_loop): Make static. (main): Use new cache constructor syntax. Start cache worker threads. Cleanup the cache at shutdown. * cygserver_process.cc: Run indent. (process_cache::process_cache): Add a trigger to use when adding a process. (process_cache::process): Move process_entry to process. Insert at the end of the list. Trigger the request loop when new process's inserted. (process_cache::process_requests): Do it. (process_cache::add): New method. (process_cache::handle_snapshot): New method. (process::process): Merge in the process_entry fields. (process::handle): Make a stub function. (process::exit_code): New method. (process_request::process): New method. (process_process_param::request_loop): New method. * cygserver_shm.cc: New header dependency - threaded_queue.h. * threaded_queue.cc (threaded_queue::cleanup): Clearer messages. (queue_process_param::stop): Short spinlock on interruptible threads. * threaded_queue.h (class threaded_queue): New constructor. * include/cygwin/cygserver_process.h (process_request): New class. (process_entry): Remove. (process): Merge in process_entry. (process_cache): Inherit from threaded_queue. Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (class server_process_param): Use new constructor syntax. * cygserver_process.cc (process_cache::~process_cache): New function. * threaded_queue.cc: Define condition debug_printf. Run indent. (threaded_queue::cleanup): Move queue_process_param guts to a method. (threaded_queue::process_requests): Ditto. (queue_process_param::queue_process_param): New method. (queue_process_param::~queue_process_param): Ditto. (queue_process_param::start): Ditto. (queue_process_param::stop): Ditto. * threaded_queue.h (class queue_process_param): Add support for interruptible request loops. * cygwin/include/cygwin/cygserver_process.h (class process_cache): Add destructor. Tue Oct 2 23:24:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver_client.cc: New flag allow_daemon to disable the daemon completely. (cygserver_request): Check it. (cygserver_init): Ditto. * environ.cc (parse_thing): Add (no)daemon option. Tue Oct 2 23:00:00 2001 Robert Collins <rbtcollins@hotmail.com> * shm.cc: Update to handle include changes from HEAD. Tue Oct 2 16:06:00 2001 Robert Collins <rbtcollins@hotmail.com> * Makefile.in: Remove cygserver_shm.o from cygwin1.dll. Rename cygserver_shm_outside.o to cygserver_shm.o. * cygserver.cc (server_request::process): Use the new client_request constructor. * cygserver_client.cc: Remove the #ifdef's stubs for the server method within cygwin. (client_request_attach_tty::client_request_attach_tty): Use the new client_request constructor. (client_request_shutdown::client_request_shutdown): Ditto. (client_request::client_request): Ditto. * cygserver_shm.cc (client_request_shm_get::serve): Remove the #ifdef'd stub for in-cygwin builds. (client_request_shm_get::client_request_shm_get): Use the new client_request constructor, and remove the in-cygwin variants. * cygserver_shm.h (class client_request_shm_get): #ifndef test the serve method - it's only used in cygserver. * shm.cc (client_request_shm_get::client_request_shm_get): New function. * include/cygwin/cygserver.h (request_header): New constructor. (class client_request): Use it. New constructor accepting the header size. #ifndef test the server method - it's only used within cygserver. (client_request_get_version): #ifdef test the server method. (client_request_shutdown): Ditto. (client_request_attach_tty): Ditto. Tue Oct 2 9:57:00 2001 Robert Collins <rbtcollins@hotmail.com> * Makefile.in: add threaded_queue.o to cygserver.exe. * cygserver.cc: Include threaded_queue.h (class server_request): Inherit from queue_request. (class server_process_param): Inherit from queue_process_param. (class server_request_queue): Inherit from threaded_queue. (request_loop): Adjust for new types. (server_request_queue::process_requests): Remove guts to threaded_queue::process_requests. (server_request::server_request): Adjust for new types. (worker_function): Delete. (server_request_queue::create_workers): Delete. (server_request_queue::cleanup): Delete. (server_request_queue::add): Move guts to threaded_queue::add. * threaded_queue.cc: New file. * threaded_queue.h: New file. Mon Oct 1 12:38:00 2001 Robert Collins <rbtcollins@hotmail.com> * cygserver.cc (client_request::serve): New function. * cygserver_process.cc: Inlude <pthread.h> for pthread_once. (process_cache::process_cache): Initialise a crtiical section for write access. (process_cache::process): Use the critical section. Also add missing entries to the cache. (do_process_init): New function to initalise class process static variables. (process::process): Ensure that the process access critical section is initialised. (process::handle): Close the handle of old process's when they have terminated and we are returning the handle for a process with the same pid. * cygserver_shm.cc: Run indent. Include cygserver_process.h to allow process cache functionality. (client_request_shm_get::serve): New parameter for process cache support. Use the process cache, not OpenProcess to get a handle to the originating process. Fix a handle leak with token_handle. * cygserver_shm.h (class client_request_shm_get): Update ::serve for process cache support. * cygserver_transport_pipes.cc: Redefine debug_printf to be conditional on DEBUG. * include/cygwin/cygserver.h: Do not implement client_request::serve in the header. * include/cygwin/cygserver_process.h (class process_cache): Add a write access critical section to prevent races when requests from a multithreaded application arrive. Sun Sep 30 23:41:00 2001 Robert Collins <rbtcollins@hotmail.com> * Makefile.in: Add cygserver_process.o to cygserver.exe. * cygserver.cc: Include signal.h and cygwin_version.h. Define debug_printf as a macro. Define DEBUG to a value. (client_request_attach_tty::serve): Add beginning of process cache support. Change from #ifdef DEBUG to work with new DEBUG style. (client_request_get_version::serve): Add beginning of process cache support. (class server_request): New prototype for support of process cache. (class queue_process_param): New class to allow request loop threading. (class server_request_queue): Add beginning of process cache support. Allow request loop threading. (request_loop): Thread function for request loops. (server_request_queue::process_requests): Initiator for threaded request loops. (client_request_shutdown::serve): Add beginning of process cache support. (server_request::server_request): Ditto. (server_request::process): Use debug_printf. Add beginning of process cache support. (server_request_queue::cleanup): Kill off any request loop threads. (server_request_queue::add): Add beginning of process cache support. (handle_signal): Trigger a shutdown. (main): Print out some useful info at startup - version, date time. Add process cache support. Spawn a separate thread for the transport request loop, thus allowing concurrent support for multiple transports. * cygserver_client.cc (client_request_get_version::serve): Add process cache support. (client_request_attach_tty::serve): Add process cache support. (client_request_shutdown::serve): Add process cache support. * cygsserver_process.cc: New file with the process cache support. * cygserver_shm.cc: Redefine debug_printf to allow conditional output. * cygwin.din: Export shmdt(). * shm.cc: Run indent. Update FIXME's. (shmdt): New function. * include/cygwin/cygserver.h (class client_request): Add process cache support. (class client_request_get_version): Ditto. (class client_request_shutdown): Ditto. (class client_request_attach_tty): Ditto. * include/cygwin/cygserver_process.h: New header for process cache support. Sun Sep 30 8:52:00 2001 Robert Collins <rbtcollins@hotmail.com> * include/cygwin/cygserver_transport.h: Add copyright header. * include/cygwin/cygserver_transport_pipes.h: Ditto. * include/cygwin/cygserver_transport_sockets.h: Ditto. Sat Sep 29 20:40:00 2001 Robert Collins <rbtcollins@hotmail.com> * Makefile.in: Add cygserver_transport_sockets.o to DLL_OFILES. Add cygserver_transport_sockets_outside.o to cygserver.exe. * cygserver.cc: Include new include files. * cygserver_client.cc: Ditto. * cygserver_shm.h: No need to include <sys/socket.h> now. * cygerver_transport.cc: Include new include files. (transport_layer_base::transport_layer_base): Strip back to a stub. (transport_layer_base::listen): Ditto. (transport_layer_base::accept): Ditto. (transport_layer_base::close): Ditto. (transport_layer_base::read): Ditto. (transport_layer_base::write): Ditto. (transport_layer_base::connect): Ditto. * cygserver_transport_pipes.cc: Include new header "cygwin/cygserver_transport_pipes.h". * cygserver_transport_sockets.cc: New file. * dcrt0.cc: No need to include <sys/socket.h> now. * fhandler_tty.cc: Ditto. * tty.cc: Ditto. * include/cygwin/cygserver_transport.h: Strip the base class to a stub. Remove the cygserver_transport_pipes class. * include/cygwin/cygserver_transport_pipes.h: New file. * include/cygwin/cygserver_transport_sockets.h: New file. Tue Sep 25 16:22:00 2001 Robert Collins <rbtcollins@hotmail.com> * autoload.cc: Add dynamic load statement for 'ImpersonateNamedPipeClient'. * Makefile.in: Add new object files, and build instructions for cygserver.exe. * cygwin.din: Export ftok, shmat, shmctl and shmget. * dcrt0.cc: Additional includes for cygserver support. (dll_crt0_1): Initialise the cygserver client. * fhandler.h (fhandler_tty): New method cygserver_attach_tty. * fhandler_tty.cc: Additional includes for cygserver support. (fhandler_tty_slave::open): Attempt to use the cygserver when obtaining handles from the parent process. On failure or 9x use the current method. (fhandler_tty_slave::cygserver_attach_tty): New function. * fork.cc (fork_child): Fixup shm memory mapped areas. * pinfo.h: Declare fixup_shms_after_fork(). * security.h: Declare alloc_sd(). * tty.cc: Additonal includes to support cygserver. (tty::common_init): Don't allow others to open us if the cygserver is running. * winsup.h: Declare cygserver_running. * cygserver.cc: New file. * cygserver_client.cc: New file. * cygserver_shm.cc: New file. * cygserver_shm.h: New file. * cygserver_transport.cc: New file. * cygserver_transport_pipes.cc: New file. * ipc.cc: New file. * shm.cc: New file. * include/cygwin/cygserver.h: New file. * include/cygwin/cygserver_transport.h: New file. * include/sys/ipc.h: New file. * include/sys/shm.h: New file. 2002-02-28 Robert Collins <rbtcollins@hotmail.com> * thread.cc (semaphore::TryWait): Set errno as required by posix 1003.1. (__sem_wait): Ditto. (__sem_trywait): Ditto.
2002-02-28 22:30:38 +08:00
if (fixup_shms_after_fork ())
api_fatal ("recreate_shm areas after fork failed");
/* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
non-zero, for some reason.
FIXME: There is a memory leak here after a fork. */
for (per_thread **t = threadstuff; *t; t++)
if ((*t)->clear_on_fork ())
(*t)->set ();
2000-02-18 03:38:33 +08:00
user_data->threadinterface->fixup_after_fork ();
/* Initialize signal/process handling */
sigproc_init ();
__pthread_atforkchild ();
* Makefile.in: Remove some obsolete stuff. * dcrt0.cc (dll_crt0_1): Call signal_fixup_after_exec where appropriate. Set myself->uid from parent version. Just use ThreadItem Init method. Close or store hexec_proc as appropriate. (_dll_crt0): Store user_data->forkee here so that proper tests can be made subsequently. (do_exit): Remove hExeced stuff. * environ.cc (environ_init): Accept environ count as well as environ pointer. * environ.h: Reflect above change. * pinfo.cc (pinfo_init): Ditto. Accept environ count. (fixup_in_spawned_child): Remove. * spawn.cc (spawn_guts): Move signal code to dll_crt0_1. Don't suspend execing process since it is no longer necessary. Store envc. * exceptions.cc (signal_fixup_after_exec): New function. (call_handler): Remove hExeced test. * child_info.h (cygheap_exec_info): Store envc as well as envp. (child_info_spawn): Store hexec_proc so that it can be closed in child. * path.cc (normalize_posix_path): Avoid intermediate use of temporary cwd buf. (normalize_win32_path): Ditto. (cwdstuff::get_initial): Always set lock. * sigproc.h: Remove hExeced. * strace.cc (strace::vsprntf): Modify to accomodate for lack of hExeced. * thread.cc (MTinterface::Init): Merge Init1 and ClearReent into this method. (MTinterface::Init1): Eliminate. (MTinterface::ClearReent): Eliminate. * thread.h: Reflect above changes. * include/sys/strace.h (strace): Make microseconds() public. Make various functions 'regparm', throughout. * pinfo.h (_pinfo): Inline simple signal manipulation functions. Requires inclusion of thread.h which was removed from .cc files, where appropriate. throughout. * pinfo.cc: Eliminate signal manipulation functions. (_pinfo::exit): Calculate total rusage for exiting process here. * cygheap.cc (size2bucket): Eliminate. (init_buckets): Ditto. (_cmalloc): Calculate size and bits in a loop rather than going through a function call. (_crealloc): Use stored array index to calculate allocated size. * spawn.cc (spawn_guts): Use _pinfo exit method to exit, calculating cpu usage.
2000-10-17 07:55:58 +08:00
cygbench ("fork-child");
return 0;
}
2000-02-18 03:38:33 +08:00
static void
slow_pid_reuse (HANDLE h)
{
2000-11-16 13:21:03 +08:00
static NO_COPY HANDLE last_fork_procs[8] = {0};
static NO_COPY unsigned nfork_procs = 0;
if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
nfork_procs = 0;
/* Keep a list of handles to forked 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 (hMainProc, h, hMainProc, &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++;
}
static int __stdcall
fork_parent (HANDLE& hParent, dll *&first_dll,
bool& load_dlls, void *stack_here, child_info_fork &ch)
{
HANDLE subproc_ready, forker_finished;
DWORD rc;
PROCESS_INFORMATION pi = {0, NULL, 0, 0};
2000-02-18 03:38:33 +08:00
/* call the pthread_atfork prepare functions */
__pthread_atforkprepare ();
subproc_init ();
2000-02-18 03:38:33 +08:00
#ifdef DEBUGGING_NOTNEEDED
/* The ProtectHandle call allocates memory so we need to make sure
that enough is set aside here so that the sbrk pointer does not
move when ProtectHandle is called after the child is started.
Otherwise the sbrk pointers in the parent will not agree with
the child and when user_data is (regrettably) copied over,
the user_data->ptr field will not be accurate. */
free (malloc (4096));
2000-02-18 03:38:33 +08:00
#endif
int c_flags = GetPriorityClass (hMainProc) /*|
CREATE_NEW_PROCESS_GROUP*/;
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
/* If we don't have a console, then don't create a console for the
child either. */
HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
FILE_SHARE_WRITE, &sec_none_nih,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);
if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
CloseHandle (console_handle);
else
c_flags |= DETACHED_PROCESS;
2000-02-18 03:38:33 +08:00
* dtable.cc (dtable::release): Check for socket. Change cnt_need_fixup_before accordingly. (dtable::dup2): Ditto. (dtable::fixup_before_fork): New method. (dtable::fixup_before_exec): Ditto. * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add definition for methods `dec_need_fixup_before', `inc_need_fixup_before', `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. * fhandler.h (class fhandler_base): Slight rearrangements. Add definitions for methods `fixup_before_fork_exec'. (class fhandler_socket): Eliminate superfluous constructor. Add member `prot_info_ptr'. Add destructor. Add definitions for methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and `fixup_after_exec'. * fork.cc (fork_parent): Care for file types which need a fixup before fork. Start child in suspended state then. * net.cc: New global variable `ws2_32_handle' and `wsadata'. (fdsock): Check for Winsock version. Call `set_socket_inheritance' only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. (cygwin_socket): Eliminate call to `set_socket_inheritance'. (cygwin_accept): Ditto. (cygwin_rcmd): Ditto. (cygwin_rresvport): Ditto. (cygwin_rexec): Ditto. (socketpair): Ditto. (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate space for the WSAPROTOCOL_INFOA struct used in fixup. (fhandler_socket::~fhandler_socket): New destructor. (fhandler_socket::fixup_before_fork_exec): New method. (fhandler_socket::fixup_after_fork): Ditto. (fhandler_socket::dup): Ditto. (wsock_init): New static function. (LoadDLLinitfunc (wsock32)): Rearranged. (LoadDLLinitfunc (ws2_32)): New function. (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' and `WSASocketA'. * spawn.cc (spawn_guts): Care for file types which need a fixup before exec. Start child in suspended state then.
2000-10-26 18:13:41 +08:00
/* Some file types (currently only sockets) need extra effort in the
parent after CreateProcess and before copying the datastructures
to the child. So we have to start the child in suspend state,
unfortunately, to avoid a race condition. */
if (cygheap->fdtab.need_fixup_before ())
* dtable.cc (dtable::release): Check for socket. Change cnt_need_fixup_before accordingly. (dtable::dup2): Ditto. (dtable::fixup_before_fork): New method. (dtable::fixup_before_exec): Ditto. * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add definition for methods `dec_need_fixup_before', `inc_need_fixup_before', `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. * fhandler.h (class fhandler_base): Slight rearrangements. Add definitions for methods `fixup_before_fork_exec'. (class fhandler_socket): Eliminate superfluous constructor. Add member `prot_info_ptr'. Add destructor. Add definitions for methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and `fixup_after_exec'. * fork.cc (fork_parent): Care for file types which need a fixup before fork. Start child in suspended state then. * net.cc: New global variable `ws2_32_handle' and `wsadata'. (fdsock): Check for Winsock version. Call `set_socket_inheritance' only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. (cygwin_socket): Eliminate call to `set_socket_inheritance'. (cygwin_accept): Ditto. (cygwin_rcmd): Ditto. (cygwin_rresvport): Ditto. (cygwin_rexec): Ditto. (socketpair): Ditto. (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate space for the WSAPROTOCOL_INFOA struct used in fixup. (fhandler_socket::~fhandler_socket): New destructor. (fhandler_socket::fixup_before_fork_exec): New method. (fhandler_socket::fixup_after_fork): Ditto. (fhandler_socket::dup): Ditto. (wsock_init): New static function. (LoadDLLinitfunc (wsock32)): Rearranged. (LoadDLLinitfunc (ws2_32)): New function. (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' and `WSASocketA'. * spawn.cc (spawn_guts): Care for file types which need a fixup before exec. Start child in suspended state then.
2000-10-26 18:13:41 +08:00
c_flags |= CREATE_SUSPENDED;
/* Create an inheritable handle to pass to the child process. This will
allow the child to duplicate handles from the parent to itself. */
hParent = NULL;
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
DUPLICATE_SAME_ACCESS))
{
system_printf ("couldn't create handle to myself for child, %E");
return -1;
}
2000-02-18 03:38:33 +08:00
/* Remember the address of the first loaded dll and decide
if we need to load dlls. We do this here so that this
information will be available in the parent and, when
the stack is copied, in the child. */
first_dll = dlls.start.next;
load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
2000-02-18 03:38:33 +08:00
/* This will help some of the confusion. */
fflush (stdout);
2000-02-18 03:38:33 +08:00
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (subproc_ready == NULL)
{
CloseHandle (hParent);
system_printf ("unable to allocate subproc_ready event, %E");
return -1;
}
forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (forker_finished == NULL)
{
CloseHandle (hParent);
CloseHandle (subproc_ready);
system_printf ("unable to allocate forker_finished event, %E");
return -1;
}
2000-02-18 03:38:33 +08:00
ProtectHandle (subproc_ready);
ProtectHandle (forker_finished);
2000-02-18 03:38:33 +08:00
init_child_info (PROC_FORK, &ch, 1, subproc_ready);
2000-02-18 03:38:33 +08:00
ch.forker_finished = forker_finished;
2000-02-18 03:38:33 +08:00
stack_base (ch);
2000-02-18 03:38:33 +08:00
si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE)&ch;
si.cbReserved2 = sizeof(ch);
2000-02-18 03:38:33 +08:00
/* Remove impersonation */
if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
RevertToSelf ();
2000-02-18 03:38:33 +08:00
ch.parent = hParent;
#ifdef DEBUGGING
if (npid_max)
{
for (int pass = 0; pass < 2; pass++)
{
pid_t pid;
while ((pid = fork_pids[npid++]))
if (!pinfo (pid))
{
ch.cygpid = pid;
goto out;
}
npid = 0;
}
}
out:
#endif
2000-02-18 03:38:33 +08:00
char sa_buf[1024];
PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf);
syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)",
myself->progname, myself->progname, c_flags, &si, &pi);
__malloc_lock (_reent_clib ());
void *newheap;
newheap = cygheap_setup_for_child (&ch,cygheap->fdtab.need_fixup_before ());
rc = CreateProcess (myself->progname, /* image to run */
myself->progname, /* what we send in arg0 */
sec_attribs,
sec_attribs,
TRUE, /* inherit handles from parent */
c_flags,
NULL, /* environment filled in later */
0, /* use current drive/directory */
&si,
&pi);
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-30 00:24:59 +08:00
CloseHandle (hParent);
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-30 00:24:59 +08:00
if (!rc)
{
__seterrno ();
syscall_printf ("CreateProcessA failed, %E");
ForceCloseHandle(subproc_ready);
ForceCloseHandle(forker_finished);
/* Restore impersonation */
if (cygheap->user.impersonated
&& cygheap->user.token != INVALID_HANDLE_VALUE)
ImpersonateLoggedOnUser (cygheap->user.token);
cygheap_setup_for_child_cleanup (newheap, &ch, 0);
return -1;
}
* dtable.cc (dtable::release): Check for socket. Change cnt_need_fixup_before accordingly. (dtable::dup2): Ditto. (dtable::fixup_before_fork): New method. (dtable::fixup_before_exec): Ditto. * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add definition for methods `dec_need_fixup_before', `inc_need_fixup_before', `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. * fhandler.h (class fhandler_base): Slight rearrangements. Add definitions for methods `fixup_before_fork_exec'. (class fhandler_socket): Eliminate superfluous constructor. Add member `prot_info_ptr'. Add destructor. Add definitions for methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and `fixup_after_exec'. * fork.cc (fork_parent): Care for file types which need a fixup before fork. Start child in suspended state then. * net.cc: New global variable `ws2_32_handle' and `wsadata'. (fdsock): Check for Winsock version. Call `set_socket_inheritance' only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. (cygwin_socket): Eliminate call to `set_socket_inheritance'. (cygwin_accept): Ditto. (cygwin_rcmd): Ditto. (cygwin_rresvport): Ditto. (cygwin_rexec): Ditto. (socketpair): Ditto. (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate space for the WSAPROTOCOL_INFOA struct used in fixup. (fhandler_socket::~fhandler_socket): New destructor. (fhandler_socket::fixup_before_fork_exec): New method. (fhandler_socket::fixup_after_fork): Ditto. (fhandler_socket::dup): Ditto. (wsock_init): New static function. (LoadDLLinitfunc (wsock32)): Rearranged. (LoadDLLinitfunc (ws2_32)): New function. (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' and `WSASocketA'. * spawn.cc (spawn_guts): Care for file types which need a fixup before exec. Start child in suspended state then.
2000-10-26 18:13:41 +08:00
/* Fixup the parent datastructure if needed and resume the child's
main thread. */
if (!cygheap->fdtab.need_fixup_before ())
cygheap_setup_for_child_cleanup (newheap, &ch, 0);
else
* dtable.cc (dtable::release): Check for socket. Change cnt_need_fixup_before accordingly. (dtable::dup2): Ditto. (dtable::fixup_before_fork): New method. (dtable::fixup_before_exec): Ditto. * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add definition for methods `dec_need_fixup_before', `inc_need_fixup_before', `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. * fhandler.h (class fhandler_base): Slight rearrangements. Add definitions for methods `fixup_before_fork_exec'. (class fhandler_socket): Eliminate superfluous constructor. Add member `prot_info_ptr'. Add destructor. Add definitions for methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and `fixup_after_exec'. * fork.cc (fork_parent): Care for file types which need a fixup before fork. Start child in suspended state then. * net.cc: New global variable `ws2_32_handle' and `wsadata'. (fdsock): Check for Winsock version. Call `set_socket_inheritance' only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. (cygwin_socket): Eliminate call to `set_socket_inheritance'. (cygwin_accept): Ditto. (cygwin_rcmd): Ditto. (cygwin_rresvport): Ditto. (cygwin_rexec): Ditto. (socketpair): Ditto. (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate space for the WSAPROTOCOL_INFOA struct used in fixup. (fhandler_socket::~fhandler_socket): New destructor. (fhandler_socket::fixup_before_fork_exec): New method. (fhandler_socket::fixup_after_fork): Ditto. (fhandler_socket::dup): Ditto. (wsock_init): New static function. (LoadDLLinitfunc (wsock32)): Rearranged. (LoadDLLinitfunc (ws2_32)): New function. (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' and `WSASocketA'. * spawn.cc (spawn_guts): Care for file types which need a fixup before exec. Start child in suspended state then.
2000-10-26 18:13:41 +08:00
{
cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
cygheap_setup_for_child_cleanup (newheap, &ch, 1);
* dtable.cc (dtable::release): Check for socket. Change cnt_need_fixup_before accordingly. (dtable::dup2): Ditto. (dtable::fixup_before_fork): New method. (dtable::fixup_before_exec): Ditto. * dtable.h (class dtable): Add member `cnt_need_fixup_before'. Add definition for methods `dec_need_fixup_before', `inc_need_fixup_before', `need_fixup_before', `fixup_before_exec' and `fixup_before_fork'. * fhandler.h (class fhandler_base): Slight rearrangements. Add definitions for methods `fixup_before_fork_exec'. (class fhandler_socket): Eliminate superfluous constructor. Add member `prot_info_ptr'. Add destructor. Add definitions for methods `dup', `fixup_before_fork_exec', `fixup_after_fork' and `fixup_after_exec'. * fork.cc (fork_parent): Care for file types which need a fixup before fork. Start child in suspended state then. * net.cc: New global variable `ws2_32_handle' and `wsadata'. (fdsock): Check for Winsock version. Call `set_socket_inheritance' only if Winsock version < 2.0. Care for `need_fixup' count in fdtab. (cygwin_socket): Eliminate call to `set_socket_inheritance'. (cygwin_accept): Ditto. (cygwin_rcmd): Ditto. (cygwin_rresvport): Ditto. (cygwin_rexec): Ditto. (socketpair): Ditto. (fhandler_socket::fhandler_socket): Set `need_fork_fixup'. Allocate space for the WSAPROTOCOL_INFOA struct used in fixup. (fhandler_socket::~fhandler_socket): New destructor. (fhandler_socket::fixup_before_fork_exec): New method. (fhandler_socket::fixup_after_fork): Ditto. (fhandler_socket::dup): Ditto. (wsock_init): New static function. (LoadDLLinitfunc (wsock32)): Rearranged. (LoadDLLinitfunc (ws2_32)): New function. (dummy_autoload): Add autoload statemants for `WSADuplicateSocketA' and `WSASocketA'. * spawn.cc (spawn_guts): Care for file types which need a fixup before exec. Start child in suspended state then.
2000-10-26 18:13:41 +08:00
ResumeThread (pi.hThread);
}
#ifdef DEBUGGING
pinfo forked ((ch.cygpid != 1 ? ch.cygpid : cygwin_pid (pi.dwProcessId)), 1);
#else
pinfo forked (cygwin_pid (pi.dwProcessId), 1);
#endif
2000-02-18 03:38:33 +08:00
/* Initialize things that are done later in dll_crt0_1 that aren't done
for the forkee. */
strcpy(forked->progname, myself->progname);
2000-02-18 03:38:33 +08:00
/* Restore impersonation */
if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
ImpersonateLoggedOnUser (cygheap->user.token);
2000-02-18 03:38:33 +08:00
ProtectHandle (pi.hThread);
/* Protect the handle but name it similarly to the way it will
be called in subproc handling. */
ProtectHandle1 (pi.hProcess, childhProc);
/* Fill in fields in the child's process table entry. */
forked->hProcess = pi.hProcess;
forked->dwProcessId = pi.dwProcessId;
forked->copysigs(myself);
/* Hopefully, this will succeed. The alternative to doing things this
way is to reserve space prior to calling CreateProcess and then fill
it in afterwards. This requires more bookkeeping than I like, though,
so we'll just do it the easy way. So, terminate any child process if
we can't actually record the pid in the internal table. */
if (!forked.remember ())
{
TerminateProcess (pi.hProcess, 1);
set_errno (EAGAIN);
goto cleanup;
}
slow_pid_reuse (pi.hProcess);
/* Wait for subproc to initialize itself. */
if (!sync_with_child (pi, subproc_ready, TRUE, "waiting for longjmp"))
goto cleanup;
/* CHILD IS STOPPED */
debug_printf ("child is alive (but stopped)");
/* Initialize, in order: data, bss, heap, stack, dll data, dll bss
Note: variables marked as NO_COPY will not be copied
since they are placed in a protected segment. */
2000-02-18 03:38:33 +08:00
MALLOC_CHECK;
rc = fork_copy (pi, "user/cygwin data",
user_data->data_start, user_data->data_end,
user_data->bss_start, user_data->bss_end,
cygheap->heapbase, cygheap->heapptr,
stack_here, ch.stackbottom,
dll_data_start, dll_data_end,
dll_bss_start, dll_bss_end, NULL);
2000-02-18 03:38:33 +08:00
__malloc_unlock (_reent_clib ());
MALLOC_CHECK;
if (!rc)
goto cleanup;
2000-02-18 03:38:33 +08:00
/* Now fill data/bss of any DLLs that were linked into the program. */
for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
{
debug_printf ("copying data/bss of a linked dll");
if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
d->p.bss_start, d->p.bss_end,
NULL))
2000-02-18 03:38:33 +08:00
goto cleanup;
}
/* Start thread, and wait for it to reload dlls. */
if (!resume_child (pi, forker_finished) ||
!sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
goto cleanup;
2000-02-18 03:38:33 +08:00
/* If DLLs were loaded in the parent, then the child has reloaded all
of them and is now waiting to have all of the individual data and
bss sections filled in. */
if (load_dlls)
{
/* CHILD IS STOPPED */
/* write memory of reloaded dlls */
for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
2000-02-18 03:38:33 +08:00
{
debug_printf ("copying data/bss for a loaded dll");
if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
d->p.bss_start, d->p.bss_end,
NULL))
goto cleanup;
2000-02-18 03:38:33 +08:00
}
/* Start the child up again. */
(void) resume_child (pi, forker_finished);
2000-02-18 03:38:33 +08:00
}
ForceCloseHandle (subproc_ready);
ForceCloseHandle (pi.hThread);
ForceCloseHandle (forker_finished);
forker_finished = NULL;
pi.hThread = NULL;
__pthread_atforkparent ();
2000-02-18 03:38:33 +08:00
return forked->pid;
2000-02-18 03:38:33 +08:00
/* Common cleanup code for failure cases */
cleanup:
2000-02-18 03:38:33 +08:00
/* Remember to de-allocate the fd table. */
if (pi.hProcess)
ForceCloseHandle1 (pi.hProcess, childhProc);
if (pi.hThread)
ForceCloseHandle (pi.hThread);
if (subproc_ready)
ForceCloseHandle (subproc_ready);
if (forker_finished)
ForceCloseHandle (forker_finished);
return -1;
}
extern "C" int
fork ()
2000-02-18 03:38:33 +08:00
{
struct
{
HANDLE hParent;
dll *first_dll;
bool load_dlls;
} grouped;
MALLOC_CHECK;
sigframe thisframe (mainthread);
debug_printf ("entering");
grouped.hParent = grouped.first_dll = NULL;
grouped.load_dlls = 0;
if (ISSTATE(myself, PID_SPLIT_HEAP))
{
system_printf ("The heap has been split, CYGWIN can't fork this process.");
system_printf ("Increase the heap_chunk_size in the registry and try again.");
set_errno (ENOMEM);
syscall_printf ("-1 = fork (), split heap");
return -1;
}
void *esp;
__asm__ volatile ("movl %%esp,%0": "=r" (esp));
myself->set_has_pgid_children ();
child_info_fork ch;
int res = setjmp (ch.jmp);
if (res)
res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
else
res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, esp, ch);
MALLOC_CHECK;
syscall_printf ("%d = fork()", res);
return res;
2000-02-18 03:38:33 +08:00
}
#ifdef DEBUGGING
void
fork_init ()
{
char buf[1024];
if (!GetEnvironmentVariable ("CYGWIN_FORK_PIDS", buf, 1024))
return;
pid_t pid;
char *p, *pe;
for (p = buf; (pid = strtol (p, &pe, 10)); p = pe)
fork_pids[npid_max++] = pid;
}
#endif /*DEBUGGING*/
2000-02-18 03:38:33 +08:00
#ifdef NEWVFORK
/* Dummy function to force second assignment below to actually be
carried out */
static vfork_save *
get_vfork_val ()
{
return vfork_storage.val ();
}
#endif
extern "C"
int
vfork ()
{
#ifndef NEWVFORK
return fork ();
#else
sigframe thisframe;
2000-02-18 03:38:33 +08:00
vfork_save *vf = get_vfork_val ();
char **esp, **pp;
2000-02-18 03:38:33 +08:00
if (vf == NULL)
vf = vfork_storage.create ();
else if (vf->pid)
return fork ();
2000-02-18 03:38:33 +08:00
if (!setjmp (vf->j))
{
vf->pid = -1;
__asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
2000-02-18 03:38:33 +08:00
__asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
for (pp = (char **)vf->frame, esp = vf->vfork_esp;
esp <= vf->vfork_ebp + 2; pp++, esp++)
*pp = *esp;
int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
debug_printf ("%d = vfork()", res);
* dcrt0.cc (dll_crt0_1): Don't close hexec_proc if it is NULL. * fork.cc (vfork): Add debugging statements. * path.cc (get_device_number): Make static. Rewrite to inspect both unix and windows paths. (get_raw_device_number): Just check for parts of raw device that we care about. (get_devn): New function, pulled from get_device_number. (win32_device_name): Accomodate arg changes to get_device_number. (mount_info::get_device_number): Call get_device_number on translated Windows path. * spawn.cc (spawn_guts): Don't treat P_VFORK differently from P_NOWAIT. Add handle to child's shared region to child so that it will be preserved if the parent goes away. * fhandler.h: Throughout, simplify to one open method for all fhandler classes, requiring a path_conv first element. * fhandler.cc (fhandler_base::open): Remove obsolete method. Generalize to require path_conv * as first argument. (fhandler_disk_file::open): Remove obsolete method. (fhandler_disk_file::open): Use path_conv pointer rather than reference. * fhandler_clipboard.cc (fhandler_dev_clipboard::dup): Use new open method. (fhandler_dev_clipboard::open): Accomodate new argument for open methods. * fhandler_console.cc (fhandler_console::open): Ditto. (fhandler_console::dup): Use new open method. (fhandler_console::fixup_after_fork): Ditto. (fhandler_console::fixup_after_exec): Ditto. * fhandler_dsp.cc (fhandler_dev_dsp::open): Accomodate new argument for open methods. * fhandler_floppy.cc (fhandler_dev_floppy::open): Ditto. * fhandler_mem.cc (fhandler_dev_mem::open): Ditto. * fhandler_random (fhandler_dev_random::open): Ditto. * fhandler_raw.cc (fhandler_dev_raw::open): Ditto. * fhandler_serial.cc (fhandler_serial::open): Ditto. * fhandler_tape.cc (fhandler_dev_tape::open): Ditto. * fhandler_tty.cc (fhandler_tty_slave::open): Ditto. (fhandler_pty_master::open): Ditto. * fhandler_windows.cc (fhandler_windows::open): Ditto. * fhandler_zero.cc (fhandler_dev_zero::open): Ditto. * fhandler_socket.cc (fhandler_socket::set_connect_secret): Accomodate new argument for open methods. * syscalls.cc (_open): Ditto. (stat_worker): Ditto.
2001-10-04 10:34:20 +08:00
debug_printf ("exiting vfork, res %d", res);
return res;
2000-02-18 03:38:33 +08:00
}
vf = get_vfork_val ();
for (pp = (char **)vf->frame, esp = vf->vfork_esp;
esp <= vf->vfork_ebp + 2; pp++, esp++)
*esp = *pp;
thisframe.init (mainthread);
cygheap->fdtab.vfork_parent_restore ();
2000-02-18 03:38:33 +08:00
if (vf->pid < 0)
{
int exitval = -vf->pid;
2001-09-14 12:39:56 +08:00
vf->pid = 0;
2000-02-18 03:38:33 +08:00
if ((vf->pid = fork ()) == 0)
exit (exitval);
}
int pid = vf->pid;
vf->pid = 0;
* dcrt0.cc (dll_crt0_1): Don't close hexec_proc if it is NULL. * fork.cc (vfork): Add debugging statements. * path.cc (get_device_number): Make static. Rewrite to inspect both unix and windows paths. (get_raw_device_number): Just check for parts of raw device that we care about. (get_devn): New function, pulled from get_device_number. (win32_device_name): Accomodate arg changes to get_device_number. (mount_info::get_device_number): Call get_device_number on translated Windows path. * spawn.cc (spawn_guts): Don't treat P_VFORK differently from P_NOWAIT. Add handle to child's shared region to child so that it will be preserved if the parent goes away. * fhandler.h: Throughout, simplify to one open method for all fhandler classes, requiring a path_conv first element. * fhandler.cc (fhandler_base::open): Remove obsolete method. Generalize to require path_conv * as first argument. (fhandler_disk_file::open): Remove obsolete method. (fhandler_disk_file::open): Use path_conv pointer rather than reference. * fhandler_clipboard.cc (fhandler_dev_clipboard::dup): Use new open method. (fhandler_dev_clipboard::open): Accomodate new argument for open methods. * fhandler_console.cc (fhandler_console::open): Ditto. (fhandler_console::dup): Use new open method. (fhandler_console::fixup_after_fork): Ditto. (fhandler_console::fixup_after_exec): Ditto. * fhandler_dsp.cc (fhandler_dev_dsp::open): Accomodate new argument for open methods. * fhandler_floppy.cc (fhandler_dev_floppy::open): Ditto. * fhandler_mem.cc (fhandler_dev_mem::open): Ditto. * fhandler_random (fhandler_dev_random::open): Ditto. * fhandler_raw.cc (fhandler_dev_raw::open): Ditto. * fhandler_serial.cc (fhandler_serial::open): Ditto. * fhandler_tape.cc (fhandler_dev_tape::open): Ditto. * fhandler_tty.cc (fhandler_tty_slave::open): Ditto. (fhandler_pty_master::open): Ditto. * fhandler_windows.cc (fhandler_windows::open): Ditto. * fhandler_zero.cc (fhandler_dev_zero::open): Ditto. * fhandler_socket.cc (fhandler_socket::set_connect_secret): Accomodate new argument for open methods. * syscalls.cc (_open): Ditto. (stat_worker): Ditto.
2001-10-04 10:34:20 +08:00
debug_printf ("exiting vfork, pid %d", pid);
sig_dispatch_pending ();
return pid;
2000-02-18 03:38:33 +08:00
#endif
}