OSDN Git Service

* hinfo.cc (hinfo::linearize_fd_array): Make max_used_fd an int so that we can
authorcgf <cgf>
Sat, 15 Jul 2000 02:48:10 +0000 (02:48 +0000)
committercgf <cgf>
Sat, 15 Jul 2000 02:48:10 +0000 (02:48 +0000)
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.

13 files changed:
winsup/cygwin/ChangeLog
winsup/cygwin/dcrt0.cc
winsup/cygwin/dlfcn.cc
winsup/cygwin/dll_init.cc
winsup/cygwin/dll_init.h
winsup/cygwin/dtable.cc
winsup/cygwin/environ.cc
winsup/cygwin/exec.cc
winsup/cygwin/fork.cc
winsup/cygwin/lib/_cygwin_crt0_common.cc
winsup/cygwin/lib/cygwin_attach_dll.c
winsup/cygwin/spawn.cc
winsup/cygwin/winsup.h

index 82d8411..d934eea 100644 (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.
index a42e84e..4dddd31 100644 (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;
index cf74d46..dc6fec3 100644 (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);
     }
 
index 0bf405f..94cc8e6 100644 (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 !!!! */
+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 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)
-{
-  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)
+/* Initialize an individual DLL */
+int
+dll::init ()
 {
-  /* FIXME: init environment (useful?) */
-  *(p->envptr) = *(user_data->envptr);
+  int ret = 1;
 
-  /* FIXME: need other initializations? */
+  /* Why didn't we just import this variable? */
+  *(p.envptr) = __cygwin_environ;
 
-  int ret = 1;
-  if (!_in_forkee)
+  /* 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;
 
-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;
+  return NULL;
 }
 
-int
-DllList::recordDll (HMODULE h, per_process *p)
+#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)
 {
-  int ret = -1;
+  char name[MAX_PATH + 1];
+  DWORD namelen = GetModuleFileName (h, name, sizeof (name));
 
-  /* debug_printf ("Record a dll p=%p\n", p); see WARNING */
-  dllType type = LINK;
-  if (_initCalled)
+  /* Already loaded? */
+  dll *d = dlls[name];
+  if (d)
     {
-      type = LOAD;
-      _numberOfOpenedDlls++;
-      forkeeMustReloadDlls (1);
+      d->count++;      /* Yes.  Bump the usage count. */
+      return d;                /* Return previously allocated pointer. */
     }
 
-  if (_in_forkee)
+  int i;
+  void *s = p->bss_end;
+  MEMORY_BASIC_INFORMATION m;
+  /* Search for space after the DLL */
+  for (i = 0; i <= RETRIES; i++)
     {
-      ret = 0;         // Just a flag
-      goto out;
+      if (!VirtualQuery (s, &m, sizeof (m)))
+       return NULL;    /* Can't do it. */
+      if (m.State == MEM_FREE)
+       break;
+      s = (char *) m.BaseAddress + m.RegionSize;
     }
 
-  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;
+  /* 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::detachDll (int dll_index)
+dll_list::detach (dll *d)
 {
-  if (dll_index != -1)
+  if (d->count <= 0)
+    system_printf ("WARNING: try to detach an already detached dll ...\n");
+  else if (--d->count == 0)
     {
-      dll *aDll = &(_list[dll_index]);
-      doGlobalDTORS (&aDll->p);
-      if (aDll->type == LOAD)
-       _numberOfOpenedDlls--;
-      aDll->type = NONE;
+      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);
     }
-  else
-    small_printf ("WARNING: try to detach an already detached dll ...\n");
 }
 
+/* Initialization called by dll_crt0_1. */
 void
-DllList::initAll ()
+dll_list::init ()
 {
-  // init for destructors
-  // because initAll isn't called in forked process, this exit function will
-  // be recorded only once
-  if (!__dll_global_dtors_recorded)
+  debug_printf ("here");
+  /* Make sure that destructors are called on exit. */
+  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);
-
-       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
+  dll d;
 
-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 ()
-{
+  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);
+
+         /* 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;
+}
index ca2cc2c..ac14668 100644 (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* ();
-};
-
-//-----------------------------------------------------------------------------
-
-class LinkedDllIterator : public DllListIterator
+struct dll
 {
-public:
-  LinkedDllIterator ();
-  ~LinkedDllIterator ();
+  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 LoadedDllIterator : public DllListIterator
+class dll_list
 {
+  dll *end;
+  dll *hold;
+  dll_type hold_type;
 public:
-  LoadedDllIterator ();
-  ~LoadedDllIterator ();
+  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;
+  }
 };
 
-//-----------------------------------------------------------------------------
-
-#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;
index 13167cc..4fb488d 100644 (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)
index 719a171..716af85 100644 (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;
index b83a9b9..0ba3ead 100644 (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);
 }
 
 /*
index 54c6681..fdd63c6 100644 (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;
+      /* Now fill data/bss of any DLLs that were linked into the program. */
+      for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
+       {
+         debug_printf ("copying data/bss of a linked dll");
+         if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
+                                                    d->p.bss_start, d->p.bss_end,
+                                                    NULL))
+           goto cleanup;
+       }
 
       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"))
+         !sync_with_child (pi, subproc_ready, load_dlls, "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)
+      /* 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)
        {
-         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,
-                                                    NULL))
-           goto cleanup;
+         /* 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);
        }
-       DLL_DONE;
-       /* 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);
 
index fcca169..4ca6dd7 100644 (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
index 09b898b..440cace 100644 (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);
 }
index f6da863..6ca82e4 100644 (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"
index 61dd627..5a1ff2f 100644 (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;