Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com Message-Id: <199909160435.XAA05764@mercury.xraylith.wisc.edu> To: cygwin-developers AT sourceware DOT cygnus DOT com Subject: (patch) noncygwin fix/update Date: Wed, 15 Sep 1999 23:35:23 -0500 From: Mumit Khan 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 * 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