Bug 833117 - Replace g_slice_set_config() with G_SLICE environment variable. r=nfroyd,r=karlt
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 26 Jun 2015 10:59:52 -0700
changeset 271175 966db7a40427211899a4c415b392aa80237a0bbc
parent 271174 6734292ea4b2156bd4909fc17b758455f11eaade
child 271176 d7ca6e1baa190e9087ae422b7f5107063cf72df2
push idunknown
push userunknown
push dateunknown
reviewersnfroyd, karlt
bugs833117
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 833117 - Replace g_slice_set_config() with G_SLICE environment variable. r=nfroyd,r=karlt Using g_slice_set_config() fails with newer glib because the slice allocator now has a static constructor that runs when glib is loaded, consequently emitting a noisy error message which confuses people into believing it's the root of their problems. The only way left to force the slice allocator to use "system" malloc (in practice, jemalloc) is to set the G_SLICE environment variable to always-malloc, and that needs to happen before glib is loaded. Fortunately, the firefox and plugin-container executables don't depend on glib. Unfortunately, webapprt does, so the problem remains for web apps running through it. xpcshell and other executables that depend on libxul directly (as opposed to loading it dynamically) are not covered either.
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
xpcom/build/nsXULAppAPI.h
xpcom/glue/standalone/moz.build
xpcom/glue/standalone/nsXPCOMGlue.cpp
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -226,16 +226,17 @@ char **gRestartArgv;
 bool gIsGtest = false;
 
 #ifdef MOZ_WIDGET_QT
 static int    gQtOnlyArgc;
 static char **gQtOnlyArgv;
 #endif
 
 #if defined(MOZ_WIDGET_GTK)
+#include <glib.h>
 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
 #define CLEANUP_MEMORY 1
 #define PANGO_ENABLE_BACKEND
 #include <pango/pangofc-fontmap.h>
 #endif
 #include <gtk/gtk.h>
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
@@ -4282,16 +4283,35 @@ XREMain::XRE_mainRun()
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
   CleanUpSandboxEnvironment();
 #endif
 
   return rv;
 }
 
+#if MOZ_WIDGET_GTK == 2
+void XRE_GlibInit()
+{
+  static bool ran_once = false;
+
+  // glib < 2.24 doesn't want g_thread_init to be invoked twice, so ensure
+  // we only do it once. No need for thread safety here, since this is invoked
+  // well before any thread is spawned.
+  if (!ran_once) {
+    // glib version < 2.36 doesn't initialize g_slice in a static initializer.
+    // Ensure this happens through g_thread_init (glib version < 2.32) or
+    // g_type_init (2.32 <= gLib version < 2.36)."
+    g_thread_init(nullptr);
+    g_type_init();
+    ran_once = true;
+  }
+}
+#endif
+
 /*
  * XRE_main - A class based main entry point used by most platforms.
  *            Note that on OSX, aAppData->xreDirectory will point to
  *            .app/Contents/Resources.
  */
 int
 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
 {
@@ -4320,24 +4340,18 @@ XREMain::XRE_main(int argc, char* argv[]
   if (!mAppData->remotingName) {
     SetAllocatedString(mAppData->remotingName, mAppData->name);
   }
   // used throughout this file
   gAppData = mAppData;
 
   mozilla::IOInterposerInit ioInterposerGuard;
 
-#if defined(MOZ_WIDGET_GTK)
-#if defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__)
-  // Disable the slice allocator, since jemalloc already uses similar layout
-  // algorithms, and using a sub-allocator tends to increase fragmentation.
-  // This must be done before g_thread_init() is called.
-  g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
-#endif
-  g_thread_init(nullptr);
+#if MOZ_WIDGET_GTK == 2
+  XRE_GlibInit();
 #endif
 
   // init
   bool exit = false;
   int result = XRE_mainInit(&exit);
   if (result != 0 || exit)
     return result;
 
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -461,18 +461,18 @@ XRE_InitChildProcess(int aArgc,
 #endif // if defined(MOZ_CRASHREPORTER)
 
   gArgv = aArgv;
   gArgc = aArgc;
 
 #ifdef MOZ_X11
   XInitThreads();
 #endif
-#if defined(MOZ_WIDGET_GTK)
-  g_thread_init(nullptr);
+#if MOZ_WIDGET_GTK == 2
+  XRE_GlibInit();
 #endif
 
 #if defined(MOZ_WIDGET_QT)
   nsQAppInstance::AddRef();
 #endif
 
   if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
 #ifdef OS_POSIX
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -472,9 +472,14 @@ XRE_API(void,
 XRE_API(void,
         XRE_ProcLoaderPreload, (const char* aProgramDir,
                                 const nsXREAppData* aAppData));
 #endif // MOZ_B2G_LOADER
 
 XRE_API(int,
         XRE_XPCShellMain, (int argc, char** argv, char** envp))
 
+#if MOZ_WIDGET_GTK == 2
+XRE_API(void,
+        XRE_GlibInit, ())
+#endif
+
 #endif // _nsXULAppAPI_h__
--- a/xpcom/glue/standalone/moz.build
+++ b/xpcom/glue/standalone/moz.build
@@ -49,8 +49,11 @@ FAIL_ON_WARNINGS = True
 USE_LIBS += [
     'fallible',
 ]
 
 # Force to build a static library only
 NO_EXPAND_LIBS = True
 
 DIST_INSTALL = True
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'):
+    CXXFLAGS += CONFIG['GLIB_CFLAGS']
--- a/xpcom/glue/standalone/nsXPCOMGlue.cpp
+++ b/xpcom/glue/standalone/nsXPCOMGlue.cpp
@@ -421,19 +421,65 @@ XPCOMGlueLoadXULFunctions(const nsDynami
 }
 
 void
 XPCOMGlueEnablePreload()
 {
   do_preload = true;
 }
 
+#if defined(MOZ_WIDGET_GTK) && (defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__))
+#define MOZ_GSLICE_INIT
+#endif
+
+#ifdef MOZ_GSLICE_INIT
+#include <glib.h>
+
+class GSliceInit {
+public:
+  GSliceInit() {
+    mHadGSlice = bool(getenv("G_SLICE"));
+    if (!mHadGSlice) {
+      // Disable the slice allocator, since jemalloc already uses similar layout
+      // algorithms, and using a sub-allocator tends to increase fragmentation.
+      // This must be done before g_thread_init() is called.
+      // glib >= 2.36 initializes g_slice as a side effect of its various static
+      // initializers, so this needs to happen before glib is loaded, which is
+      // this is hooked in XPCOMGlueStartup before libxul is loaded. This
+      // relies on the main executable not depending on glib.
+      setenv("G_SLICE", "always-malloc", 1);
+    }
+  }
+
+  ~GSliceInit() {
+#if MOZ_WIDGET_GTK == 2
+    if (sTop) {
+      auto XRE_GlibInit = (void (*)(void)) GetSymbol(sTop->libHandle,
+        "XRE_GlibInit");
+      // Initialize glib enough for G_SLICE to have an effect before it is unset.
+      // unset.
+      XRE_GlibInit();
+    }
+#endif
+    if (!mHadGSlice) {
+      unsetenv("G_SLICE");
+    }
+  }
+
+private:
+  bool mHadGSlice;
+};
+#endif
+
 nsresult
 XPCOMGlueStartup(const char* aXPCOMFile)
 {
+#ifdef MOZ_GSLICE_INIT
+  GSliceInit gSliceInit;
+#endif
   xpcomFunctions.version = XPCOM_GLUE_VERSION;
   xpcomFunctions.size    = sizeof(XPCOMFunctions);
 
   if (!aXPCOMFile) {
     aXPCOMFile = XPCOM_DLL;
   }
 
   GetFrozenFunctionsFunc func = XPCOMGlueLoad(aXPCOMFile);