/* dcrt0.cc -- essentially the main() for the Cygwin dll
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007 Red Hat, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
This file is part of Cygwin.
details. */
#include "winsup.h"
+#include "miscfuncs.h"
#include <unistd.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include "glob.h"
-#include "exceptions.h"
#include <ctype.h>
-#include <limits.h>
-#include <winnls.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"
#include "shared_info.h"
#include "cygwin_version.h"
#include "dll_init.h"
-#include "sync.h"
#include "heap.h"
-#include "environ.h"
+#include "tls_pbuf.h"
+#include "exception.h"
+#include "cygxdr.h"
+#include "fenv.h"
+#include "ntdll.h"
+#include "wow64.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 lock_process::locker;
-
-bool display_title;
-bool strip_title_path;
-bool allow_glob = true;
-bool NO_COPY in_forkee;
-
-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 __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;
-
-MTinterface _mtinterf;
-
-bool NO_COPY _cygwin_testing;
-
-char NO_COPY almost_null[1];
-
-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 = &__cygwin_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},
- /* UNUSED forkee */ 0,
- /* hmodule */ NULL,
- /* api_major */ CYGWIN_VERSION_API_MAJOR,
- /* api_minor */ CYGWIN_VERSION_API_MINOR,
- /* unused2 */ {0, 0, 0, 0, 0, 0},
- /* threadinterface */ &_mtinterf,
- /* impure_ptr */ _GLOBAL_REENT,
- };
- bool ignore_case_with_glob;
- int __declspec (dllexport) _check_for_executable = true;
-#ifdef DEBUGGING
- int pinger;
-#endif
- int NO_COPY __api_fatal_exit_val = 1;
-};
+static int NO_COPY envc;
+static char NO_COPY **envp;
-char *old_title;
-char title_buf[TITLESIZE + 1];
+bool NO_COPY jit_debug;
static void
do_global_dtors ()
{
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_VALID_FLAGS, /* 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)
{
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--;
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;
+ /* This is a kludge to work around a version of _cygwin_common_crt0
+ which overwrote the cxx_malloc field with the local DLL copy.
+ Hilarity ensues if the DLL is not loaded while the process
+ is forking. */
+ __cygwin_user_data.cxx_malloc = &default_cygwin_cxx_malloc;
}
child_info NO_COPY *child_proc_info = NULL;
-#define CYGWIN_GUARD (PAGE_EXECUTE_READWRITE | PAGE_GUARD)
+#define CYGWIN_GUARD (PAGE_READWRITE | PAGE_GUARD)
void
child_info_fork::alloc_stack_hard_way (volatile char *b)
{
- void *new_stack_pointer;
- MEMORY_BASIC_INFORMATION m;
- void *newbase;
- int newlen;
- 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 (stacktop > (LPBYTE) m.AllocationBase && stacktop < curbot)
- {
- newbase = curbot;
- newlen = (LPBYTE) stackbottom - (LPBYTE) curbot;
- guard = false;
- }
- else
- {
- newbase = (LPBYTE) stacktop - (128 * 1024);
- newlen = (LPBYTE) stackbottom - (LPBYTE) newbase;
- guard = true;
- }
+ void *stack_ptr;
+ DWORD stacksize;
+
+ /* First check if the requested stack area is part of the user heap
+ or part of a mmapped region. If so, we have been started from a
+ pthread with an application-provided stack, and the stack has just
+ to be used as is. */
+ if ((stacktop >= cygheap->user_heap.base
+ && stackbottom <= cygheap->user_heap.max)
+ || is_mmapped_region ((caddr_t) stacktop, (caddr_t) stackbottom))
+ return;
- if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
+ /* First, try to reserve the entire stack. */
+ stacksize = (char *) stackbottom - (char *) stackaddr;
+ if (!VirtualAlloc (stackaddr, stacksize, MEM_RESERVE, PAGE_NOACCESS))
api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
- 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, stacksize);
- if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
- api_fatal ("fork: couldn't get new stack info, %E");
-
- if (guard)
+ stackaddr, stackbottom);
+ stacksize = (char *) stackbottom - (char *) stacktop;
+ stack_ptr = VirtualAlloc (stacktop, stacksize, MEM_COMMIT, PAGE_READWRITE);
+ if (!stack_ptr)
+ abort ("can't commit memory for stack %p(%d), %E", stacktop, stacksize);
+ if (guardsize != (size_t) -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",
- m.BaseAddress);
+ /* Allocate PAGE_GUARD page if it still fits. */
+ if (stack_ptr > stackaddr)
+ {
+ stack_ptr = (void *) ((LPBYTE) stack_ptr
+ - wincap.page_size ());
+ if (!VirtualAlloc (stack_ptr, wincap.page_size (), MEM_COMMIT,
+ CYGWIN_GUARD))
+ api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
+ stack_ptr);
+ }
+ /* Allocate POSIX guard pages. */
+ if (guardsize > 0)
+ VirtualAlloc (stackaddr, guardsize, MEM_COMMIT, PAGE_NOACCESS);
}
- if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
- api_fatal ("fork: couldn't get new stack info, %E");
- stacktop = m.BaseAddress;
b[0] = '\0';
}
{
volatile char * volatile esp;
__asm__ volatile ("movl %%esp,%0": "=r" (esp));
- if (_tlsbase != stackbottom)
+ /* Make sure not to try a hard allocation if we have been forked off from
+ the main thread of a Cygwin process which has been started from a 64 bit
+ parent. In that case the _tlsbase of the forked child is not the same
+ as the _tlsbase of the parent (== stackbottom), but only because the
+ stack of the parent has been slightly rearranged. See comment in
+ wow64_revert_to_original_stack for details. We check here if the
+ parent stack fits into the child stack. */
+ if (_tlsbase != stackbottom
+ && (!wincap.is_wow64 ()
+ || stacktop < (char *) NtCurrentTeb ()->DeallocationStack
+ || stackbottom > _tlsbase))
alloc_stack_hard_way (esp);
else
{
char *st = (char *) stacktop - 4096;
while (_tlstop >= st)
esp = getstack (esp);
- stacksize = 0;
+ stackaddr = 0;
+ /* This only affects forked children of a process started from a native
+ 64 bit process, but it doesn't hurt to do it unconditionally. Fix
+ StackBase in the child to be the same as in the parent, so that the
+ computation of _my_tls is correct. */
+ _tlsbase = (char *) stackbottom;
}
}
static void
initial_env ()
{
- char buf[NT_MAX_PATH];
- if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+ if (GetEnvironmentVariableA ("CYGWIN_TESTING", NULL, 0))
_cygwin_testing = 1;
#ifdef DEBUGGING
DWORD len;
-
- if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
- {
- DWORD ms = atoi (buf);
- console_printf ("Sleeping %d, pid %u %P\n", ms, GetCurrentProcessId ());
- Sleep (ms);
- if (!strace.active () && !dynamically_loaded)
- strace.hello ();
- }
- if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
+ char buf[NT_MAX_PATH];
+ if (GetEnvironmentVariableA ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
{
char buf1[NT_MAX_PATH];
len = GetModuleFileName (NULL, buf1, NT_MAX_PATH);
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");
break_here ();
}
}
#endif
-
}
child_info *
if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res
|| res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC)
- res = NULL;
+ {
+ strace.activate (false);
+ res = NULL;
+ }
else
{
if ((res->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
unsigned should_be_cb = 0;
switch (res->type)
{
- case _PROC_FORK:
+ case _CH_FORK:
in_forkee = true;
should_be_cb = sizeof (child_info_fork);
/* fall through */;
- case _PROC_SPAWN:
- case _PROC_EXEC:
+ case _CH_SPAWN:
+ case _CH_EXEC:
if (!should_be_cb)
should_be_cb = sizeof (child_info_spawn);
if (should_be_cb != res->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 ();
+ while (!being_debugged ())
+ yield ();
+ strace.activate (res->type == _CH_FORK);
}
break;
default:
system_printf ("unknown exec type %d", res->type);
/* intentionally fall through */
- case _PROC_WHOOPS:
+ case _CH_WHOOPS:
res = NULL;
break;
}
child_info_fork::handle_fork ()
{
cygheap_fixup_in_child (false);
- memory_init ();
- set_myself (NULL);
+ memory_init (false);
+ myself.thisproc (NULL);
myself->uid = cygheap->user.real_uid;
myself->gid = cygheap->user.real_gid;
"dll bss", dll_bss_start, dll_bss_end,
"user heap", cygheap->user_heap.base, cygheap->user_heap.ptr,
NULL);
+
+ /* Do the relocations here. These will actually likely be overwritten by the
+ below child_copy but we do them here in case there is a read-only section
+ which does not get copied by fork. */
+ _pei386_runtime_relocator (user_data);
+
/* 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,
void
child_info_spawn::handle_spawn ()
{
+ extern void fixup_lockf_after_exec ();
HANDLE h;
cygheap_fixup_in_child (true);
- memory_init ();
+ memory_init (false);
if (!moreinfo->myself_pinfo ||
- !DuplicateHandle (hMainProc, moreinfo->myself_pinfo, hMainProc, &h, 0,
+ !DuplicateHandle (GetCurrentProcess (), moreinfo->myself_pinfo,
+ GetCurrentProcess (), &h, 0,
FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
h = NULL;
- set_myself (h);
+ myself.thisproc (h);
__argc = moreinfo->argc;
__argv = moreinfo->argv;
envp = moreinfo->envp;
cygheap->fdtab.move_fd (__stdin, 0);
if (__stdout >= 0)
cygheap->fdtab.move_fd (__stdout, 1);
+ cygheap->user.groups.clear_supp ();
+
+ /* If we're execing we may have "inherited" a list of children forked by the
+ previous process executing under this pid. Reattach them here so that we
+ can wait for them. */
+ if (type == _CH_EXEC)
+ reattach_children ();
ready (true);
child_proc_info->parent = NULL;
signal_fixup_after_exec ();
- if (moreinfo->old_title)
+ fixup_lockf_after_exec ();
+}
+
+/* Retrieve and store system directory for later use. Note that the
+ directory is stored with a trailing backslash! */
+static void
+init_windows_system_directory ()
+{
+ if (!windows_system_directory_length)
{
- old_title = strcpy (title_buf, moreinfo->old_title);
- cfree (moreinfo->old_title);
+ windows_system_directory_length =
+ GetSystemDirectoryW (windows_system_directory, MAX_PATH);
+ if (windows_system_directory_length == 0)
+ api_fatal ("can't find windows system directory");
+ windows_system_directory[windows_system_directory_length++] = L'\\';
+ windows_system_directory[windows_system_directory_length] = L'\0';
+
+ system_wow64_directory_length =
+ GetSystemWow64DirectoryW (system_wow64_directory, MAX_PATH);
+ if (system_wow64_directory_length)
+ {
+ system_wow64_directory[system_wow64_directory_length++] = L'\\';
+ system_wow64_directory[system_wow64_directory_length] = L'\0';
+ }
}
}
-void __stdcall
+void
dll_crt0_0 ()
{
+ child_proc_info = get_cygwin_startup_info ();
+ init_windows_system_directory ();
init_global_security ();
initial_env ();
- SetErrorMode (SEM_FAILCRITICALERRORS);
-
- /* 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. */
- sigproc_init ();
+ SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
lock_process::init ();
_impure_ptr = _GLOBAL_REENT;
user_data->impure_ptr = _impure_ptr;
user_data->impure_ptr_ptr = &_impure_ptr;
- if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
- GetCurrentProcess (), &hMainProc, 0, FALSE,
- DUPLICATE_SAME_ACCESS))
- hMainProc = GetCurrentProcess ();
+ DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+ GetCurrentProcess (), &hMainThread,
+ 0, false, DUPLICATE_SAME_ACCESS);
- DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
- &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
-
- OpenProcessToken (hMainProc, MAXIMUM_ALLOWED, &hProcToken);
+ NtOpenProcessToken (NtCurrentProcess (), MAXIMUM_ALLOWED, &hProcToken);
set_cygwin_privileges (hProcToken);
device::init ();
do_global_ctors (&__CTOR_LIST__, 1);
cygthread::init ();
- child_proc_info = get_cygwin_startup_info ();
if (!child_proc_info)
- memory_init ();
+ {
+ memory_init (true);
+ /* WOW64 process? Check if we have been started from 64 bit process
+ and if our stack is at an unusual address. Set wow64_has_64bit_parent
+ if so. Problem description in wow64_test_for_64bit_parent. */
+ if (wincap.is_wow64 ())
+ wow64_has_64bit_parent = wow64_test_for_64bit_parent ();
+ }
else
{
cygwin_user_h = child_proc_info->user_h;
switch (child_proc_info->type)
{
- case _PROC_FORK:
+ case _CH_FORK:
fork_info->handle_fork ();
break;
- case _PROC_SPAWN:
- case _PROC_EXEC:
+ case _CH_SPAWN:
+ case _CH_EXEC:
spawn_info->handle_spawn ();
break;
}
events_init ();
tty_list::init_session ();
- cygheap->cwd.init ();
+ _main_tls = &_my_tls;
+
+ /* 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 ();
debug_printf ("finished dll_crt0_0 initialization");
}
void
dll_crt0_1 (void *)
{
+ extern void initial_setlocale ();
+
+ 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 ();
-#ifdef CGF
+ user_shared->initialize ();
+
+#ifdef CYGHEAP_DEBUG
int i = 0;
const int n = 2 * 1024 * 1024;
while (i--)
- small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n));
+ {
+ void *p = cmalloc (HEAP_STR, n);
+ if (p)
+ small_printf ("cmalloc returns %p\n", cmalloc (HEAP_STR, n));
+ else
+ {
+ small_printf ("total allocated %p\n", (i - 1) * n);
+ break;
+ }
+ }
#endif
- 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 (!in_forkee)
- pthread::init_mainthread ();
+ {
+ pthread::init_mainthread ();
+ _pei386_runtime_relocator (user_data);
+ }
#ifdef DEBUGGING
strace.microseconds ();
NOTE: Don't do anything that involves the stack until you've completed
this step. */
- if (fork_info->stacksize)
+ if (fork_info->stackaddr)
{
_tlsbase = (char *) fork_info->stackbottom;
_tlstop = (char *) fork_info->stacktop;
- _my_tls.init_exception_handler (_cygtls::handle_exceptions);
}
longjmp (fork_info->jmp, true);
}
+ __sinit (_impure_ptr);
+
#ifdef DEBUGGING
{
extern void fork_init ();
}
#endif
pinfo_init (envp, envc);
-
- if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
- old_title = title_buf;
+ strace.dll_info ();
/* Allocate cygheap->fdtab */
dtable_init ();
uinfo_init (); /* initialize user info */
- 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_session ();
+ /* Set internal locale to the environment settings. */
+ initial_setlocale ();
+
if (!__argc)
{
PWCHAR wline = GetCommandLineW ();
if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\')))
{
char *new_argv0 = (char *) malloc (NT_MAX_PATH);
- cygwin_conv_to_posix_path (__argv[0], new_argv0);
+ 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);
}
}
++__progname;
else
__progname = __argv[0];
+ program_invocation_name = __argv[0];
+ program_invocation_short_name = __progname;
if (__progname)
{
char *cp = strchr (__progname, '\0') - 4;
*cp = '\0';
}
- /* Set new console title if appropriate. */
-
- if (display_title && !dynamically_loaded)
- {
- char *cp = __progname;
- if (strip_title_path)
- for (char *ptr = cp; *ptr && *ptr != ' '; ptr++)
- if (isdirsep (*ptr))
- cp = ptr + 1;
- set_console_title (cp);
- }
-
+ (void) xdr_set_vprintf (&cygxdr_vwarnx);
cygwin_finished_initializing = true;
/* Call init of loaded dlls. */
dlls.init ();
for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++)
user_data->premain[i] (__argc, __argv, user_data);
- debug_printf ("user_data->main %p", user_data->main);
+ set_errno (0);
if (dynamically_loaded)
{
- set_errno (0);
+ _setlocale_r (_REENT, LC_CTYPE, "C");
return;
}
/* Disable case-insensitive globbing */
ignore_case_with_glob = false;
- set_errno (0);
-
MALLOC_CHECK;
cygbench (__progname);
- /* 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. */
ld_preload ();
+ /* Per POSIX set the default application locale back to "C". */
+ _setlocale_r (_REENT, LC_CTYPE, "C");
+
if (user_data->main)
- cygwin_exit (user_data->main (__argc, __argv, *user_data->envptr));
+ {
+ /* Create a copy of Cygwin's version of __argv so that, if the user makes
+ a change to an element of argv[] it does not affect Cygwin's argv.
+ Changing the the contents of what argv[n] points to will still
+ affect Cygwin. This is similar (but not exactly like) Linux. */
+ char *newargv[__argc + 1];
+ char **nav = newargv;
+ char **oav = __argv;
+ while ((*nav++ = *oav++) != NULL)
+ continue;
+ cygwin_exit (user_data->main (__argc, newargv, *user_data->envptr));
+ }
+ __asm__ (" \n\
+ .global __cygwin_exit_return \n\
+__cygwin_exit_return: \n\
+");
}
extern "C" void __stdcall
_dll_crt0 ()
{
+ /* Handle WOW64 process started from native 64 bit process. See comment
+ in wow64_test_for_64bit_parent for a full problem description. */
+ if (wow64_has_64bit_parent && !dynamically_loaded)
+ {
+ /* Must be static since it's referenced after the stack pointers have
+ been moved. */
+ static PVOID allocationbase = 0;
+
+ /* Check if we just move the stack. See comment in
+ wow64_revert_to_original_stack for the gory details. */
+ PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
+ if (stackaddr)
+ {
+ /* 2nd half of the stack move. Set stack pointers to new address. */
+ __asm__ ("\n\
+ movl %[ADDR], %%esp \n\
+ movl %%esp, %%ebp \n"
+ : : [ADDR] "r" (stackaddr));
+ /* Now we're back on the original stack. Free up space taken by the
+ former main thread stack and set DeallocationStack correctly. */
+ VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
+ NtCurrentTeb ()->DeallocationStack = allocationbase;
+ }
+ else
+ /* Fall back to respawn if wow64_revert_to_original_stack fails. */
+ wow64_respawn_process ();
+ }
+#ifdef __i386__
+ _feinitialise ();
+#endif
main_environ = user_data->envptr;
if (in_forkee)
- fork_info->alloc_stack ();
- else
- __sinit (_impure_ptr);
+ {
+ fork_info->alloc_stack ();
+ _main_tls = &_my_tls;
+ }
- _main_tls = &_my_tls;
_main_tls->call ((DWORD (*) (void *, void *)) dll_crt0_1, NULL);
}
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.
+
+ 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. */
atexit (do_global_dtors);
+ sig_dispatch_pending (true);
}
-exit_states NO_COPY exit_state;
-
void __stdcall
do_exit (int status)
{
lock_process until_exit (true);
- if (exit_state < ES_GLOBAL_DTORS)
- {
- exit_state = ES_GLOBAL_DTORS;
- dll_global_dtors ();
- }
-
if (exit_state < ES_EVENTS_TERMINATE)
{
exit_state = ES_EVENTS_TERMINATE;
events_terminate ();
}
- UINT n = (UINT) status;
- if (exit_state < ES_THREADTERM)
- {
- exit_state = ES_THREADTERM;
- cygthread::terminate ();
- }
-
if (exit_state < ES_SIGNAL)
{
exit_state = ES_SIGNAL;
close_all_files ();
}
+ UINT n = (UINT) status;
+ if (exit_state < ES_THREADTERM)
+ {
+ exit_state = ES_THREADTERM;
+ cygthread::terminate ();
+ }
+
myself->stopsig = 0;
if (exit_state < ES_HUP_PGRP)
}
- if (exit_state < ES_TITLE)
- {
- exit_state = ES_TITLE;
- /* restore console title */
- if (old_title && display_title)
- set_console_title (old_title);
- }
-
- if (exit_state < ES_TTY_TERMINATE)
- {
- exit_state = ES_TTY_TERMINATE;
- cygwin_shared->tty.terminate ();
- }
-
myself.exit (n);
}
-static NO_COPY muto atexit_lock;
-
extern "C" int
-cygwin_atexit (void (*function)(void))
+cygwin_atexit (void (*fn) (void))
{
int res;
- atexit_lock.init ("atexit_lock");
- atexit_lock.acquire ();
- res = atexit (function);
- atexit_lock.release ();
+ dll *d = dlls.find ((void *) _my_tls.retaddr ());
+ res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d) : atexit (fn);
return res;
}
extern "C" void
cygwin_exit (int n)
{
- dll_global_dtors ();
- if (atexit_lock)
- atexit_lock.acquire ();
+ exit_state = ES_EXIT_STARTING;
exit (n);
}
do_exit (((DWORD) n & 0xff) << 8);
}
+extern "C" void cygwin_stackdump ();
+
extern "C" void
-__api_fatal (const char *fmt, ...)
+vapi_fatal (const char *fmt, va_list ap)
{
char buf[4096];
- va_list ap;
-
- va_start (ap, fmt);
- int n = __small_sprintf (buf, "%P: *** fatal error - ");
+ int n = __small_sprintf (buf, "%P: *** fatal error %s- ", in_forkee ? "in forked process " : "");
__small_vsprintf (buf + n, fmt, ap);
va_end (ap);
strace.prntf (_STRACE_SYSTEM, NULL, "%s", buf);
#ifdef DEBUGGING
try_to_debug ();
#endif
+ cygwin_stackdump ();
myself.exit (__api_fatal_exit_val);
}
+extern "C" void
+api_fatal (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vapi_fatal (fmt, ap);
+}
+
void
multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version)
{
if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap")))
{
- child_proc_info->type = _PROC_WHOOPS;
+ child_proc_info->type = _CH_WHOOPS;
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)
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