This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

(patch) noncygwin fix/update



Loading Cygwin DLL from a non-cygwin app has been broken for a while,
and I just couldn't figure it out until I finally noticed the culprit
-- the static_load hack in init.cc:dll_entry().

These changes make it much more robust to write Java JNI's etc since
some of the internal changes are now easier to track. However, see
the comment marked with NOTE in dll_dllcrt0_1 that says NOT to call
sigproc_init() nor tty_init(). Both of these create threads and use
synchronization, which simply is not possible from a DLL entry point
since Windows serializes dll entry points. I've been wracking my 
brain (and spending way too much time on this since I'd like to see
signals working), but I see no easy way.

In case the topic comes up again, there is no way to do this cleanly
using the same entry point unless we overhaul the DLL initialization
scheme. Should we decide to do it, it's going to take some work to
make sure we don't break every app that forks (I'm sure Sergey will
hunt me down for breaking xterm again ;-).

Retrofitted against 1999-09-13 ss.

Wed Sep 15 23:31:14 1999  Mumit Khan  <khan@xraylith.wisc.edu>

	* init.cc (dll_entry): Remove static_load case.
	* dcrt0.c (set_os_type): Make it externally visible.
	* dll_init.cc (dll_dllcrt0_1): Update noncygwin initialization
	for post-b20.1 code.

Index: init.cc
===================================================================
RCS file: /homes/khan/src/CVSROOT/cygwin-dev/winsup/init.cc,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 init.cc
--- init.cc	1999/09/16 04:09:02	1.1.1.1
+++ init.cc	1999/09/16 04:10:02
@@ -30,16 +30,6 @@ WINAPI dll_entry (HANDLE hdll, DWORD rea
   switch (reason)
     {
     case DLL_PROCESS_ATTACH:
-      if (!static_load)
-	{
-	  do_global_ctors (&__CTOR_LIST__, TRUE);
-	  shared_init ();
-	  user_data->malloc = &(export_malloc);
-	  user_data->free = &(export_free);
-	  user_data->realloc = &(export_realloc);
-	  user_data->calloc = &(export_calloc);
-	  malloc_init ();
-	}
       break;
     case DLL_THREAD_ATTACH:
       break;
Index: dcrt0.cc
===================================================================
RCS file: /homes/khan/src/CVSROOT/cygwin-dev/winsup/dcrt0.cc,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 dcrt0.cc
--- dcrt0.cc	1999/09/16 04:09:02	1.1.1.1
+++ dcrt0.cc	1999/09/16 04:26:38
@@ -100,7 +100,7 @@ os_type NO_COPY os_being_run;
    operating system being run.  This information is used internally
    to manage the inconsistency in Win32 API calls between Win32 OSes. */
 /* Cygwin internal */
-static void
+void
 set_os_type ()
 {
   OSVERSIONINFO os_version_info;
Index: dll_init.cc
===================================================================
RCS file: /homes/khan/src/CVSROOT/cygwin-dev/winsup/dll_init.cc,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 dll_init.cc
--- dll_init.cc	1999/09/16 04:09:02	1.1.1.1
+++ dll_init.cc	1999/09/16 04:26:45
@@ -407,6 +407,15 @@ extern "C"
    DLL to be loaded and the main app is not Cygwin. */
 /* FIXME: This function duplicates too much code from dll_crt0_1 in
    dcrt0.cc.  Need to consolidate this and remove the duplication. */
+
+static NO_COPY STARTUPINFO si;
+static NO_COPY LPBYTE info = NULL;
+# define ciresrv ((struct child_info_fork *)(si.lpReserved2))
+
+extern void alloc_stack (child_info_fork *ci);
+extern void do_global_ctors (void (**)(), int);
+extern void set_os_type ();
+
 static void
 dll_dllcrt0_1 (per_process *uptr)
 {
@@ -415,11 +424,73 @@ dll_dllcrt0_1 (per_process *uptr)
   /* FIXME: Verify forked children get their exception handler set up ok. */
   exception_list cygwin_except_entry;
 
-  check_sanity_and_sync (uptr);
+  int mypid = 0;
 
+  char zeros[sizeof (ciresrv->zero)] = {0};
   /* Set the local copy of the pointer into the user space. */
   user_data = uptr;
+  user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
+
+  GetStartupInfo (&si);
+  if (si.cbReserved2 >= EXEC_MAGIC_SIZE &&
+      memcmp (ciresrv->zero, zeros, sizeof (zeros)) == 0)
+    switch (ciresrv->type)
+      {
+	case PROC_EXEC:
+	case PROC_SPAWN:
+	case PROC_FORK:
+	case PROC_FORK1:
+	  {
+	    HANDLE me = GetCurrentProcess ();
+	    child_proc_info = ciresrv;
+	    mypid = child_proc_info->cygpid;
+	    cygwin_shared_h = child_proc_info->shared_h;
+	    console_shared_h = child_proc_info->console_h;
+
+	    /* We don't want subprocesses to inherit this */
+	    if (!DuplicateHandle (me, child_proc_info->parent_alive, me, &parent_alive,
+				       0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+	      system_printf ("parent_alive DuplicateHandle failed, %E");
+
+	    switch (child_proc_info->type)
+	      {
+		case PROC_EXEC:
+		case PROC_SPAWN:
+		  info = si.lpReserved2 + ciresrv->cb;
+		  break;
+		case PROC_FORK:
+		case PROC_FORK1:
+		  user_data->forkee = child_proc_info->cygpid;
+		  user_data->heaptop = child_proc_info->heaptop;
+		  user_data->heapbase = child_proc_info->heapbase;
+		  user_data->heapptr = child_proc_info->heapptr;
+		  alloc_stack (ciresrv);		// may never return
+	      }
+	    break;
+	  }
+	default:
+	  if ((ciresrv->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC)
+	    api_fatal ("conflicting versions of cygwin1.dll detected.  Use only the most recent version.\n");
+      }
+
+  do_global_ctors (&__CTOR_LIST__, 1);
+
+#ifdef DEBUGGING
+  if (child_proc_info)
+    switch (child_proc_info->type)
+      {
+	case PROC_FORK:
+	case PROC_FORK1:
+	  ProtectHandle (child_proc_info->forker_finished);
+	case PROC_EXEC:
+	  ProtectHandle (child_proc_info->subproc_ready);
+      }
+#endif
+
+  regthread ("main", GetCurrentThreadId ());
 
+  check_sanity_and_sync (user_data);
+
   /* Nasty static stuff needed by newlib -- point to a local copy of
      the reent stuff.
      Note: this MUST be done here (before the forkee code) as the
@@ -428,16 +499,48 @@ dll_dllcrt0_1 (per_process *uptr)
 
   *(user_data->impure_ptr_ptr) = &reent_data;
   _impure_ptr = &reent_data;
+
+#ifdef _MT_SAFE
+  user_data->resourcelocks = &_reslock;
+  user_data->resourcelocks->Init();
+
+  user_data->threadinterface = &_mtinterf;
+  user_data->threadinterface->Init0();
+#endif
+
+  /* Set the os_being_run global. */
+  set_os_type ();
+
+  /* If we didn't call SetFileApisToOEM, console I/O calls would use a
+     different codepage than other Win32 API calls.  In some languages
+     (not English), this would result in "cat > filename" creating a file
+     by a different name than if CreateFile was used to create filename.
+     SetFileApisToOEM prevents this problem by making all calls use the
+     OEM codepage. */
+
+  SetFileApisToOEM ();
 
-  /* Initialize the cygwin32 subsystem if this is the first process,
+  /* Initialize the host dependent constants object. */
+  host_dependent.init ();
+
+  /* Initialize the cygwin subsystem if this is the first process,
      or attach to the shared data structure if it's already running. */
   shared_init ();
 
+  if (mypid)
+    set_myself (cygwin_shared->p[mypid]);
+
   /* Initialize events. */
   events_init ();
 
   (void) SetErrorMode (SEM_FAILCRITICALERRORS);
 
+  /* Call this once before heap initializing, to avoid heap fragmentation */
+  extern PSID get_admin_sid (), get_system_sid (), get_world_sid ();
+  get_admin_sid ();
+  get_system_sid ();
+  get_world_sid ();
+
   /* Initialize the heap. */
   heap_init ();
 
@@ -446,6 +549,24 @@ dll_dllcrt0_1 (per_process *uptr)
      shared_init. */
   init_exceptions (&cygwin_except_entry);
 
+  if (user_data->forkee)
+    {
+      /* If we've played with the stack, stacksize != 0.  That means that
+	 fork() was invoked from other than the main thread.  Make sure that
+	 frame pointer is referencing the new stack so that the OS knows what
+	 to do when it needs to increase the size of the stack.
+
+	 NOTE: Don't do anything that involves the stack until you've completed
+	 this step. */
+      if (ciresrv->stacksize)
+	{
+	  asm ("movl %0,%%fs:4" : : "r" (ciresrv->stackbottom));
+	  asm ("movl %0,%%fs:8" : : "r" (ciresrv->stacktop));
+	}
+
+      longjmp (ciresrv->jmp, ciresrv->cygpid);
+    }
+
   pinfo_init (NULL);		/* Initialize our process table entry. */
 
   /* Nasty static stuff needed by newlib - initialize it.
@@ -454,21 +575,38 @@ dll_dllcrt0_1 (per_process *uptr)
      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
 
   /* Allocate dtable */
   dtable_init ();
 
-  /* Connect to tty. */
-  tty_init ();
+  /* NOTE: No call to sigproc_init() nor to tty_init(). These create
+     threads and uses synchronization, and that's a NO-NO from a
+     DLL entry point thanks to the Windows serialization when loading
+     DLLs dynamically. See MSDN docs for more info.  */
 
   /* Set up standard fds in file descriptor table. */
   hinfo_init ();
 
+  /* Initialize uid, gid. */
+  uinfo_init ();
+
+  syscall_printf ("Application CYGWIN version: %d.%d, api: %d.%d",
+		  user_data->dll_major, user_data->dll_minor,
+		  user_data->api_major, user_data->api_minor);
+  syscall_printf ("CYGWIN DLL version: %d.%d, api: %d.%d",
+		  cygwin_version.dll_major, cygwin_version.dll_minor,
+		  cygwin_version.api_major, cygwin_version.api_minor);
+
   /* Call init of loaded dlls. */
   DllList::the().initAll();
 
@@ -487,7 +625,7 @@ int
 dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
 {
   /* Partially initialize Cygwin guts for non-cygwin apps. */
-  if (! user_data)
+  if (! user_data || user_data->magic_biscuit == 0)
     {
       dll_dllcrt0_1 (p);
     }

Regards,
Mumit


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]