This is the mail archive of the pthreads-win32@sourceware.org mailing list for the pthreas-win32 project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] autostatic.c


My next patch is an overhaul of autostatic.c that adds support for older MSVC versions, fixes the no-init bug in small-static builds, and smooths out a number of rough edges.

++ autostatic.c

* Move the #includes up to the top, in case PTW32_STATIC_LIB is defined in
  a header file (and a later patch from me will need a symbol from
  implement.h early on)

* Added a big fat comment documenting the pre/post-main() black magic and
  the anchoring business

* The init/exit routines are supposed to return int, not void, and return
  a value of 0 to indicate "no error" (see the "Addendum: int Instead of
  void" section in the Codeguru article)

* I got rid of the attribute_section() macro (in favor of writing things
  out longhand) because it's not enough to abstract away all the
  differences between the various forms of declarations needed (for
  example, #pragma is needed in some cases, and that can't be stuffed into
  a macro (and __pragma() isn't supported by older MSVC versions))

* The way that MSVC pre/post-main() black magic is done changed in 8.0, so
  the code now implements the "old" and "new" ways. I've tested that this
  works for everything back to MSVC6.

* Added a bit at the end to avoid warnings when PTW32_STATIC_LIB is not
  defined in non-inlined builds

++ implement.h

* This bit sticks a reference to autostatic.obj into every object file, so
  that the linker won't optimize it away (for "small static" builds)


--Daniel



-- Daniel Richard G. || danielg@teragram.com || Software Developer Teragram Linguistic Technologies (a division of SAS) http://www.teragram.com/
diff --git a/autostatic.c b/autostatic.c
index 092aff2..21c1748 100755
--- a/autostatic.c
+++ b/autostatic.c
@@ -34,36 +34,73 @@
  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
+#include "pthread.h"
+#include "implement.h"
+
 #if defined(PTW32_STATIC_LIB)
 
 #if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER)
 
-#include "pthread.h"
-#include "implement.h"
+/* For an explanation of this code (at least the MSVC parts), refer to
+ *
+ * http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945/
+ * ("Running Code Before and After Main")
+ *
+ * Compatibility with MSVC8 was cribbed from Boost:
+ *
+ * http://svn.boost.org/svn/boost/trunk/libs/thread/src/win32/tss_pe.cpp
+ *
+ * In addition to that, because we are in a static library, and the linker
+ * can't tell that the constructor/destructor functions are actually
+ * needed, we need a way to prevent the linker from optimizing away this
+ * module. The pthread_win32_autostatic_anchor() hack below (and in
+ * implement.h) does the job in a portable manner.
+ */
 
-static void on_process_init(void)
+static int on_process_init(void)
 {
     pthread_win32_process_attach_np ();
+    return 0;
 }
 
-static void on_process_exit(void)
+static int on_process_exit(void)
 {
     pthread_win32_thread_detach_np  ();
     pthread_win32_process_detach_np ();
+    return 0;
 }
 
 #if defined(__MINGW64__) || defined(__MINGW32__)
-# define attribute_section(a) __attribute__((section(a)))
+__attribute__((section(".ctors"), used)) static int (*gcc_ctor)(void) = on_process_init;
+__attribute__((section(".dtors"), used)) static int (*gcc_dtor)(void) = on_process_exit;
 #elif defined(_MSC_VER)
-# define attribute_section(a) __pragma(section(a,long,read)); __declspec(allocate(a))
+#  if _MSC_VER >= 1400	/* MSVC8 */
+#    pragma section(".CRT$XCU", long, read)
+#    pragma section(".CRT$XPU", long, read)
+__declspec(allocate(".CRT$XCU")) static int (*msc_ctor)(void) = on_process_init;
+__declspec(allocate(".CRT$XPU")) static int (*msc_dtor)(void) = on_process_exit;
+#  else
+#    pragma data_seg(".CRT$XCU")
+static int (*msc_ctor)(void) = on_process_init;
+#    pragma data_seg(".CRT$XPU")
+static int (*msc_dtor)(void) = on_process_exit;
+#    pragma data_seg()	/* reset data segment */
+#  endif
 #endif
 
-attribute_section(".ctors") void *gcc_ctor = on_process_init;
-attribute_section(".dtors") void *gcc_dtor = on_process_exit;
-
-attribute_section(".CRT$XCU") void *msc_ctor = on_process_init;
-attribute_section(".CRT$XPU") void *msc_dtor = on_process_exit;
-
 #endif /* defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) */
 
+/* This dummy function exists solely to be referenced by other modules
+ * (specifically, in implement.h), so that the linker can't optimize away
+ * this module. Don't call it.
+ */
+void pthread_win32_autostatic_anchor(void) { abort(); }
+
 #endif /* PTW32_STATIC_LIB */
+
+#if ! defined(PTW32_BUILD_INLINED)
+/*
+ * Avoid "translation unit is empty" warnings
+ */
+typedef int foo;
+#endif
diff --git a/implement.h b/implement.h
index 92f5740..7529ad2 100644
--- a/implement.h
+++ b/implement.h
@@ -109,6 +109,16 @@ typedef VOID (APIENTRY *PAPCFUNC)(DWORD dwParam);
 #  if defined(_MSC_VER) && _MSC_VER < 1300
      typedef long intptr_t;
 #  endif
+
+/*
+ * Don't allow the linker to optimize away autostatic.obj in static builds.
+ */
+#if defined(PTW32_STATIC_LIB)
+void pthread_win32_autostatic_anchor(void);
+#  if defined(__MINGW64__) || defined(__MINGW32__)
+__attribute__((unused, used))
+#  endif
+static void (*local_autostatic_anchor)(void) = pthread_win32_autostatic_anchor;
 #endif
 
 typedef enum

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