* hinfo.cc (hinfo::linearize_fd_array): Make max_used_fd an int so that we can

detect when there are no fds to pass.
* dcrt0.cc (host_dependent_constants::init): Revert Sat Mar 18 01:32:04 2000
change.
(dll_crt0_1): Set "cygwin_finished_initializing" flag.
(dll_crt0): Don't perform memcpy if uptr is already set to internal structure.
(_dll_crt0): Remember location of programs envptr.
* dll_init.h (per_module, dll, dll_list): Revamp.
* dll_init.cc: Revamp.  Use new classes.
* fork.cc (fork): Use new revamped dll, dll_list, and per_module stuff.
* environ.cc: Use __cygwin_environ throughout rather than the
user_data->envptr.
* exec.cc: Ditto.
* spawn.cc: Ditto.
* winsup.h: Declare update_envptrs, cygwin_finished_initializing.
* lib/_cygwin_crt0_common.cc (_cygwin_crt0_common): Revert previous change.
* lib/cygwin_attach_dll.cc (cygwin_attach_dll): Always pass in own per_process
structure or we end up overwriting information from the main program.
This commit is contained in:
Christopher Faylor 2000-07-15 02:48:11 +00:00
parent 44d2afed74
commit 2eb392bd77
13 changed files with 427 additions and 496 deletions

View File

@ -1,3 +1,27 @@
Fri Jul 14 22:40:22 2000 Christopher Faylor <cgf@cygnus.com>
* hinfo.cc (hinfo::linearize_fd_array): Make max_used_fd an int so that
we can detect when there are no fds to pass.
* dcrt0.cc (host_dependent_constants::init): Revert Sat Mar 18 01:32:04
2000 change.
(dll_crt0_1): Set "cygwin_finished_initializing" flag.
(dll_crt0): Don't perform memcpy if uptr is already set to internal
structure.
(_dll_crt0): Remember location of programs envptr.
* dll_init.h (per_module, dll, dll_list): Revamp.
* dll_init.cc: Revamp. Use new classes.
* fork.cc (fork): Use new revamped dll, dll_list, and per_module stuff.
* environ.cc: Use __cygwin_environ throughout rather than the
user_data->envptr.
* exec.cc: Ditto.
* spawn.cc: Ditto.
* winsup.h: Declare update_envptrs, cygwin_finished_initializing.
* lib/_cygwin_crt0_common.cc (_cygwin_crt0_common): Revert previous
change.
* lib/cygwin_attach_dll.cc (cygwin_attach_dll): Always pass in own
per_process structure or we end up overwriting information from the
main program.
Wed Jul 12 00:46:00 2000 Christopher Faylor <cgf@cygnus.com>
* debug.cc (thread_stub): Use impure_ptr in place of reent_data.

View File

@ -40,6 +40,7 @@ BOOL strip_title_path = FALSE;
BOOL allow_glob = TRUE;
HANDLE NO_COPY parent_alive = NULL;
int cygwin_finished_initializing = 0;
/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t.
This is subtracted from the signal number prior to shifting the bit.
@ -49,10 +50,8 @@ HANDLE NO_COPY parent_alive = NULL;
measure to allow an orderly transfer to the new, correct sigmask method. */
unsigned int signal_shift_subtract = 1;
#ifdef _MT_SAFE
ResourceLocks _reslock NO_COPY;
MTinterface _mtinterf NO_COPY;
#endif
extern "C"
{
@ -64,6 +63,7 @@ extern "C"
/* This is an exported copy of environ which can be used by DLLs
which use cygwin.dll. */
char **__cygwin_environ;
char ***main_environ;
/* __progname used in getopt error message */
char *__progname = NULL;
struct _reent reent_data;
@ -192,7 +192,7 @@ host_dependent_constants::init ()
{
case winNT:
win32_upper = 0xffffffff;
shared = FILE_SHARE_READ | FILE_SHARE_WRITE;
shared = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break;
case win98:
@ -699,16 +699,8 @@ dll_crt0_1 ()
of the calls below (eg. uinfo_init) do stdio calls - this area must
be set to zero before then. */
#ifdef _MT_SAFE
user_data->threadinterface->ClearReent();
user_data->threadinterface->Init1();
#else
memset (&reent_data, 0, sizeof (reent_data));
reent_data._errno = 0;
reent_data._stdin = reent_data.__sf + 0;
reent_data._stdout = reent_data.__sf + 1;
reent_data._stderr = reent_data.__sf + 2;
#endif
char *line = GetCommandLineA ();
@ -734,7 +726,10 @@ dll_crt0_1 ()
/* beyond this we only do for cygwin apps or dlls */
if (dynamically_loaded)
return;
{
cygwin_finished_initializing = 1;
return;
}
/* Initialize signal/subprocess handling. */
sigproc_init ();
@ -766,15 +761,14 @@ dll_crt0_1 ()
/* Set up __progname for getopt error call. */
__progname = argv[0];
/* Call init of loaded dlls. */
DllList::the().initAll();
set_errno (0);
/* Flush signals and ensure that signal thread is up and running. Can't
do this for noncygwin case since the signal thread is blocked due to
LoadLibrary serialization. */
sig_send (NULL, __SIGFLUSH); /* also initializes uid, gid */
sig_send (NULL, __SIGFLUSH);
cygwin_finished_initializing = 1;
/* Call init of loaded dlls. */
dlls.init ();
/* Execute any specified "premain" functions */
if (user_data->premain[PREMAIN_LEN / 2])
@ -782,6 +776,9 @@ dll_crt0_1 ()
user_data->premain[i] (argc, argv);
debug_printf ("user_data->main %p", user_data->main);
set_errno (0);
if (user_data->main)
exit (user_data->main (argc, argv, *user_data->envptr));
}
@ -806,6 +803,7 @@ _dll_crt0 ()
}
#endif
main_environ = user_data->envptr;
user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
set_console_handler ();
@ -874,7 +872,7 @@ void
dll_crt0 (per_process *uptr)
{
/* Set the local copy of the pointer into the user space. */
if (uptr)
if (uptr && uptr != user_data)
{
memcpy (user_data, uptr, per_process_overwrite);
*(user_data->impure_ptr_ptr) = &reent_data;

View File

@ -183,13 +183,12 @@ dlopen (const char *name, int)
if (!name)
{
// handle for the current module
ret = (void *) GetModuleHandle (0);
ret = (void *) GetModuleHandle (NULL);
}
else
{
// handle for the named library
const char *fullpath = get_full_path_of_dll (name);
DllList::the().currentDlOpenedLib (fullpath);
ret = (void *) LoadLibrary (fullpath);
}

View File

@ -13,65 +13,28 @@ details. */
extern void __stdcall check_sanity_and_sync (per_process *);
#ifdef _MT_SAFE
extern ResourceLocks _reslock NO_COPY;
extern MTinterface _mtinterf NO_COPY;
#endif /*_MT_SAFE*/
dll_list NO_COPY dlls;
/* WARNING: debug can't be called before init !!!! */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// the private structure
typedef enum { NONE, LINK, LOAD } dllType;
struct dll
{
per_process p;
HMODULE handle;
const char *name;
dllType type;
};
static NO_COPY int in_forkee = 0;
/* local variables */
//-----------------------------------------------------------------------------
#define MAX_DLL_BEFORE_INIT 100 // FIXME: enough ???
static dll _list_before_init[MAX_DLL_BEFORE_INIT];
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// local variables
static DllList _the;
static int _last = 0;
static int _max = MAX_DLL_BEFORE_INIT;
static dll *_list = _list_before_init;
static int _initCalled = 0;
static int _numberOfOpenedDlls = 0;
static int _forkeeMustReloadDlls = 0;
static int _in_forkee = 0;
static const char *_dlopenedLib = 0;
static int _dlopenIndex = -1;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static int __dll_global_dtors_recorded = 0;
static int dll_global_dtors_recorded = 0;
/* Run destructors for all DLLs on exit. */
static void
__dll_global_dtors()
dll_global_dtors()
{
_the.doGlobalDestructorsOfDlls();
for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
d->p.run_dtors ();
}
static void
doGlobalCTORS (per_process *p)
/* Run all constructors associated with a dll */
void
per_module::run_ctors ()
{
void (**pfunc)() = p->ctors;
void (**pfunc)() = ctors;
/* Run ctors backwards, so skip the first entry and find how many
there are, then run them. */
@ -86,230 +49,160 @@ doGlobalCTORS (per_process *p)
}
}
static void
doGlobalDTORS (per_process *p)
/* Run all destructors associated with a dll */
void
per_module::run_dtors ()
{
if (!p)
return;
void (**pfunc)() = p->dtors;
void (**pfunc)() = dtors;
for (int i = 1; pfunc[i]; i++)
(pfunc[i]) ();
}
#define INC 500
static int
add (HMODULE h, char *name, per_process *p, dllType type)
/* Initialize an individual DLL */
int
dll::init ()
{
int ret = -1;
if (p)
check_sanity_and_sync (p);
if (_last == _max)
{
if (!_initCalled) // we try to load more than MAX_DLL_BEFORE_INIT
{
small_printf ("try to load more dll than max allowed=%d\n",
MAX_DLL_BEFORE_INIT);
ExitProcess (1);
}
dll* newArray = new dll[_max+INC];
if (_list)
{
memcpy (newArray, _list, _max * sizeof (dll));
if (_list != _list_before_init)
delete []_list;
}
_list = newArray;
_max += INC;
}
_list[_last].name = name && type == LOAD ? strdup (name) : NULL;
_list[_last].handle = h;
_list[_last].p = *p;
_list[_last].type = type;
ret = _last++;
return ret;
}
static int
initOneDll (per_process *p)
{
/* FIXME: init environment (useful?) */
*(p->envptr) = *(user_data->envptr);
/* FIXME: need other initializations? */
int ret = 1;
if (!_in_forkee)
/* Why didn't we just import this variable? */
*(p.envptr) = __cygwin_environ;
/* Don't run constructors or the "main" if we've forked. */
if (!in_forkee)
{
/* global contructors */
doGlobalCTORS (p);
p.run_ctors ();
/* entry point of dll (use main of per_process with null args...) */
if (p->main)
ret = (*(p->main)) (0, 0, 0);
if (p.main)
ret = (*(p.main)) (0, 0, 0);
}
return ret;
}
DllList&
DllList::the ()
/* Look for a dll based on name */
dll *
dll_list::operator[] (const char *name)
{
return _the;
dll *d = &start;
while ((d = d->next) != NULL)
if (strcasematch (name, d->name))
return d;
return NULL;
}
#define RETRIES 100
/* Allocate space for a dll struct after the just-loaded dll. */
dll *
dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
{
char name[MAX_PATH + 1];
DWORD namelen = GetModuleFileName (h, name, sizeof (name));
/* Already loaded? */
dll *d = dlls[name];
if (d)
{
d->count++; /* Yes. Bump the usage count. */
return d; /* Return previously allocated pointer. */
}
int i;
void *s = p->bss_end;
MEMORY_BASIC_INFORMATION m;
/* Search for space after the DLL */
for (i = 0; i <= RETRIES; i++)
{
if (!VirtualQuery (s, &m, sizeof (m)))
return NULL; /* Can't do it. */
if (m.State == MEM_FREE)
break;
s = (char *) m.BaseAddress + m.RegionSize;
}
/* Couldn't find any. Uh oh. FIXME: Issue an error? */
if (i == RETRIES)
return NULL; /* Oh well */
SYSTEM_INFO s1;
GetSystemInfo (&s1);
/* Need to do the shared memory thing since W95 can't allocate in
the shared memory region otherwise. */
HANDLE h1 = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none_nih,
PAGE_READWRITE, 0, sizeof (dll), NULL);
DWORD n = (DWORD) m.BaseAddress;
n = ((n - (n % s1.dwAllocationGranularity)) + s1.dwAllocationGranularity);
d = (dll *) MapViewOfFileEx (h1, FILE_MAP_WRITE, 0, 0, 0, (void *) n);
CloseHandle (h1);
/* Now we've allocated a block of information. Fill it in with the supplied
info about this DLL. */
d->count = 1;
d->namelen = namelen;
strcpy (d->name, name);
d->handle = h;
d->p = p;
d->type = type;
if (end == NULL)
end = &start; /* Point to "end" of dll chain. */
end->next = d; /* Standard linked list stuff. */
d->next = NULL;
d->prev = end;
end = d;
tot++;
if (type == DLL_LOAD)
loaded_dlls++;
return d;
}
/* Detach a DLL from the chain. */
void
DllList::currentDlOpenedLib (const char *name)
dll_list::detach (dll *d)
{
if (_dlopenedLib != 0)
small_printf ("WARNING: previous dlopen of %s wasn't correctly performed\n", _dlopenedLib);
_dlopenedLib = name;
_dlopenIndex = -1;
}
int
DllList::recordDll (HMODULE h, per_process *p)
{
int ret = -1;
/* debug_printf ("Record a dll p=%p\n", p); see WARNING */
dllType type = LINK;
if (_initCalled)
{
type = LOAD;
_numberOfOpenedDlls++;
forkeeMustReloadDlls (1);
}
if (_in_forkee)
{
ret = 0; // Just a flag
goto out;
}
char buf[MAX_PATH];
GetModuleFileName (h, buf, MAX_PATH);
if (type == LOAD && _dlopenedLib !=0)
{
// it is not the current dlopened lib
// so we insert one empty lib to preserve place for current dlopened lib
if (!strcasematch (_dlopenedLib, buf))
{
if (_dlopenIndex == -1)
_dlopenIndex = add (0, 0, 0, NONE);
ret = add (h, buf, p, type);
}
else // it is the current dlopened lib
{
if (_dlopenIndex != -1)
{
_list[_dlopenIndex].handle = h;
_list[_dlopenIndex].p = *p;
_list[_dlopenIndex].type = type;
ret = _dlopenIndex;
_dlopenIndex = -1;
}
else // it this case the dlopened lib doesn't need other lib
ret = add (h, buf, p, type);
_dlopenedLib = 0;
}
}
else
ret = add (h, buf, p, type);
out:
if (_initCalled) // main module is already initialized
{
if (!initOneDll (p))
ret = -1;
}
return ret;
if (d->count <= 0)
system_printf ("WARNING: try to detach an already detached dll ...\n");
else if (--d->count == 0)
{
d->p.run_dtors ();
d->prev->next = d->next;
if (d->next)
d->next->prev = d->prev;
if (d->type == DLL_LOAD)
loaded_dlls--;
if (end == d)
end = d->prev;
UnmapViewOfFile (d);
}
}
/* Initialization called by dll_crt0_1. */
void
DllList::detachDll (int dll_index)
dll_list::init ()
{
if (dll_index != -1)
debug_printf ("here");
/* Make sure that destructors are called on exit. */
if (!dll_global_dtors_recorded)
{
dll *aDll = &(_list[dll_index]);
doGlobalDTORS (&aDll->p);
if (aDll->type == LOAD)
_numberOfOpenedDlls--;
aDll->type = NONE;
}
else
small_printf ("WARNING: try to detach an already detached dll ...\n");
}
void
DllList::initAll ()
{
// init for destructors
// because initAll isn't called in forked process, this exit function will
// be recorded only once
if (!__dll_global_dtors_recorded)
{
atexit (__dll_global_dtors);
__dll_global_dtors_recorded = 1;
atexit (dll_global_dtors);
dll_global_dtors_recorded = 1;
}
if (!_initCalled)
{
debug_printf ("call to DllList::initAll");
for (int i = 0; i < _last; i++)
{
per_process *p = &_list[i].p;
if (p)
initOneDll (p);
}
_initCalled = 1;
}
}
void
DllList::doGlobalDestructorsOfDlls ()
{
// global destructors in reverse order
for (int i = _last - 1; i >= 0; i--)
{
if (_list[i].type != NONE)
{
per_process *p = &_list[i].p;
if (p)
doGlobalDTORS (p);
}
}
}
int
DllList::numberOfOpenedDlls ()
{
return _numberOfOpenedDlls;
}
int
DllList::forkeeMustReloadDlls ()
{
return _forkeeMustReloadDlls;
}
void
DllList::forkeeMustReloadDlls (int i)
{
_forkeeMustReloadDlls = i;
/* Walk the dll chain, initializing each dll */
dll *d = &start;
while ((d = d->next))
d->init ();
}
#define A64K (64 * 1024)
/* Mark every memory address up to "here" as reserved. This may force
Windows NT to load a DLL in the next available, lowest slot. */
void
static void
reserve_upto (const char *name, DWORD here)
{
DWORD size;
@ -334,7 +227,7 @@ reserve_upto (const char *name, DWORD here)
/* Release all of the memory previously allocated by "upto" above.
Note that this may also free otherwise reserved memory. If that becomes
a problem, we'll have to keep track of the memory that we reserve above. */
void
static void
release_upto (const char *name, DWORD here)
{
DWORD size;
@ -354,87 +247,68 @@ release_upto (const char *name, DWORD here)
}
}
#define MAX_DLL_SIZE (sizeof (dll))
/* Reload DLLs after a fork. Iterates over the list of dynamically loaded DLLs
and attempts to load them in the same place as they were loaded in the parent. */
void
DllList::forkeeLoadDlls ()
dll_list::load_after_fork (HANDLE parent, dll *first)
{
_initCalled = 1;
_in_forkee = 1;
in_forkee = 1;
int try2 = 0;
for (int i = 0; i < _last; i++)
if (_list[i].type == LOAD)
{
const char *name = _list[i].name;
HMODULE handle = _list[i].handle;
HMODULE h = LoadLibraryEx (name, NULL, DONT_RESOLVE_DLL_REFERENCES);
dll d;
if (h == handle)
{
FreeLibrary (h);
LoadLibrary (name);
}
else if (try2)
api_fatal ("unable to remap %s to same address as parent -- %p", name, h);
else
{
FreeLibrary (h);
reserve_upto (name, (DWORD) handle);
try2 = 1;
i--;
continue;
}
if (try2)
{
release_upto (name, (DWORD) handle);
try2 = 0;
}
}
_in_forkee = 0;
}
void *next = first;
while (next)
{
DWORD nb;
/* Read the dll structure from the parent. */
if (!ReadProcessMemory (parent, next, &d, MAX_DLL_SIZE, &nb) ||
nb != MAX_DLL_SIZE)
return;
/* We're only interested in dynamically loaded dlls.
Hopefully, this function wouldn't even have been called unless
the parent had some of those. */
if (d.type == DLL_LOAD)
{
HMODULE h = LoadLibraryEx (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// iterators
DllListIterator::DllListIterator (int type) : _type (type), _index (-1)
{
operator++ ();
}
DllListIterator::~DllListIterator ()
{
}
DllListIterator::operator per_process* ()
{
return &_list[index ()].p;
}
void
DllListIterator::operator++ ()
{
_index++;
while (_index < _last && (int) (_list[_index].type) != _type)
_index++;
if (_index == _last)
_index = -1;
}
LinkedDllIterator::LinkedDllIterator () : DllListIterator ((int) LINK)
{
}
LinkedDllIterator::~LinkedDllIterator ()
{
}
LoadedDllIterator::LoadedDllIterator () : DllListIterator ((int) LOAD)
{
}
LoadedDllIterator::~LoadedDllIterator ()
{
/* See if DLL will load in proper place. If so, free it and reload
it the right way.
It sort of stinks that we can't invert the order of the FreeLibrary
and LoadLibrary since Microsoft documentation seems to imply that that
should do what we want. However, since the library was loaded above,
The second LoadLibrary does not execute it's startup code unless it
is first unloaded. */
if (h == d.handle)
{
FreeLibrary (h);
LoadLibrary (d.name);
}
else if (try2)
api_fatal ("unable to remap %s to same address as parent -- %p", d.name, h);
else
{
/* It loaded in the wrong place. Dunno why this happens but it always
seems to happen when there are multiple DLLs attempting to load into
the same address space. In the "forked" process, the second DLL always
loads into a different location. */
FreeLibrary (h);
/* Block all of the memory up to the new load address. */
reserve_upto (d.name, (DWORD) d.handle);
try2 = 1; /* And try */
continue; /* again. */
}
/* If we reached here, and try2 is set, then there is a lot of memory to
release. */
if (try2)
{
release_upto (d.name, (DWORD) d.handle);
try2 = 0;
}
}
next = d.next; /* Get the address of the next DLL. */
}
in_forkee = 0;
}
extern "C" int
@ -448,33 +322,70 @@ dll_dllcrt0 (HMODULE h, per_process *p)
/* Partially initialize Cygwin guts for non-cygwin apps. */
if (dynamically_loaded && user_data->magic_biscuit == 0)
dll_crt0 (p);
return _the.recordDll (h, p);
if (p)
check_sanity_and_sync (p);
dll_type type;
/* If this function is called before cygwin has finished
initializing, then the DLL must be a cygwin-aware DLL
that was explicitly linked into the program rather than
a dlopened DLL. */
if (!cygwin_finished_initializing)
type = DLL_LINK;
else
{
type = DLL_LOAD;
dlls.reload_on_fork = 1;
}
/* Allocate and initialize space for the DLL. */
dll *d = dlls.alloc (h, p, type);
/* If d == NULL, then something is broken.
Otherwise, if we've finished initializing, it's ok to
initialize the DLL. If we haven't finished initializing,
it may not be safe to call the dll's "main" since not
all of cygwin's internal structures may have been set up. */
if (!d || (cygwin_finished_initializing && !d->init ()))
return -1;
return (DWORD) d;
}
/* OBSOLETE: This function is obsolescent and will go away in the
future. Cygwin can now handle being loaded from a noncygwin app
using the same entry point. */
extern "C"
int
extern "C" int
dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
{
return dll_dllcrt0 (h, p);
}
extern "C"
void
cygwin_detach_dll (int dll_index)
extern "C" void
cygwin_detach_dll (dll *d)
{
_the.detachDll (dll_index);
dlls.detach (d);
}
extern "C"
void
extern "C" void
dlfork (int val)
{
_the.forkeeMustReloadDlls (val);
dlls.reload_on_fork = val;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/* Called from various places to update all of the individual
ideas of the environ block. Explain to me again why we didn't
just import __cygwin_environ? */
void __stdcall
update_envptrs ()
{
extern char ***main_environ;
for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
{
*(d->p.envptr) = __cygwin_environ;
}
*main_environ = __cygwin_environ;
}

View File

@ -1,6 +1,6 @@
/* dll_init.h
Copyright 1998 Cygnus Solutions
Copyright 1998, 1999, 2000 Cygnus Solutions
This file is part of Cygwin.
@ -8,95 +8,84 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
//-----------------------------------------------------------------------------
// list of loaded DLL (used by fork & init)
class DllList
struct per_module
{
public:
static DllList& the ();
// return dll index used for freeDll
int recordDll (HMODULE, per_process*);
void detachDll (int dll_index);
// called after initialization of main module in dll_crt0
void initAll ();
// global destructors of loaded dlls
void doGlobalDestructorsOfDlls ();
// number of dlls dlopened
int numberOfOpenedDlls ();
// boolean to determine if forked process must reload dlls opened with
// LoadLibrary or dlopen ...
// default = 0 (FALSE)
int forkeeMustReloadDlls ();
void forkeeMustReloadDlls (int);
void forkeeLoadDlls ();
// set name of current library opened with dlopen
void currentDlOpenedLib (const char*);
char ***envptr;
void (**ctors)(void);
void (**dtors)(void);
void *data_start;
void *data_end;
void *bss_start;
void *bss_end;
int (*main)(int, char **, char **);
per_module &operator = (per_process *p)
{
envptr = p->envptr;
ctors = p->ctors;
dtors = p->dtors;
data_start = p->data_start;
data_end = p->data_end;
bss_start = p->bss_start;
bss_end = p->bss_end;
main = p->main;
return *this;
}
void run_ctors ();
void run_dtors ();
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class DllListIterator
typedef enum
{
int _type;
int _index;
DLL_NONE,
DLL_LINK,
DLL_LOAD,
DLL_ANY
} dll_type;
protected:
DllListIterator (int type);
int index () const { return _index; }
public:
virtual ~DllListIterator();
int ok() { return _index!=-1; }
void operator++ ();
void operator++ (int) { operator++ (); }
operator per_process* ();
struct dll
{
struct dll *next, *prev;
per_module p;
HMODULE handle;
int count;
dll_type type;
int namelen;
char name[MAX_PATH + 1];
void detach ();
int init ();
};
//-----------------------------------------------------------------------------
#define MAX_DLL_BEFORE_INIT 100
class LinkedDllIterator : public DllListIterator
class dll_list
{
dll *end;
dll *hold;
dll_type hold_type;
public:
LinkedDllIterator ();
~LinkedDllIterator ();
dll start;
int tot;
int loaded_dlls;
int reload_on_fork;
dll *operator [] (const char *name);
dll *alloc (HINSTANCE, per_process *, dll_type);
void detach (dll *);
void init ();
void load_after_fork (HANDLE, dll *);
dll *istart (dll_type t)
{
hold_type = t;
hold = &start;
return inext ();
}
dll *inext ()
{
while ((hold = hold->next))
if (hold_type == DLL_ANY || hold->type == hold_type)
break;
return hold;
}
};
//-----------------------------------------------------------------------------
class LoadedDllIterator : public DllListIterator
{
public:
LoadedDllIterator ();
~LoadedDllIterator ();
};
//-----------------------------------------------------------------------------
#define DO_LINKED_DLL(var) \
{ \
LinkedDllIterator iterator; \
while (iterator.ok ()) \
{ \
per_process *var = (per_process *) iterator;
#define DO_LOADED_DLL(var) \
{ \
LoadedDllIterator iterator; \
while (iterator.ok ()) \
{ \
per_process *var = (per_process *) iterator;
#define DLL_DONE \
iterator++; \
} \
}
extern dll_list dlls;

View File

@ -497,8 +497,8 @@ hinfo::linearize_fd_array (unsigned char *in_buf, int buflen)
LPBYTE
hinfo::de_linearize_fd_array (LPBYTE buf)
{
int len;
size_t max_used_fd, inc_size;
int len, max_used_fd;
size_t inc_size;
debug_printf ("buf %x", buf);
@ -518,7 +518,7 @@ hinfo::de_linearize_fd_array (LPBYTE buf)
return NULL;
}
for (size_t i = 0; i <= max_used_fd; i++)
for (int i = 0; i <= max_used_fd; i++)
{
/* 0xFF means closed */
if (*buf == 0xff)

View File

@ -13,7 +13,7 @@ details. */
#include <ctype.h>
#include <fcntl.h>
#define environ (*user_data->envptr)
#define environ __cygwin_environ
extern BOOL allow_glob;
extern BOOL allow_ntea;
@ -228,11 +228,12 @@ setenv (const char *name, const char *value, int rewrite)
for (P = environ, cnt = 0; *P; ++P, ++cnt)
;
__cygwin_environ = environ = (char **) realloc ((char *) environ,
(size_t) (sizeof (char *) * (cnt + 2)));
environ = (char **) realloc ((char *) environ,
(size_t) (sizeof (char *) * (cnt + 2)));
if (!environ)
return -1;
environ[cnt + 1] = NULL;
update_envptrs ();
offset = cnt;
}
@ -502,7 +503,8 @@ environ_init (int already_posix)
if (!sawTERM)
envp[i++] = strdup ("TERM=cygwin");
envp[i] = NULL;
__cygwin_environ = environ = envp;
environ = envp;
update_envptrs ();
FreeEnvironmentStringsA ((char *) rawenv);
parse_options (NULL);
MALLOC_CHECK;

View File

@ -44,7 +44,7 @@ execl (const char *path, const char *arg0, ...)
while (argv[i++] != NULL);
va_end (args);
MALLOC_CHECK;
return _execve (path, (char * const *) argv, *user_data->envptr);
return _execve (path, (char * const *) argv, __cygwin_environ);
}
extern "C"
@ -52,7 +52,7 @@ int
execv (const char *path, char * const *argv)
{
MALLOC_CHECK;
return _execve (path, (char * const *) argv, *user_data->envptr);
return _execve (path, (char * const *) argv, __cygwin_environ);
}
/* the same as a standard exec() calls family, but with NT security support */
@ -85,7 +85,7 @@ sexecl (HANDLE hToken, const char *path, const char *arg0, ...)
va_end (args);
MALLOC_CHECK;
return sexecve (hToken, path, (char * const *) argv, *user_data->envptr);
return sexecve (hToken, path, (char * const *) argv, __cygwin_environ);
}
extern "C"
@ -131,8 +131,7 @@ sexeclp (HANDLE hToken, const char *path, const char *arg0, ...)
va_end (args);
MALLOC_CHECK;
return sexecvpe (hToken, path, (const char * const *) argv,
*user_data->envptr);
return sexecvpe (hToken, path, (const char * const *) argv, __cygwin_environ);
}
extern "C"
@ -164,7 +163,7 @@ int
sexecv (HANDLE hToken, const char *path, const char * const *argv)
{
MALLOC_CHECK;
return sexecve (hToken, path, argv, *user_data->envptr);
return sexecve (hToken, path, argv, __cygwin_environ);
}
extern "C"
@ -172,7 +171,7 @@ int
sexecp (HANDLE hToken, const char *path, const char * const *argv)
{
MALLOC_CHECK;
return sexecvpe (hToken, path, argv, *user_data->envptr);
return sexecvpe (hToken, path, argv, __cygwin_environ);
}
/*

View File

@ -280,6 +280,13 @@ fork ()
return -1;
}
/* 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. */
dll *first_dll = dlls.start.next;
int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
static child_info_fork ch;
x = setjmp (ch.jmp);
@ -457,43 +464,41 @@ fork ()
if (!rc)
goto cleanup;
/* Now fill data/bss of linked dll */
DO_LINKED_DLL (p)
{
debug_printf ("copying data/bss of a linked dll");
if (!fork_copy (pi, "linked dll data/bss", p->data_start, p->data_end,
p->bss_start, p->bss_end,
NULL))
goto cleanup;
}
DLL_DONE;
proc_register (child);
int load_dll = DllList::the().forkeeMustReloadDlls() &&
DllList::the().numberOfOpenedDlls();
/* Start thread, and wait for it to reload dlls. */
if (!resume_child (pi, forker_finished) ||
!sync_with_child (pi, subproc_ready, load_dll, "child loading dlls"))
goto cleanup;
/* child reload dlls & then write their data and bss */
if (load_dll)
{
/* CHILD IS STOPPED */
/* write memory of reloaded dlls */
DO_LOADED_DLL (p)
/* 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 for a loaded dll");
if (!fork_copy (pi, "loaded dll data/bss", p->data_start, p->data_end,
p->bss_start, p->bss_end,
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))
goto cleanup;
}
DLL_DONE;
/* Start the child up again. */
(void) resume_child (pi, forker_finished);
}
proc_register (child);
/* 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;
/* 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 ())
{
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;
}
/* Start the child up again. */
(void) resume_child (pi, forker_finished);
}
ForceCloseHandle (subproc_ready);
ForceCloseHandle (pi.hThread);
@ -532,6 +537,14 @@ fork ()
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
/* If we've played with the stack, stacksize != 0. That means that
@ -548,20 +561,22 @@ fork ()
dtable.fixup_after_fork (hParent);
signal_fixup_after_fork ();
ForceCloseHandle (hParent);
MALLOC_CHECK;
/* reload dlls if necessary */
if (!DllList::the().forkeeMustReloadDlls() ||
!DllList::the().numberOfOpenedDlls())
/* 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
{
DllList::the().forkeeLoadDlls();
dlls.load_after_fork (hParent, first_dll);
sync_with_parent ("loaded dlls", TRUE);
}
ForceCloseHandle (hParent);
(void) ForceCloseHandle (child_proc_info->subproc_ready);
(void) ForceCloseHandle (child_proc_info->forker_finished);

View File

@ -56,10 +56,7 @@ _cygwin_crt0_common (MainFunc f, per_process *u)
u->ctors = &__CTOR_LIST__;
u->dtors = &__DTOR_LIST__;
if (!u->envptr)
u->envptr = &environ;
else
environ = *(u->envptr);
u->envptr = &environ;
if (uwasnull)
_impure_ptr = u->impure_ptr; /* Use field initialized in newer DLLs. */
else

View File

@ -17,15 +17,9 @@ details. */
int
cygwin_attach_dll (HMODULE h, MainFunc f)
{
struct per_process *u;
if (_cygwin_crt0_common (f, NULL))
u = NULL; /* Newer DLL. Use DLL internal per_process. */
else /* Older DLL. Provide a per_process */
{
u = (struct per_process *) alloca (sizeof (*u));
(void) _cygwin_crt0_common (f, u);
}
struct per_process u;
(void) _cygwin_crt0_common (f, &u);
/* jump into the dll. */
return dll_dllcrt0 (h, u);
return dll_dllcrt0 (h, &u);
}

View File

@ -894,7 +894,7 @@ spawnl (int mode, const char *path, const char *arg0, ...)
va_end (args);
return _spawnve (NULL, mode, path, (char * const *) argv,
*user_data->envptr);
__cygwin_environ);
}
extern "C"
@ -939,7 +939,7 @@ spawnlp (int mode, const char *path, const char *arg0, ...)
va_end (args);
return spawnvpe (mode, path, (char * const *) argv, *user_data->envptr);
return spawnvpe (mode, path, (char * const *) argv, __cygwin_environ);
}
extern "C"
@ -969,7 +969,7 @@ extern "C"
int
spawnv (int mode, const char *path, const char * const *argv)
{
return _spawnve (NULL, mode, path, argv, *user_data->envptr);
return _spawnve (NULL, mode, path, argv, __cygwin_environ);
}
extern "C"
@ -984,7 +984,7 @@ extern "C"
int
spawnvp (int mode, const char *path, const char * const *argv)
{
return spawnvpe (mode, path, argv, *user_data->envptr);
return spawnvpe (mode, path, argv, __cygwin_environ);
}
extern "C"

View File

@ -323,6 +323,8 @@ extern HANDLE netapi32_handle;
extern "C" void error_start_init (const char*);
extern "C" int try_to_debug ();
extern int cygwin_finished_initializing;
/**************************** Miscellaneous ******************************/
const char * __stdcall find_exec (const char *name, path_conv& buf, const char *winenv = "PATH=",
@ -473,6 +475,7 @@ struct win_env
win_env * __stdcall getwinenv (const char *name, const char *posix = NULL);
void __stdcall update_envptrs ();
char * __stdcall winenv (const char * const *, int);
extern char **__cygwin_environ;