* 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:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user