OSDN Git Service

* globals.cc (enum exit_states::ES_GLOBAL_DTORS): Delete.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / dcrt0.cc
index 48a7b9f..9cff06f 100644 (file)
@@ -1,6 +1,7 @@
 /* dcrt0.cc -- essentially the main() for the Cygwin dll
 
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2007, 2008, 2009
    Red Hat, Inc.
 
 This file is part of Cygwin.
@@ -10,21 +11,18 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
+#include "miscfuncs.h"
 #include <unistd.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include "glob.h"
-#include "exceptions.h"
 #include <ctype.h>
-#include <limits.h>
-#include <wingdi.h>
-#include <winuser.h>
+#include <locale.h>
+#include "environ.h"
 #include "sigproc.h"
 #include "pinfo.h"
 #include "cygerrno.h"
 #define NEED_VFORK
 #include "perprocess.h"
-#include "security.h"
 #include "path.h"
 #include "fhandler.h"
 #include "dtable.h"
@@ -34,97 +32,23 @@ details. */
 #include "shared_info.h"
 #include "cygwin_version.h"
 #include "dll_init.h"
-#include "sync.h"
 #include "heap.h"
+#include "tls_pbuf.h"
 
 #define MAX_AT_FILE_LEVEL 10
 
 #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
 
-extern "C" void cygwin_exit (int) __attribute__ ((noreturn));
-
-HANDLE NO_COPY hMainProc = (HANDLE) -1;
-HANDLE NO_COPY hMainThread;
-HANDLE NO_COPY hProcToken;
-HANDLE NO_COPY hProcImpToken;
-muto NO_COPY dtable::lock_cs;  /* This should be in dtable.cc but it causes inexplicable
-                                  errors there. */
-
-bool display_title;
-bool strip_title_path;
-bool allow_glob = true;
-codepage_type current_codepage = ansi_cp;
-
-int __argc_safe;
-int _declspec(dllexport) __argc;
-char _declspec(dllexport) **__argv;
-#ifdef NEWVFORK
-vfork_save NO_COPY *main_vfork;
-#endif
-
-static int NO_COPY envc;
-char NO_COPY **envp;
 
+extern "C" void cygwin_exit (int) __attribute__ ((noreturn));
 extern "C" void __sinit (_reent *);
 
-_cygtls NO_COPY *_main_tls;
-
-bool NO_COPY cygwin_finished_initializing;
-
-/* 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.
-   In older versions of cygwin, the signal was used as-is to shift the
-   bit for masking.  So, we'll temporarily detect this and set it to zero
-   for programs that are linked using older cygwins.  This is just a stopgap
-   measure to allow an orderly transfer to the new, correct sigmask method. */
-unsigned NO_COPY int signal_shift_subtract = 1;
-
-ResourceLocks _reslock NO_COPY;
-MTinterface _mtinterf;
-
-bool NO_COPY _cygwin_testing;
-
-char NO_COPY almost_null[1];
+static int NO_COPY envc;
+static char NO_COPY **envp;
 
-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;
-  struct per_process __cygwin_user_data =
-  {/* initial_sp */ 0, /* magic_biscuit */ 0,
-   /* dll_major */ CYGWIN_VERSION_DLL_MAJOR,
-   /* dll_major */ CYGWIN_VERSION_DLL_MINOR,
-   /* impure_ptr_ptr */ NULL, /* envptr */ NULL,
-   /* malloc */ malloc, /* free */ free,
-   /* realloc */ realloc,
-   /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL,
-   /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL,
-   /* bss_start */ NULL, /* bss_end */ NULL,
-   /* calloc */ calloc,
-   /* premain */ {NULL, NULL, NULL, NULL},
-   /* run_ctors_p */ 0,
-   /* unused */ {0, 0, 0, 0, 0, 0, 0},
-   /* forkee */ 0,
-   /* hmodule */ NULL,
-   /* api_major */ CYGWIN_VERSION_API_MAJOR,
-   /* api_minor */ CYGWIN_VERSION_API_MINOR,
-   /* unused2 */ {0, 0, 0, 0, 0},
-   /* resourcelocks */ &_reslock, /* threadinterface */ &_mtinterf,
-   /* impure_ptr */ _GLOBAL_REENT,
-  };
-  bool ignore_case_with_glob;
-  int __declspec (dllexport) _check_for_executable = true;
-#ifdef DEBUGGING
-  int pinger;
-#endif
-};
+static char title_buf[TITLESIZE + 1];
 
-char *old_title;
-char title_buf[TITLESIZE + 1];
+bool NO_COPY jit_debug;
 
 static void
 do_global_dtors ()
@@ -141,7 +65,7 @@ do_global_dtors ()
 static void __stdcall
 do_global_ctors (void (**in_pfunc)(), int force)
 {
-  if (!force && user_data->forkee)
+  if (!force && in_forkee)
     return;            // inherit constructed stuff from parent pid
 
   /* Run ctors backwards, so skip the first entry and find how many
@@ -166,14 +90,17 @@ insert_file (char *name, char *&cmd)
 {
   HANDLE f;
   DWORD size;
-
-  f = CreateFile (name + 1,
-                 GENERIC_READ,          /* open for reading    */
-                 FILE_SHARE_READ,       /* share for reading   */
-                 &sec_none_nih,         /* no security         */
-                 OPEN_EXISTING,         /* existing file only  */
-                 FILE_ATTRIBUTE_NORMAL, /* normal file         */
-                 NULL);                 /* no attr. template   */
+  tmp_pathbuf tp;
+
+  PWCHAR wname = tp.w_get ();
+  sys_mbstowcs (wname, NT_MAX_PATH, name + 1);
+  f = CreateFileW (wname,
+                  GENERIC_READ,         /* open for reading    */
+                  FILE_SHARE_READ,      /* share for reading   */
+                  &sec_none_nih,        /* default security    */
+                  OPEN_EXISTING,        /* existing file only  */
+                  FILE_ATTRIBUTE_NORMAL,/* normal file         */
+                  NULL);                /* no attr. template   */
 
   if (f == INVALID_HANDLE_VALUE)
     {
@@ -304,7 +231,15 @@ globify (char *word, char **&argv, int &argc, int &argvlen)
            else if (s[1] == quote || s[1] == '\\')
              s++;
            *p++ = '\\';
-           *p++ = *s;
+           size_t cnt = isascii (*s) ? 1 : mbtowc (NULL, s, MB_CUR_MAX);
+           if (cnt <= 1 || cnt == (size_t)-1)
+             *p++ = *s;
+           else
+             {
+               --s;
+               while (cnt-- > 0)
+                 *p++ = *++s;
+             }
          }
        if (*s == quote)
          p--;
@@ -422,9 +357,7 @@ check_sanity_and_sync (per_process *p)
   /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */
   /* about changing it].                                                  */
   if (sizeof (per_process) != SIZEOF_PER_PROCESS)
-    {
-      api_fatal ("per_process sanity check failed");
-    }
+    api_fatal ("per_process sanity check failed");
 
   /* Make sure that the app and the dll are in sync. */
 
@@ -442,55 +375,53 @@ check_sanity_and_sync (per_process *p)
   if (p->api_major > cygwin_version.api_major)
     api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d > %d",
               p->api_major, cygwin_version.api_major);
-
-  if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <=
-      CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK)
-    signal_shift_subtract = 0;
 }
 
 child_info NO_COPY *child_proc_info = NULL;
-static MEMORY_BASIC_INFORMATION NO_COPY sm;
 
-#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \
-                    PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS)
+#define CYGWIN_GUARD (PAGE_EXECUTE_READWRITE | PAGE_GUARD)
 
-static void
-alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
+void
+child_info_fork::alloc_stack_hard_way (volatile char *b)
 {
   void *new_stack_pointer;
   MEMORY_BASIC_INFORMATION m;
   void *newbase;
   int newlen;
-  LPBYTE curbot = (LPBYTE) sm.BaseAddress + sm.RegionSize;
-  bool noguard;
+  bool guard;
+
+  if (!VirtualQuery ((LPCVOID) &b, &m, sizeof m))
+    api_fatal ("fork: couldn't get stack info, %E");
+
+  LPBYTE curbot = (LPBYTE) m.BaseAddress + m.RegionSize;
 
-  if (ci->stacktop > (LPBYTE) sm.AllocationBase && ci->stacktop < curbot)
+  if (stacktop > (LPBYTE) m.AllocationBase && stacktop < curbot)
     {
       newbase = curbot;
-      newlen = (LPBYTE) ci->stackbottom - (LPBYTE) curbot;
-      noguard = 1;
+      newlen = (LPBYTE) stackbottom - (LPBYTE) curbot;
+      guard = false;
     }
   else
     {
-      newbase = ci->stacktop;
-      newlen = (DWORD) ci->stackbottom - (DWORD) ci->stacktop;
-      noguard = 0;
+      newbase = (LPBYTE) stacktop - (128 * 1024);
+      newlen = (LPBYTE) stackbottom - (LPBYTE) newbase;
+      guard = true;
     }
+
   if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
     api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
-               ci->stacktop, ci->stackbottom);
-
-  new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize);
-
-  if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT,
+               stacktop, stackbottom);
+  new_stack_pointer = (void *) ((LPBYTE) stackbottom - (stacksize += 8192));
+  if (!VirtualAlloc (new_stack_pointer, stacksize, MEM_COMMIT,
                     PAGE_EXECUTE_READWRITE))
     api_fatal ("fork: can't commit memory for stack %p(%d), %E",
-              new_stack_pointer, ci->stacksize);
+              new_stack_pointer, stacksize);
   if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
     api_fatal ("fork: couldn't get new stack info, %E");
-  if (!noguard)
+
+  if (guard)
     {
-      m.BaseAddress = (LPVOID) ((DWORD) m.BaseAddress - 1);
+      m.BaseAddress = (LPBYTE) m.BaseAddress - 1;
       if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
                         CYGWIN_GUARD))
        api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
@@ -498,70 +429,68 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
     }
   if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
     api_fatal ("fork: couldn't get new stack info, %E");
-  ci->stacktop = m.BaseAddress;
+  stacktop = m.BaseAddress;
   b[0] = '\0';
 }
 
 void *getstack (void *) __attribute__ ((noinline));
 volatile char *
-getstack (volatile char *p)
+getstack (volatile char * volatile p)
 {
-  *p |= 0;
+  *p ^= 1;
+  *p ^= 1;
   return p - 4096;
 }
 
 /* extend the stack prior to fork longjmp */
 
-static void
-alloc_stack (child_info_fork *ci)
+void
+child_info_fork::alloc_stack ()
 {
-  volatile char *esp;
+  volatile char * volatile esp;
   __asm__ volatile ("movl %%esp,%0": "=r" (esp));
-  if (_tlsbase != ci->stackbottom)
-    alloc_stack_hard_way (ci, esp);
+  if (_tlsbase != stackbottom)
+    alloc_stack_hard_way (esp);
   else
     {
-      while (_tlstop > ci->stacktop)
+      char *st = (char *) stacktop - 4096;
+      while (_tlstop >= st)
        esp = getstack (esp);
-      ci->stacksize = 0;
+      stacksize = 0;
     }
 }
 
-#ifdef DEBUGGING
-void
+extern "C" void
 break_here ()
 {
+  static int NO_COPY sent_break;
+  if (!sent_break++)
+    DebugBreak ();
   debug_printf ("break here");
 }
-#endif
 
 static void
 initial_env ()
 {
-  char buf[CYG_MAX_PATH];
-  if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+  if (GetEnvironmentVariableA ("CYGWIN_TESTING", NULL, 0))
     _cygwin_testing = 1;
 
 #ifdef DEBUGGING
+  char buf[NT_MAX_PATH];
   DWORD len;
 
-  if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
+  if (GetEnvironmentVariableA ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
     {
       DWORD ms = atoi (buf);
-      buf[0] = '\0';
-      len = GetModuleFileName (NULL, buf, CYG_MAX_PATH);
-      console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf);
+      console_printf ("Sleeping %d, pid %u %P\n", ms, GetCurrentProcessId ());
       Sleep (ms);
-      if (!strace.active && !dynamically_loaded)
-       {
-         strace.inited = 0;
-         strace.hello ();
-       }
+      if (!strace.active () && !dynamically_loaded)
+       strace.hello ();
     }
-  if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
+  if (GetEnvironmentVariableA ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
     {
-      char buf1[CYG_MAX_PATH];
-      len = GetModuleFileName (NULL, buf1, CYG_MAX_PATH);
+      char buf1[NT_MAX_PATH];
+      len = GetModuleFileName (NULL, buf1, NT_MAX_PATH);
       strlwr (buf1);
       strlwr (buf);
       char *p = strpbrk (buf, ":=");
@@ -572,9 +501,9 @@ initial_env ()
       if (strstr (buf1, buf))
        {
          error_start_init (p);
+         jit_debug = true;
          try_to_debug ();
          console_printf ("*** Sending Break.  gdb may issue spurious SIGTRAP message.\n");
-         DebugBreak ();
          break_here ();
        }
     }
@@ -586,21 +515,17 @@ child_info *
 get_cygwin_startup_info ()
 {
   STARTUPINFO si;
-  char zeros[sizeof (child_proc_info->zero)] = {0};
 
   GetStartupInfo (&si);
   child_info *res = (child_info *) si.lpReserved2;
+
   if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res
-      || memcmp (res->zero, zeros, sizeof (res->zero)) != 0)
+      || res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC)
     res = NULL;
   else
     {
       if ((res->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
        multiple_cygwin_problem ("proc intro", res->intro, 0);
-      else if (res->intro == PROC_MAGIC_GENERIC
-              && res->magic != CHILD_INFO_MAGIC)
-       multiple_cygwin_problem ("proc magic", res->magic,
-                                CHILD_INFO_MAGIC);
       else if (res->cygheap != (void *) &_cygheap_start)
        multiple_cygwin_problem ("cygheap base", (DWORD) res->cygheap,
                                 (DWORD) &_cygheap_start);
@@ -609,7 +534,7 @@ get_cygwin_startup_info ()
       switch (res->type)
        {
          case _PROC_FORK:
-           user_data->forkee = true;
+           in_forkee = true;
            should_be_cb = sizeof (child_info_fork);
            /* fall through */;
          case _PROC_SPAWN:
@@ -620,6 +545,13 @@ get_cygwin_startup_info ()
              multiple_cygwin_problem ("proc size", res->cb, should_be_cb);
            else if (sizeof (fhandler_union) != res->fhandler_union_cb)
              multiple_cygwin_problem ("fhandler size", res->fhandler_union_cb, sizeof (fhandler_union));
+           if (res->isstraced ())
+             {
+               res->ready (false);
+               for (unsigned i = 0; !being_debugged () && i < 10000; i++)
+                 low_priority_sleep (0);
+               strace.hello ();
+             }
            break;
          default:
            system_printf ("unknown exec type %d", res->type);
@@ -633,19 +565,129 @@ get_cygwin_startup_info ()
   return res;
 }
 
+#define dll_data_start &_data_start__
+#define dll_data_end &_data_end__
+#define dll_bss_start &_bss_start__
+#define dll_bss_end &_bss_end__
+
+void
+child_info_fork::handle_fork ()
+{
+  cygheap_fixup_in_child (false);
+  memory_init (false);
+  myself.thisproc (NULL);
+  myself->uid = cygheap->user.real_uid;
+  myself->gid = cygheap->user.real_gid;
+
+  child_copy (parent, false,
+             "dll data", dll_data_start, dll_data_end,
+             "dll bss", dll_bss_start, dll_bss_end,
+             "user heap", cygheap->user_heap.base, cygheap->user_heap.ptr,
+             NULL);
+  /* step 2 now that the dll has its heap filled in, we can fill in the
+     user's data and bss since user_data is now filled out. */
+  child_copy (parent, false,
+             "data", user_data->data_start, user_data->data_end,
+             "bss", user_data->bss_start, user_data->bss_end,
+             NULL);
+
+  if (fixup_mmaps_after_fork (parent))
+    api_fatal ("recreate_mmaps_after_fork_failed");
+}
+
+void
+child_info_spawn::handle_spawn ()
+{
+  extern void fixup_lockf_after_exec ();
+  HANDLE h;
+  cygheap_fixup_in_child (true);
+  memory_init (false);
+  if (!moreinfo->myself_pinfo ||
+      !DuplicateHandle (hMainProc, moreinfo->myself_pinfo, hMainProc, &h, 0,
+                       FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+    h = NULL;
+  myself.thisproc (h);
+  __argc = moreinfo->argc;
+  __argv = moreinfo->argv;
+  envp = moreinfo->envp;
+  envc = moreinfo->envc;
+  if (!dynamically_loaded)
+    cygheap->fdtab.fixup_after_exec ();
+  if (__stdin >= 0)
+    cygheap->fdtab.move_fd (__stdin, 0);
+  if (__stdout >= 0)
+    cygheap->fdtab.move_fd (__stdout, 1);
+  cygheap->user.groups.clear_supp ();
+
+  ready (true);
+
+  /* Need to do this after debug_fixup_after_fork_exec or DEBUGGING handling of
+     handles might get confused. */
+  CloseHandle (child_proc_info->parent);
+  child_proc_info->parent = NULL;
+
+  signal_fixup_after_exec ();
+  if (moreinfo->old_title)
+    {
+      old_title = strcpy (title_buf, moreinfo->old_title);
+      cfree (moreinfo->old_title);
+    }
+  fixup_lockf_after_exec ();
+}
+
+#if 0
+/* Setting the TS-aware flag in the application's PE header is sufficient.
+   Just keep this in as a reminder. */
+
+static DEP_SYSTEM_POLICY_TYPE dep_system_policy = (DEP_SYSTEM_POLICY_TYPE) -1;
+
+static void
+disable_dep ()
+{
+  DWORD ppolicy;
+  BOOL perm;
+
+  if (dep_system_policy < 0)
+    {
+      dep_system_policy = GetSystemDEPPolicy ();
+      debug_printf ("DEP System Policy: %d", (int) dep_system_policy);
+    }
+  if (dep_system_policy < OptIn)
+    return;
+  if (!GetProcessDEPPolicy (hMainProc, &ppolicy, &perm))
+    {
+      debug_printf ("GetProcessDEPPolicy: %E");
+      return;
+    }
+  debug_printf ("DEP Process Policy: %d (permanent = %d)", ppolicy, perm);
+  if (ppolicy > 0 && !perm && !SetProcessDEPPolicy (0))
+    debug_printf ("SetProcessDEPPolicy: %E");
+}
+#endif
+
 void __stdcall
 dll_crt0_0 ()
 {
-  init_console_handler (TRUE);
+  init_global_security ();
+  initial_env ();
+
+  SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+
+  /* Initialize signal processing here, early, in the hopes that the creation
+     of a thread early in the process will cause more predictability in memory
+     layout for the main thread. */
+  if (!dynamically_loaded)
+    sigproc_init ();
+
+  lock_process::init ();
   _impure_ptr = _GLOBAL_REENT;
   _impure_ptr->_stdin = &_impure_ptr->__sf[0];
   _impure_ptr->_stdout = &_impure_ptr->__sf[1];
   _impure_ptr->_stderr = &_impure_ptr->__sf[2];
   _impure_ptr->_current_locale = "C";
-  wincap.init ();
-  initial_env ();
+  user_data->impure_ptr = _impure_ptr;
+  user_data->impure_ptr_ptr = &_impure_ptr;
 
-  init_global_security ();
   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
                       GetCurrentProcess (), &hMainProc, 0, FALSE,
                        DUPLICATE_SAME_ACCESS))
@@ -653,10 +695,9 @@ dll_crt0_0 ()
 
   DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
                   &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
-  if (wincap.has_security ())
-    OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
 
-  SetErrorMode (SEM_FAILCRITICALERRORS);
+  OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
+  set_cygwin_privileges (hProcToken);
 
   device::init ();
   do_global_ctors (&__CTOR_LIST__, 1);
@@ -664,75 +705,74 @@ dll_crt0_0 ()
 
   child_proc_info = get_cygwin_startup_info ();
   if (!child_proc_info)
-    memory_init ();
+    memory_init (true);
   else
     {
       cygwin_user_h = child_proc_info->user_h;
       switch (child_proc_info->type)
        {
          case _PROC_FORK:
-           alloc_stack (fork_info);
-           cygheap_fixup_in_child (false);
-           memory_init ();
-           set_myself (NULL);
+           fork_info->handle_fork ();
            break;
          case _PROC_SPAWN:
          case _PROC_EXEC:
-           HANDLE h;
-           cygheap_fixup_in_child (true);
-           memory_init ();
-           if (!spawn_info->moreinfo->myself_pinfo ||
-               !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
-                                 hMainProc, &h, 0, FALSE,
-                                 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
-             h = NULL;
-           set_myself (h);
-           if (child_proc_info->type != _PROC_FORK)
-             child_proc_info->ready (true);
-           __argc = spawn_info->moreinfo->argc;
-           __argv = spawn_info->moreinfo->argv;
-           envp = spawn_info->moreinfo->envp;
-           envc = spawn_info->moreinfo->envc;
-           if (!dynamically_loaded)
-             cygheap->fdtab.fixup_after_exec ();
-           signal_fixup_after_exec ();
-           if (spawn_info->moreinfo->old_title)
-             {
-               old_title = strcpy (title_buf, spawn_info->moreinfo->old_title);
-               cfree (spawn_info->moreinfo->old_title);
-             }
+           spawn_info->handle_spawn ();
            break;
        }
     }
 
+  user_data->threadinterface->Init ();
+
   _cygtls::init ();
 
   /* Initialize events */
   events_init ();
+  tty_list::init_session ();
+
+#if 0
+  /* Setting the TS-aware flag in the application's PE header is sufficient.
+     Just keep this in as a reminder. */
+
+  /* The disable_dep function disables DEP for all Cygwin processes if
+     the process runs on a Windows Server 2008 with Terminal Services
+     installed.  This combination (TS+DEP) breaks *some* Cygwin
+     applications.  The Terminal Service specific DLL tsappcmp.dll
+     changes the page protection of some pages in the application's text
+     segment from PAGE_EXECUTE_WRITECOPY to PAGE_WRITECOPY for no
+     apparent reason.  This occurs before any Cygwin or applicaton code
+     had a chance to run.  MS has no explanation for this so far, but is
+     rather busy trying to avoid giving support for this problem (as of
+     2008-11-11).
+
+     Unfortunately disabling DEP seems to have a not negligible
+     performance hit.  In the long run, either MS has to fix their
+     problem, or we have to find a better workaround, if any exists.
+     Idle idea: Adding EXECUTE protection to all text segment pages? */
+  if (wincap.ts_has_dep_problem ())
+    disable_dep ();
+#endif
 
-  cygheap->cwd.init ();
-
-  /* Late duplicate simplifies tweaking the process token in uinfo.cc. */
-  if (wincap.has_security ())
-    DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED, NULL,
-                     SecurityImpersonation, TokenImpersonation,
-                     &hProcImpToken);
+  debug_printf ("finished dll_crt0_0 initialization");
 }
 
 /* Take over from libc's crt0.o and start the application. Note the
    various special cases when Cygwin DLL is being runtime loaded (as
    opposed to being link-time loaded by Cygwin apps) from a non
    cygwin app via LoadLibrary.  */
-static void
-dll_crt0_1 (char *)
+void
+dll_crt0_1 (void *)
 {
-  /* According to onno@stack.urc.tue.nl, the exception handler record must
-     be on the stack.  */
-  /* FIXME: Verify forked children get their exception handler set up ok. */
-  exception_list cygwin_except_entry;
-
+  if (dynamically_loaded)
+    sigproc_init ();
   check_sanity_and_sync (user_data);
+
+  /* Initialize malloc and then call user_shared_initialize since it relies
+     on a functioning malloc and it's possible that the user's program may
+     have overridden malloc.  We only know about that at this stage,
+     unfortunately. */
   malloc_init ();
+  user_shared_initialize ();
+
 #ifdef CGF
   int i = 0;
   const int n = 2 * 1024 * 1024;
@@ -740,24 +780,21 @@ dll_crt0_1 (char *)
     small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n));
 #endif
 
-  /* Initialize SIGSEGV handling, etc. */
-  init_exceptions (&cygwin_except_entry);
-
-  user_data->resourcelocks->Init ();
-  user_data->threadinterface->Init ();
   ProtectHandle (hMainProc);
   ProtectHandle (hMainThread);
 
+  cygheap->cwd.init ();
+
   /* Initialize pthread mainthread when not forked and it is safe to call new,
      otherwise it is reinitalized in fixup_after_fork */
-  if (!user_data->forkee)
+  if (!in_forkee)
     pthread::init_mainthread ();
 
 #ifdef DEBUGGING
   strace.microseconds ();
 #endif
 
-  create_signal_arrived ();
+  create_signal_arrived (); /* FIXME: move into wait_sig? */
 
   /* Initialize debug muto, if DLL is built with --enable-debugging.
      Need to do this before any helper threads start. */
@@ -769,7 +806,7 @@ dll_crt0_1 (char *)
 #endif
 
   cygbench ("pre-forkee");
-  if (user_data->forkee)
+  if (in_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
@@ -782,7 +819,9 @@ dll_crt0_1 (char *)
        {
          _tlsbase = (char *) fork_info->stackbottom;
          _tlstop = (char *) fork_info->stacktop;
+         _my_tls.init_exception_handler (_cygtls::handle_exceptions);
        }
+
       longjmp (fork_info->jmp, true);
     }
 
@@ -792,36 +831,30 @@ dll_crt0_1 (char *)
   fork_init ();
   }
 #endif
-
-  /* Initialize our process table entry. */
   pinfo_init (envp, envc);
 
-  /* Can be set only after environment has been initialized. */
-  if (wincap.has_security ())
-    set_cygwin_privileges (hProcImpToken);
-
   if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
-      old_title = title_buf;
+    old_title = title_buf;
 
   /* Allocate cygheap->fdtab */
   dtable_init ();
 
-  /* Initialize user info. */
-  uinfo_init ();
+  uinfo_init ();       /* initialize user info */
 
-  /* Initialize signal/subprocess handling. */
-  sigproc_init ();
+  wait_for_sigthread ();
+  extern DWORD threadfunc_ix;
+  if (!threadfunc_ix)
+    system_printf ("internal error: couldn't determine location of thread function on stack.  Expect signal problems.");
 
   /* Connect to tty. */
-  tty_init ();
+  tty::init_session ();
 
   if (!__argc)
     {
-      char *line = GetCommandLineA ();
-      line = strcpy ((char *) alloca (strlen (line) + 1), line);
-
-      if (current_codepage == oem_cp)
-       CharToOemA (line, line);
+      PWCHAR wline = GetCommandLineW ();
+      size_t size = sys_wcstombs (NULL, 0, wline);
+      char *line = (char *) alloca (size);
+      sys_wcstombs (line, size, wline);
 
       /* Scan the command line and build argv.  Expand wildcards if not
         called from another cygwin process. */
@@ -832,8 +865,9 @@ dll_crt0_1 (char *)
         win32 style. */
       if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\')))
        {
-         char *new_argv0 = (char *) malloc (CYG_MAX_PATH);
-         cygwin_conv_to_posix_path (__argv[0], new_argv0);
+         char *new_argv0 = (char *) malloc (NT_MAX_PATH);
+         cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, __argv[0],
+                           new_argv0, NT_MAX_PATH);
          __argv[0] = (char *) realloc (new_argv0, strlen (new_argv0) + 1);
        }
     }
@@ -854,7 +888,7 @@ dll_crt0_1 (char *)
   if (__progname)
     {
       char *cp = strchr (__progname, '\0') - 4;
-      if (cp > __progname && strcasematch (cp, ".exe"))
+      if (cp > __progname && ascii_strcasematch (cp, ".exe"))
        *cp = '\0';
     }
 
@@ -890,7 +924,6 @@ dll_crt0_1 (char *)
   /* Disable case-insensitive globbing */
   ignore_case_with_glob = false;
 
-
   set_errno (0);
 
   MALLOC_CHECK;
@@ -899,66 +932,35 @@ dll_crt0_1 (char *)
   /* 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. */
-  wait_for_sigthread ();
   ld_preload ();
+  /* Reset current application locale to "C" per POSIX */
+  _setlocale_r (_REENT, LC_CTYPE, "C");
   if (user_data->main)
     cygwin_exit (user_data->main (__argc, __argv, *user_data->envptr));
+  __asm__ ("                           \n\
+       .global __cygwin_exit_return    \n\
+__cygwin_exit_return:                  \n\
+");
 }
 
-struct _reent *
-initialize_main_tls (char *padding)
-{
-  if (!_main_tls)
-    {
-      _main_tls = &_my_tls;
-      _main_tls->init_thread (padding, NULL);
-    }
-  return &_main_tls->local_clib;
-}
-
-/* Wrap the real one, otherwise gdb gets confused about
-   two symbols with the same name, but different addresses.
-
-   UPTR is a pointer to global data that lives on the libc side of the
-   line [if one distinguishes the application from the dll].  */
-
 extern "C" void __stdcall
 _dll_crt0 ()
 {
-  extern HANDLE sync_startup;
-  extern unsigned threadfunc_ix;
-  if (threadfunc_ix)
-    /* nothing to do */;
-  else if (!sync_startup)
-    system_printf ("internal error: sync_startup not called at start.  Expect signal problems.");
-  else
-    {
-      WaitForSingleObject (sync_startup, INFINITE);
-      CloseHandle (sync_startup);
-    }
-
-  if (!threadfunc_ix)
-    system_printf ("internal error: couldn't determine location of thread function on stack.  Expect signal problems.");
-
   main_environ = user_data->envptr;
-  *main_environ = NULL;
-
-  char padding[CYGTLS_PADSIZE];
-
-  if (child_proc_info && child_proc_info->type == _PROC_FORK)
-    user_data->forkee = true;
+  if (in_forkee)
+    fork_info->alloc_stack ();
   else
     __sinit (_impure_ptr);
 
-  initialize_main_tls (padding);
-  dll_crt0_1 (padding);
+  _main_tls = &_my_tls;
+  _main_tls->call ((DWORD (*) (void *, void *)) dll_crt0_1, NULL);
 }
 
 void
 dll_crt0 (per_process *uptr)
 {
   /* Set the local copy of the pointer into the user space. */
-  if (uptr && uptr != user_data)
+  if (!in_forkee && uptr && uptr != user_data)
     {
       memcpy (user_data, uptr, per_process_overwrite);
       *(user_data->impure_ptr_ptr) = _GLOBAL_REENT;
@@ -980,33 +982,30 @@ cygwin_dll_init ()
   static char **envp;
   static int _fmode;
 
-  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
-                      GetCurrentProcess (), &hMainProc, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS))
-    hMainProc = GetCurrentProcess ();
-
-  DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
-                  &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
   user_data->magic_biscuit = sizeof (per_process);
 
   user_data->envptr = &envp;
   user_data->fmode_ptr = &_fmode;
 
-  main_environ = user_data->envptr;
-  *main_environ = NULL;
-  initialize_main_tls((char *)&_my_tls);
-  dll_crt0_1 (NULL);
+  _dll_crt0 ();
 }
 
 extern "C" void
 __main (void)
 {
+  /* Ordering is critical here.  DLL ctors have already been
+     run as they were being loaded, so we should stack the 
+     queued call to DLL dtors now.  */
+  atexit (dll_global_dtors);
   do_global_ctors (user_data->ctors, false);
+  /* Now we have run global ctors, register their dtors.  */
   atexit (do_global_dtors);
+  /* At exit, global dtors will run first, so the app can still
+     use shared library functions while terminating; then the
+     DLLs will be destroyed; finally newlib will shut down stdio
+     and terminate itself.  */
 }
 
-exit_states NO_COPY exit_state;
-
 void __stdcall
 do_exit (int status)
 {
@@ -1021,13 +1020,7 @@ do_exit (int status)
     }
 #endif
 
-  get_exit_lock ();
-
-  if (exit_state < ES_GLOBAL_DTORS)
-    {
-      exit_state = ES_GLOBAL_DTORS;
-      dll_global_dtors ();
-    }
+  lock_process until_exit (true);
 
   if (exit_state < ES_EVENTS_TERMINATE)
     {
@@ -1065,10 +1058,9 @@ do_exit (int status)
       /* Kill orphaned children on group leader exit */
       if (myself->has_pgid_children && myself->pid == myself->pgid)
        {
-         siginfo_t si;
+         siginfo_t si = {0};
          si.si_signo = -SIGHUP;
          si.si_code = SI_KERNEL;
-         si.si_pid = si.si_uid = si.si_errno = 0;
          sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children",
                          myself->pid, myself->pgid);
          kill_pgrp (myself->pgid, si);
@@ -1103,10 +1095,9 @@ do_exit (int status)
   if (exit_state < ES_TTY_TERMINATE)
     {
       exit_state = ES_TTY_TERMINATE;
-      tty_terminate ();
+      cygwin_shared->tty.terminate ();
     }
 
-  minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
   myself.exit (n);
 }
 
@@ -1126,7 +1117,6 @@ cygwin_atexit (void (*function)(void))
 extern "C" void
 cygwin_exit (int n)
 {
-  dll_global_dtors ();
   if (atexit_lock)
     atexit_lock.acquire ();
   exit (n);
@@ -1138,17 +1128,6 @@ _exit (int n)
   do_exit (((DWORD) n & 0xff) << 8);
 }
 
-void
-get_exit_lock ()
-{
-  myself.lock ();
-  if (exit_state < ES_SET_MUTO)
-    {
-      exit_state = ES_SET_MUTO;
-      muto::set_exiting_thread ();
-    }
-}
-
 extern "C" void
 __api_fatal (const char *fmt, ...)
 {
@@ -1156,29 +1135,15 @@ __api_fatal (const char *fmt, ...)
   va_list ap;
 
   va_start (ap, fmt);
-  int n = __small_sprintf (buf, "%P (%u): *** ", cygwin_pid (GetCurrentProcessId ()));
+  int n = __small_sprintf (buf, "%P: *** fatal error - ");
   __small_vsprintf (buf + n, fmt, ap);
   va_end (ap);
-  strcat (buf, "\n");
-  int len = strlen (buf);
-  DWORD done;
-  WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
-
-  /* Make sure that the message shows up on the screen, too, since this is
-     a serious error. */
-  if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR)
-    {
-      HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
-                            FILE_SHARE_WRITE | FILE_SHARE_WRITE,
-                            &sec_none, OPEN_EXISTING, 0, 0);
-      if (h != INVALID_HANDLE_VALUE)
-       WriteFile (h, buf, len, &done, 0);
-    }
+  strace.prntf (_STRACE_SYSTEM, NULL, "%s", buf);
 
 #ifdef DEBUGGING
   try_to_debug ();
 #endif
-  myself.exit (1);
+  myself.exit (__api_fatal_exit_val);
 }
 
 void
@@ -1190,8 +1155,7 @@ multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned vers
       return;
     }
 
-  char buf[1024];
-  if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf)))
+  if (GetEnvironmentVariableA ("CYGWIN_MISMATCH_OK", NULL, 0))
     return;
 
   if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version)
@@ -1211,8 +1175,7 @@ are unable to find another cygwin DLL.",
 void __stdcall
 cygbench (const char *s)
 {
-  char buf[1024];
-  if (GetEnvironmentVariable ("CYGWIN_BENCH", buf, sizeof (buf)))
+  if (GetEnvironmentVariableA ("CYGWIN_BENCH", NULL, 0))
     small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ());
 }
 #endif