Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2000-02-17 22:38:33 +0300
committerChristopher Faylor <me@cgf.cx>2000-02-17 22:38:33 +0300
commit1fd5e000ace55b323124c7e556a7a864b972a5c4 (patch)
treedc4fcf1e5e22a040716ef92c496b8d94959b2baa /winsup/cygwin/dll_init.cc
parent369d8a8fd5e887eca547bf34bccfdf755c9e5397 (diff)
import winsup-2000-02-17 snapshot
Diffstat (limited to 'winsup/cygwin/dll_init.cc')
-rw-r--r--winsup/cygwin/dll_init.cc499
1 files changed, 499 insertions, 0 deletions
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
new file mode 100644
index 000000000..a1d217576
--- /dev/null
+++ b/winsup/cygwin/dll_init.cc
@@ -0,0 +1,499 @@
+/* dll_init.cc
+
+ Copyright 1998, 1999, 2000 Cygnus Solutions.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <stdlib.h>
+#include "winsup.h"
+#include "exceptions.h"
+#include "dll_init.h"
+
+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*/
+
+/* 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;
+};
+
+//-----------------------------------------------------------------------------
+
+#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 void
+__dll_global_dtors()
+{
+ _the.doGlobalDestructorsOfDlls();
+}
+
+static void
+doGlobalCTORS (per_process *p)
+{
+ void (**pfunc)() = p->ctors;
+
+ /* Run ctors backwards, so skip the first entry and find how many
+ there are, then run them. */
+
+ if (pfunc)
+ {
+ int i;
+ for (i = 1; pfunc[i]; i++);
+
+ for (int j = i - 1; j > 0; j-- )
+ (pfunc[j]) ();
+ }
+}
+
+static void
+doGlobalDTORS (per_process *p)
+{
+ if (!p)
+ return;
+ void (**pfunc)() = p->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)
+{
+ 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)
+{
+ /* global variable user_data must be initialized */
+ if (user_data == NULL)
+ {
+ small_printf ("WARNING: process not inited while trying to init a DLL!\n");
+ return 0;
+ }
+
+ /* init impure_ptr */
+ *(p->impure_ptr_ptr) = *(user_data->impure_ptr_ptr);
+
+ /* FIXME: init environment (useful?) */
+ *(p->envptr) = *(user_data->envptr);
+
+ /* FIXME: need other initializations? */
+
+ int ret = 1;
+ if (!_in_forkee)
+ {
+ /* global contructors */
+ doGlobalCTORS (p);
+
+ /* entry point of dll (use main of per_process with null args...) */
+ if (p->main)
+ ret = (*(p->main)) (0, 0, 0);
+ }
+
+ return ret;
+}
+
+DllList&
+DllList::the ()
+{
+ return _the;
+}
+
+void
+DllList::currentDlOpenedLib (const char *name)
+{
+ 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;
+}
+
+void
+DllList::detachDll (int dll_index)
+{
+ if (dll_index != -1)
+ {
+ 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;
+ }
+
+ 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;
+}
+
+#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
+reserve_upto (const char *name, DWORD here)
+{
+ DWORD size;
+ MEMORY_BASIC_INFORMATION mb;
+ for (DWORD start = 0x10000; start < here; start += size)
+ if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
+ size = 64 * 1024;
+ else
+ {
+ size = A64K * ((mb.RegionSize + A64K - 1) / A64K);
+ start = A64K * (((DWORD) mb.BaseAddress + A64K - 1) / A64K);
+
+ if (start + size > here)
+ size = here - start;
+ if (mb.State == MEM_FREE &&
+ !VirtualAlloc ((void *) start, size, MEM_RESERVE, PAGE_NOACCESS))
+ api_fatal ("couldn't allocate memory %p(%d) for '%s' alignment, %E\n",
+ start, size, name);
+ }
+}
+
+/* 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
+release_upto (const char *name, DWORD here)
+{
+ DWORD size;
+ MEMORY_BASIC_INFORMATION mb;
+ for (DWORD start = 0x10000; start < here; start += size)
+ if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
+ size = 64 * 1024;
+ else
+ {
+ size = mb.RegionSize;
+ if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS &&
+ ((void *) start < user_data->heapbase || (void *) start > user_data->heaptop)))
+ continue;
+ if (!VirtualFree ((void *) start, 0, MEM_RELEASE))
+ api_fatal ("couldn't release memory %p(%d) for '%s' alignment, %E\n",
+ start, size, name);
+ }
+}
+
+/* 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 ()
+{
+ _initCalled = 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);
+
+ 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;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// 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 ()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// the extern symbols
+
+extern "C"
+{
+ /* This is an exported copy of environ which can be used by DLLs
+ which use cygwin.dll. */
+ extern struct _reent reent_data;
+};
+
+extern "C"
+int
+dll_dllcrt0 (HMODULE h, per_process *p)
+{
+ /* Partially initialize Cygwin guts for non-cygwin apps. */
+ if (dynamically_loaded && (! user_data || user_data->magic_biscuit == 0))
+ {
+ dll_crt0 (p);
+ }
+ return _the.recordDll (h, p);
+}
+
+/* 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
+dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
+{
+ return dll_dllcrt0 (h, p);
+}
+
+extern "C"
+void
+cygwin_detach_dll (int dll_index)
+{
+ _the.detachDll (dll_index);
+}
+
+extern "C"
+void
+dlfork (int val)
+{
+ _the.forkeeMustReloadDlls (val);
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------