summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Korn <dave.korn.cygwin@gmail.com>2010-02-02 01:54:55 +0000
committerDave Korn <dave.korn.cygwin@gmail.com>2010-02-02 01:54:55 +0000
commita3906150100103ab8e268f9ad0785fca83341e9f (patch)
tree77f12186ff42abea5a544244be91f848716fbbdd
parent50da6b49eda0cf16c276b2b3ad74c0d2db9be8a2 (diff)
downloadcygnal-a3906150100103ab8e268f9ad0785fca83341e9f.tar.gz
cygnal-a3906150100103ab8e268f9ad0785fca83341e9f.tar.bz2
cygnal-a3906150100103ab8e268f9ad0785fca83341e9f.zip
* how-startup-shutdown-works.txt: Add new document.
-rw-r--r--winsup/cygwin/ChangeLog4
-rwxr-xr-xwinsup/cygwin/how-startup-shutdown-works.txt165
2 files changed, 169 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 4571a2c08..f49a31c8e 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,7 @@
+2010-02-02 Dave Korn <dave.korn.cygwin@gmail.com>
+
+ * how-startup-shutdown-works.txt: Add new document.
+
2010-01-29 Corinna Vinschen <corinna@vinschen.de>
* sec_auth.cc (lsaauth): Use CYG_LSA_MAGIC as checksum start value to
diff --git a/winsup/cygwin/how-startup-shutdown-works.txt b/winsup/cygwin/how-startup-shutdown-works.txt
new file mode 100755
index 000000000..578deeb30
--- /dev/null
+++ b/winsup/cygwin/how-startup-shutdown-works.txt
@@ -0,0 +1,165 @@
+Copyright 2010 Red Hat Inc., contributed by Dave Korn.
+
+
+ How the C runtime handles startup and termination.
+ --------------------------------------------------
+
+This file documents the processes involved in starting up and shutting down
+a Cygwin executable. The responsibility is divided between code that is
+statically linked into each Cygwin-based DLL or executable as part of the
+C runtime, and code in the Cygwin DLL itself that co-operates with it. The
+runtime library code lives in the winsup/cygwin/lib directory, and a little
+of it is in winsup/cygwin/include/cygwin/cygwin_dll.h
+
+
+
+ Process overall startup sequence.
+ =================================
+
+Overall process startup (and indeed termination) is under the control of the
+underlying Windows OS. The details of the Win32 CreateProcess API and the
+underlying NT Native API ZwCreateProcess calls are far more complex (and
+unknown, since proprietary) than we need go into here; the important details
+are that the process address space is first created, then an initial thread
+is spawned that performs DLL initialisation, calling the DllMain functions of
+all statically-linked DLLs in load order. This thread is also serialised under
+the Windows OS global loader lock, and DllMain functions are very limited in
+what they can do as a consequence; to help deal with this, cygwin wraps the
+user's DllMain function and defers calling it until runtime. Once the DLLs
+have been initialised, the initial thread then performs C runtime setup and
+calls into the executable's main() function.
+
+
+ Entry sequence for Cygwin-based DLLs.
+ =====================================
+
+In the compiler's LINK_SPEC, a -e option sets the entry point (what Windows
+regards as DllMain) to __cygwin_dll_entry@12. This is defined in
+include/cygwin/cygwin_dll.h. The user's DllMain function, if any, is called
+from within this function - directly in the case of thread attach/detach
+notifications and process detach, but indirectly at process attach time via
+cygwin_attach_dll in lib/cygwin_attach_dll.c, which calls the CRT common code
+_cygwin_crt0_common and then hands off to the Cygwin DLL at dll_dllcrt0. The
+CRT common code doesn't call the user DllMain at once; it caches a pointer to
+it in the 'main' member of the DLL's per_process struct.
+
+
+ __cygwin_dll_entry@12 -> cygwin_attach_dll -> (_cygwin_crt0_common)
+ -> dll_dllcrt0 -> (DllMain?maybe?)
+
+dll_dllcrt0 is in dll_init.cc sets up exception handler, ensures cygwin DLL is
+at least partially initialised, allocates a new entry for the DLL chain, and
+either calls the 'main' function (via dll::init) before returning to the OS
+loader, or defers doing so until dll_crt0_1 runs dlls.dll_list::init() during
+the application's startup sequence, depending on whether Cygwin DLL was fully
+initialised yet or not. In general statically linked DLLs will defer, while
+dlopen'd DLLs will run at once. The Cygwin DLL runs the dependent DLL's ctors
+immediately prior to making the call, whether immediate or deferred.
+
+
+ Entry sequence for Cygwin-based executables.
+ ============================================
+
+The entry point is the windows standard entrypoint, WinMainCRTStartup, aliased
+to mainCRTStartup, defined in crt0.c. It aligns the stack, sets the x87 fpu
+cw, and hands off to cygwin_crt0 in lib/cygwin_crt0.c, which calls the CRT
+common init code in _cygwin_crt0_common and heads off into the DLL, never to
+return from _dll_crt0.
+
+ mainCRTStartup -> cygwin_crt0 -> (_cygwin_crt0_common) -> _dll_crt0
+ -> dll_crt0_1 -> (n*DllMain?maybe?) -> main -> (__main) -> cygwin_exit
+
+This is a wrapper that does some fork-related stack sorting out then hands off
+to dll_crt0_1, which completes all Cygwin DLL initialisation, runs any
+deferred DllMain calls, and jumps into the application, returning via the
+termination routines.
+
+
+ Post-entry construction.
+ ========================
+
+The compiler automatically inserts a hidden call to __main at the start of the
+user's main() function. During startup, DLL constructors are run in dll:init()
+immediately prior to calling that DLL's DllMain function (not in a forkee,
+though; once is enough). In __main, all statically-loaded DLL ctors are now
+complete, so we queue an atexit call to dll_global_dtors, then run the
+application's ctors and queue an atexit call to do_global_dtors.
+
+
+
+ Process overall termination sequence.
+ =====================================
+
+The program termination sequence can begin in one of the following ways:
+
+- by returning from main()
+- by calling exit(), _Exit() or _exit()
+- by calling abort()
+ (this can be implicit, such as when an unhandled C++ exception is thrown,
+ or when an SEH exception is raised and not trapped, or an unhandled signal
+ terminates the program).
+
+
+ Unload sequence for Cygwin-based DLLS.
+ ======================================
+
+ _cygwin_dll_entry@12 -> (DllMain) -> cygwin_detach_dll -> dll_list::detach
+ -> (remove_dll_atexit) -> (dll::run_dtors)
+
+When a DLL is unloaded, whether as a result of dlclose() calling FreeLibrary(),
+or when then entire process is terminating, the OS arranges to call the DLL's
+DllMain function with a DLL_PROCESS_DETACH notification. As during the entry
+sequence, this is also wrapped by _cygwin_dll_entry(), although there is in
+this case no need to defer calling the user's DllMain hook; it is called at
+once. If no error is indicated, the dll is then detached from Cygwin's
+internal tracking list, and any atexit functions it has registered are run and
+cancelled from the atexit list. Finally any static destructors are run.
+
+
+ Exit sequence for Cygwin-based executables.
+ ============================================
+
+This diagram illustrates the code paths, listed above, by which the main
+executable can terminate:
+
+ +-------------->-- exception handling --->----------------------------+
+ | |
+ +-------------->--------- abort --------->--- stdio cleanup ----------+
+ | |
+ +-------------->-- direct or via _Exit -->-------------------+ |
+ | | |
+ +-------------->----------+ | |
+ | V stdio cleanup, V V
+ main -> dll_crt0_1 -> cygwin_exit -> exit -> atexit funcs -> _exit -> do_exit
+ -> pinfo::exit -> ExitProcess -> END.
+
+Returning from main() transfers control back to dll_crt0_1(), which passes the
+return value to cygwin_exit(); this is the same as calling exit(), which is
+an export name alias for cygwin_exit() anyway. cygwin_exit() calls the real
+exit() function in newlib, which runs the atexit functions and shuts down
+stdio before exiting via _exit(), which immediately passes the exit status
+through to do_exit(). If exiting via abort(), stdio is cleaned up, but no
+atexit functions are run.
+
+All the termination sequences end up in do_exit(), which takes care of POSIXy
+stuff like process group and child signalling, tty disconnection, etc. This
+finally passes control to pinfo::exit(), which takes care of indicating the
+correct overall exit status and then gives control to the OS process shutdown
+routine, ExitProcess().
+
+During ExitProcess(), all the statically-linked DLLs in the application are
+terminated, by calling their DllMain functions with the DLL_PROCESS_DETACH
+notification.
+
+
+ Static object destruction.
+ ==========================
+
+Static object destruction for any statically-linked DLLs, or any dlopen()ed
+DLLs that have still not been dlclose()d by termination time, is handled in
+dll_global_dtors(). As the description above makes clear, this relies on the
+atexit functions being run, and so only takes place during a graceful exit,
+and not in the case of termination via _exit(), _Exit(), abort() or through an
+unhandled signal or exception. The destructors are run before stdio has been
+terminated, and in reverse of DLL load order.
+