* 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> Wed Jul 12 00:46:00 2000 Christopher Faylor <cgf@cygnus.com>
* debug.cc (thread_stub): Use impure_ptr in place of reent_data. * 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; BOOL allow_glob = TRUE;
HANDLE NO_COPY parent_alive = NULL; HANDLE NO_COPY parent_alive = NULL;
int cygwin_finished_initializing = 0;
/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t. /* 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. 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. */ measure to allow an orderly transfer to the new, correct sigmask method. */
unsigned int signal_shift_subtract = 1; unsigned int signal_shift_subtract = 1;
#ifdef _MT_SAFE
ResourceLocks _reslock NO_COPY; ResourceLocks _reslock NO_COPY;
MTinterface _mtinterf NO_COPY; MTinterface _mtinterf NO_COPY;
#endif
extern "C" extern "C"
{ {
@ -64,6 +63,7 @@ extern "C"
/* This is an exported copy of environ which can be used by DLLs /* This is an exported copy of environ which can be used by DLLs
which use cygwin.dll. */ which use cygwin.dll. */
char **__cygwin_environ; char **__cygwin_environ;
char ***main_environ;
/* __progname used in getopt error message */ /* __progname used in getopt error message */
char *__progname = NULL; char *__progname = NULL;
struct _reent reent_data; struct _reent reent_data;
@ -192,7 +192,7 @@ host_dependent_constants::init ()
{ {
case winNT: case winNT:
win32_upper = 0xffffffff; win32_upper = 0xffffffff;
shared = FILE_SHARE_READ | FILE_SHARE_WRITE; shared = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break; break;
case win98: case win98:
@ -699,16 +699,8 @@ dll_crt0_1 ()
of the calls below (eg. uinfo_init) do stdio calls - this area must of the calls below (eg. uinfo_init) do stdio calls - this area must
be set to zero before then. */ be set to zero before then. */
#ifdef _MT_SAFE
user_data->threadinterface->ClearReent(); user_data->threadinterface->ClearReent();
user_data->threadinterface->Init1(); 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 (); char *line = GetCommandLineA ();
@ -734,7 +726,10 @@ dll_crt0_1 ()
/* beyond this we only do for cygwin apps or dlls */ /* beyond this we only do for cygwin apps or dlls */
if (dynamically_loaded) if (dynamically_loaded)
return; {
cygwin_finished_initializing = 1;
return;
}
/* Initialize signal/subprocess handling. */ /* Initialize signal/subprocess handling. */
sigproc_init (); sigproc_init ();
@ -766,15 +761,14 @@ dll_crt0_1 ()
/* Set up __progname for getopt error call. */ /* Set up __progname for getopt error call. */
__progname = argv[0]; __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 /* 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 do this for noncygwin case since the signal thread is blocked due to
LoadLibrary serialization. */ 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 */ /* Execute any specified "premain" functions */
if (user_data->premain[PREMAIN_LEN / 2]) if (user_data->premain[PREMAIN_LEN / 2])
@ -782,6 +776,9 @@ dll_crt0_1 ()
user_data->premain[i] (argc, argv); user_data->premain[i] (argc, argv);
debug_printf ("user_data->main %p", user_data->main); debug_printf ("user_data->main %p", user_data->main);
set_errno (0);
if (user_data->main) if (user_data->main)
exit (user_data->main (argc, argv, *user_data->envptr)); exit (user_data->main (argc, argv, *user_data->envptr));
} }
@ -806,6 +803,7 @@ _dll_crt0 ()
} }
#endif #endif
main_environ = user_data->envptr;
user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL; user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
set_console_handler (); set_console_handler ();
@ -874,7 +872,7 @@ void
dll_crt0 (per_process *uptr) dll_crt0 (per_process *uptr)
{ {
/* Set the local copy of the pointer into the user space. */ /* 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); memcpy (user_data, uptr, per_process_overwrite);
*(user_data->impure_ptr_ptr) = &reent_data; *(user_data->impure_ptr_ptr) = &reent_data;

View File

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

View File

@ -13,65 +13,28 @@ details. */
extern void __stdcall check_sanity_and_sync (per_process *); extern void __stdcall check_sanity_and_sync (per_process *);
#ifdef _MT_SAFE dll_list NO_COPY dlls;
extern ResourceLocks _reslock NO_COPY;
extern MTinterface _mtinterf NO_COPY;
#endif /*_MT_SAFE*/
/* WARNING: debug can't be called before init !!!! */ static NO_COPY int in_forkee = 0;
/* local variables */
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// the private structure
typedef enum { NONE, LINK, LOAD } dllType;
struct dll
{
per_process p;
HMODULE handle;
const char *name;
dllType type;
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define MAX_DLL_BEFORE_INIT 100 // FIXME: enough ??? static int dll_global_dtors_recorded = 0;
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;
/* Run destructors for all DLLs on exit. */
static void 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 /* Run all constructors associated with a dll */
doGlobalCTORS (per_process *p) void
per_module::run_ctors ()
{ {
void (**pfunc)() = p->ctors; void (**pfunc)() = ctors;
/* Run ctors backwards, so skip the first entry and find how many /* Run ctors backwards, so skip the first entry and find how many
there are, then run them. */ there are, then run them. */
@ -86,230 +49,160 @@ doGlobalCTORS (per_process *p)
} }
} }
static void /* Run all destructors associated with a dll */
doGlobalDTORS (per_process *p) void
per_module::run_dtors ()
{ {
if (!p) void (**pfunc)() = dtors;
return;
void (**pfunc)() = p->dtors;
for (int i = 1; pfunc[i]; i++) for (int i = 1; pfunc[i]; i++)
(pfunc[i]) (); (pfunc[i]) ();
} }
#define INC 500 /* Initialize an individual DLL */
int
static int dll::init ()
add (HMODULE h, char *name, per_process *p, dllType type)
{ {
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; 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 */ /* global contructors */
doGlobalCTORS (p); p.run_ctors ();
/* entry point of dll (use main of per_process with null args...) */ /* entry point of dll (use main of per_process with null args...) */
if (p->main) if (p.main)
ret = (*(p->main)) (0, 0, 0); ret = (*(p.main)) (0, 0, 0);
} }
return ret; return ret;
} }
DllList& /* Look for a dll based on name */
DllList::the () 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 void
DllList::currentDlOpenedLib (const char *name) dll_list::detach (dll *d)
{ {
if (_dlopenedLib != 0) if (d->count <= 0)
small_printf ("WARNING: previous dlopen of %s wasn't correctly performed\n", _dlopenedLib); system_printf ("WARNING: try to detach an already detached dll ...\n");
_dlopenedLib = name; else if (--d->count == 0)
_dlopenIndex = -1; {
} d->p.run_dtors ();
d->prev->next = d->next;
int if (d->next)
DllList::recordDll (HMODULE h, per_process *p) d->next->prev = d->prev;
{ if (d->type == DLL_LOAD)
int ret = -1; loaded_dlls--;
if (end == d)
/* debug_printf ("Record a dll p=%p\n", p); see WARNING */ end = d->prev;
dllType type = LINK; UnmapViewOfFile (d);
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;
} }
/* Initialization called by dll_crt0_1. */
void 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]); atexit (dll_global_dtors);
doGlobalDTORS (&aDll->p); dll_global_dtors_recorded = 1;
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;
} }
if (!_initCalled) /* Walk the dll chain, initializing each dll */
{ dll *d = &start;
debug_printf ("call to DllList::initAll"); while ((d = d->next))
for (int i = 0; i < _last; i++) d->init ();
{
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;
} }
#define A64K (64 * 1024) #define A64K (64 * 1024)
/* Mark every memory address up to "here" as reserved. This may force /* Mark every memory address up to "here" as reserved. This may force
Windows NT to load a DLL in the next available, lowest slot. */ Windows NT to load a DLL in the next available, lowest slot. */
void static void
reserve_upto (const char *name, DWORD here) reserve_upto (const char *name, DWORD here)
{ {
DWORD size; DWORD size;
@ -334,7 +227,7 @@ reserve_upto (const char *name, DWORD here)
/* Release all of the memory previously allocated by "upto" above. /* Release all of the memory previously allocated by "upto" above.
Note that this may also free otherwise reserved memory. If that becomes 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. */ 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) release_upto (const char *name, DWORD here)
{ {
DWORD size; 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 /* 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. */ and attempts to load them in the same place as they were loaded in the parent. */
void void
DllList::forkeeLoadDlls () dll_list::load_after_fork (HANDLE parent, dll *first)
{ {
_initCalled = 1; in_forkee = 1;
_in_forkee = 1;
int try2 = 0; int try2 = 0;
for (int i = 0; i < _last; i++) dll d;
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);
if (h == handle) void *next = first;
{ while (next)
FreeLibrary (h); {
LoadLibrary (name); DWORD nb;
} /* Read the dll structure from the parent. */
else if (try2) if (!ReadProcessMemory (parent, next, &d, MAX_DLL_SIZE, &nb) ||
api_fatal ("unable to remap %s to same address as parent -- %p", name, h); nb != MAX_DLL_SIZE)
else return;
{ /* We're only interested in dynamically loaded dlls.
FreeLibrary (h); Hopefully, this function wouldn't even have been called unless
reserve_upto (name, (DWORD) handle); the parent had some of those. */
try2 = 1; if (d.type == DLL_LOAD)
i--; {
continue; HMODULE h = LoadLibraryEx (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES);
}
if (try2)
{
release_upto (name, (DWORD) handle);
try2 = 0;
}
}
_in_forkee = 0;
}
//----------------------------------------------------------------------------- /* See if DLL will load in proper place. If so, free it and reload
//----------------------------------------------------------------------------- it the right way.
// iterators It sort of stinks that we can't invert the order of the FreeLibrary
and LoadLibrary since Microsoft documentation seems to imply that that
DllListIterator::DllListIterator (int type) : _type (type), _index (-1) should do what we want. However, since the library was loaded above,
{ The second LoadLibrary does not execute it's startup code unless it
operator++ (); is first unloaded. */
} if (h == d.handle)
{
DllListIterator::~DllListIterator () FreeLibrary (h);
{ LoadLibrary (d.name);
} }
else if (try2)
DllListIterator::operator per_process* () api_fatal ("unable to remap %s to same address as parent -- %p", d.name, h);
{ else
return &_list[index ()].p; {
} /* 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
void the same address space. In the "forked" process, the second DLL always
DllListIterator::operator++ () loads into a different location. */
{ FreeLibrary (h);
_index++; /* Block all of the memory up to the new load address. */
while (_index < _last && (int) (_list[_index].type) != _type) reserve_upto (d.name, (DWORD) d.handle);
_index++; try2 = 1; /* And try */
if (_index == _last) continue; /* again. */
_index = -1; }
} /* If we reached here, and try2 is set, then there is a lot of memory to
release. */
LinkedDllIterator::LinkedDllIterator () : DllListIterator ((int) LINK) if (try2)
{ {
} release_upto (d.name, (DWORD) d.handle);
try2 = 0;
LinkedDllIterator::~LinkedDllIterator () }
{ }
} next = d.next; /* Get the address of the next DLL. */
}
LoadedDllIterator::LoadedDllIterator () : DllListIterator ((int) LOAD) in_forkee = 0;
{
}
LoadedDllIterator::~LoadedDllIterator ()
{
} }
extern "C" int extern "C" int
@ -448,33 +322,70 @@ dll_dllcrt0 (HMODULE h, per_process *p)
/* Partially initialize Cygwin guts for non-cygwin apps. */ /* Partially initialize Cygwin guts for non-cygwin apps. */
if (dynamically_loaded && user_data->magic_biscuit == 0) if (dynamically_loaded && user_data->magic_biscuit == 0)
dll_crt0 (p); 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 /* OBSOLETE: This function is obsolescent and will go away in the
future. Cygwin can now handle being loaded from a noncygwin app future. Cygwin can now handle being loaded from a noncygwin app
using the same entry point. */ using the same entry point. */
extern "C" extern "C" int
int
dll_noncygwin_dllcrt0 (HMODULE h, per_process *p) dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
{ {
return dll_dllcrt0 (h, p); return dll_dllcrt0 (h, p);
} }
extern "C" extern "C" void
void cygwin_detach_dll (dll *d)
cygwin_detach_dll (int dll_index)
{ {
_the.detachDll (dll_index); dlls.detach (d);
} }
extern "C" extern "C" void
void
dlfork (int val) 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 /* dll_init.h
Copyright 1998 Cygnus Solutions Copyright 1998, 1999, 2000 Cygnus Solutions
This file is part of Cygwin. 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 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
//----------------------------------------------------------------------------- struct per_module
// list of loaded DLL (used by fork & init)
class DllList
{ {
public: char ***envptr;
static DllList& the (); void (**ctors)(void);
void (**dtors)(void);
// return dll index used for freeDll void *data_start;
int recordDll (HMODULE, per_process*); void *data_end;
void detachDll (int dll_index); void *bss_start;
void *bss_end;
// called after initialization of main module in dll_crt0 int (*main)(int, char **, char **);
void initAll (); per_module &operator = (per_process *p)
{
// global destructors of loaded dlls envptr = p->envptr;
void doGlobalDestructorsOfDlls (); ctors = p->ctors;
dtors = p->dtors;
// number of dlls dlopened data_start = p->data_start;
int numberOfOpenedDlls (); data_end = p->data_end;
bss_start = p->bss_start;
// boolean to determine if forked process must reload dlls opened with bss_end = p->bss_end;
// LoadLibrary or dlopen ... main = p->main;
// default = 0 (FALSE) return *this;
int forkeeMustReloadDlls (); }
void forkeeMustReloadDlls (int); void run_ctors ();
void run_dtors ();
void forkeeLoadDlls ();
// set name of current library opened with dlopen
void currentDlOpenedLib (const char*);
}; };
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class DllListIterator typedef enum
{ {
int _type; DLL_NONE,
int _index; DLL_LINK,
DLL_LOAD,
DLL_ANY
} dll_type;
protected: struct dll
DllListIterator (int type); {
int index () const { return _index; } struct dll *next, *prev;
per_module p;
public: HMODULE handle;
virtual ~DllListIterator(); int count;
dll_type type;
int ok() { return _index!=-1; } int namelen;
void operator++ (); char name[MAX_PATH + 1];
void operator++ (int) { operator++ (); } void detach ();
operator per_process* (); int init ();
}; };
//----------------------------------------------------------------------------- #define MAX_DLL_BEFORE_INIT 100
class LinkedDllIterator : public DllListIterator class dll_list
{ {
dll *end;
dll *hold;
dll_type hold_type;
public: public:
LinkedDllIterator (); dll start;
~LinkedDllIterator (); 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;
}
}; };
//----------------------------------------------------------------------------- extern dll_list dlls;
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++; \
} \
}

View File

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

View File

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

View File

@ -44,7 +44,7 @@ execl (const char *path, const char *arg0, ...)
while (argv[i++] != NULL); while (argv[i++] != NULL);
va_end (args); va_end (args);
MALLOC_CHECK; MALLOC_CHECK;
return _execve (path, (char * const *) argv, *user_data->envptr); return _execve (path, (char * const *) argv, __cygwin_environ);
} }
extern "C" extern "C"
@ -52,7 +52,7 @@ int
execv (const char *path, char * const *argv) execv (const char *path, char * const *argv)
{ {
MALLOC_CHECK; 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 */ /* 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); va_end (args);
MALLOC_CHECK; MALLOC_CHECK;
return sexecve (hToken, path, (char * const *) argv, *user_data->envptr); return sexecve (hToken, path, (char * const *) argv, __cygwin_environ);
} }
extern "C" extern "C"
@ -131,8 +131,7 @@ sexeclp (HANDLE hToken, const char *path, const char *arg0, ...)
va_end (args); va_end (args);
MALLOC_CHECK; MALLOC_CHECK;
return sexecvpe (hToken, path, (const char * const *) argv, return sexecvpe (hToken, path, (const char * const *) argv, __cygwin_environ);
*user_data->envptr);
} }
extern "C" extern "C"
@ -164,7 +163,7 @@ int
sexecv (HANDLE hToken, const char *path, const char * const *argv) sexecv (HANDLE hToken, const char *path, const char * const *argv)
{ {
MALLOC_CHECK; MALLOC_CHECK;
return sexecve (hToken, path, argv, *user_data->envptr); return sexecve (hToken, path, argv, __cygwin_environ);
} }
extern "C" extern "C"
@ -172,7 +171,7 @@ int
sexecp (HANDLE hToken, const char *path, const char * const *argv) sexecp (HANDLE hToken, const char *path, const char * const *argv)
{ {
MALLOC_CHECK; 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; 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; static child_info_fork ch;
x = setjmp (ch.jmp); x = setjmp (ch.jmp);
@ -457,43 +464,41 @@ fork ()
if (!rc) if (!rc)
goto cleanup; goto cleanup;
/* Now fill data/bss of linked dll */ /* Now fill data/bss of any DLLs that were linked into the program. */
DO_LINKED_DLL (p) 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", 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)
{ {
debug_printf ("copying data/bss for a loaded dll"); debug_printf ("copying data/bss of a linked dll");
if (!fork_copy (pi, "loaded dll data/bss", p->data_start, p->data_end, if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
p->bss_start, p->bss_end, d->p.bss_start, d->p.bss_end,
NULL)) NULL))
goto cleanup; goto cleanup;
} }
DLL_DONE;
/* Start the child up again. */ proc_register (child);
(void) resume_child (pi, forker_finished);
} /* 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 (subproc_ready);
ForceCloseHandle (pi.hThread); ForceCloseHandle (pi.hThread);
@ -532,6 +537,14 @@ fork ()
char c; char c;
if (GetEnvironmentVariable ("FORKDEBUG", &c, 1)) if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
try_to_debug (); 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 #endif
/* If we've played with the stack, stacksize != 0. That means that /* If we've played with the stack, stacksize != 0. That means that
@ -548,20 +561,22 @@ fork ()
dtable.fixup_after_fork (hParent); dtable.fixup_after_fork (hParent);
signal_fixup_after_fork (); signal_fixup_after_fork ();
ForceCloseHandle (hParent);
MALLOC_CHECK; MALLOC_CHECK;
/* reload dlls if necessary */ /* If we haven't dynamically loaded any dlls, just signal
if (!DllList::the().forkeeMustReloadDlls() || the parent. Otherwise, load all the dlls, tell the parent
!DllList::the().numberOfOpenedDlls()) 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); sync_with_parent ("performed fork fixup.", FALSE);
else else
{ {
DllList::the().forkeeLoadDlls(); dlls.load_after_fork (hParent, first_dll);
sync_with_parent ("loaded dlls", TRUE); sync_with_parent ("loaded dlls", TRUE);
} }
ForceCloseHandle (hParent);
(void) ForceCloseHandle (child_proc_info->subproc_ready); (void) ForceCloseHandle (child_proc_info->subproc_ready);
(void) ForceCloseHandle (child_proc_info->forker_finished); (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->ctors = &__CTOR_LIST__;
u->dtors = &__DTOR_LIST__; u->dtors = &__DTOR_LIST__;
if (!u->envptr) u->envptr = &environ;
u->envptr = &environ;
else
environ = *(u->envptr);
if (uwasnull) if (uwasnull)
_impure_ptr = u->impure_ptr; /* Use field initialized in newer DLLs. */ _impure_ptr = u->impure_ptr; /* Use field initialized in newer DLLs. */
else else

View File

@ -17,15 +17,9 @@ details. */
int int
cygwin_attach_dll (HMODULE h, MainFunc f) cygwin_attach_dll (HMODULE h, MainFunc f)
{ {
struct per_process *u; struct per_process u;
if (_cygwin_crt0_common (f, NULL)) (void) _cygwin_crt0_common (f, &u);
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);
}
/* jump into the dll. */ /* 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); va_end (args);
return _spawnve (NULL, mode, path, (char * const *) argv, return _spawnve (NULL, mode, path, (char * const *) argv,
*user_data->envptr); __cygwin_environ);
} }
extern "C" extern "C"
@ -939,7 +939,7 @@ spawnlp (int mode, const char *path, const char *arg0, ...)
va_end (args); va_end (args);
return spawnvpe (mode, path, (char * const *) argv, *user_data->envptr); return spawnvpe (mode, path, (char * const *) argv, __cygwin_environ);
} }
extern "C" extern "C"
@ -969,7 +969,7 @@ extern "C"
int int
spawnv (int mode, const char *path, const char * const *argv) 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" extern "C"
@ -984,7 +984,7 @@ extern "C"
int int
spawnvp (int mode, const char *path, const char * const *argv) 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" extern "C"

View File

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