Blame glib/glib-init.c

Packit ae235b
/*
Packit ae235b
 * Copyright © 2011 Canonical Limited
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful, but
Packit ae235b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Ryan Lortie <desrt@desrt.ca>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include "glib-init.h"
Packit ae235b
Packit ae235b
#include "glib-private.h"
Packit ae235b
#include "gtypes.h"
Packit ae235b
#include "gutils.h"     /* for GDebugKey */
Packit ae235b
#include "gconstructor.h"
Packit ae235b
#include "gmem.h"       /* for g_mem_gc_friendly */
Packit ae235b
Packit ae235b
#include <string.h>
Packit ae235b
#include <stdlib.h>
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <ctype.h>
Packit ae235b
Packit ae235b
/* This seems as good a place as any to make static assertions about platform
Packit ae235b
 * assumptions we make throughout GLib. */
Packit ae235b
Packit ae235b
/* We do not support 36-bit bytes or other historical curiosities. */
Packit ae235b
G_STATIC_ASSERT (CHAR_BIT == 8);
Packit ae235b
Packit ae235b
/* We assume that data pointers are the same size as function pointers... */
Packit ae235b
G_STATIC_ASSERT (sizeof (gpointer) == sizeof (GFunc));
Packit ae235b
G_STATIC_ASSERT (_g_alignof (gpointer) == _g_alignof (GFunc));
Packit ae235b
/* ... and that all function pointers are the same size. */
Packit ae235b
G_STATIC_ASSERT (sizeof (GFunc) == sizeof (GCompareDataFunc));
Packit ae235b
G_STATIC_ASSERT (_g_alignof (GFunc) == _g_alignof (GCompareDataFunc));
Packit ae235b
Packit ae235b
/* We assume that "small" enums (those where all values fit in INT32_MIN
Packit ae235b
 * to INT32_MAX) are exactly int-sized. In particular, we assume that if
Packit ae235b
 * an enum has no members that exceed the range of char/short, the
Packit ae235b
 * compiler will make it int-sized anyway, so adding a member later that
Packit ae235b
 * *does* exceed the range of char/short is not an ABI break. */
Packit ae235b
typedef enum {
Packit ae235b
    TEST_CHAR_0 = 0
Packit ae235b
} TestChar;
Packit ae235b
typedef enum {
Packit ae235b
    TEST_SHORT_0 = 0,
Packit ae235b
    TEST_SHORT_256 = 256
Packit ae235b
} TestShort;
Packit ae235b
typedef enum {
Packit ae235b
    TEST_INT32_MIN = G_MININT32,
Packit ae235b
    TEST_INT32_MAX = G_MAXINT32
Packit ae235b
} TestInt;
Packit ae235b
G_STATIC_ASSERT (sizeof (TestChar) == sizeof (int));
Packit ae235b
G_STATIC_ASSERT (sizeof (TestShort) == sizeof (int));
Packit ae235b
G_STATIC_ASSERT (sizeof (TestInt) == sizeof (int));
Packit ae235b
G_STATIC_ASSERT (_g_alignof (TestChar) == _g_alignof (int));
Packit ae235b
G_STATIC_ASSERT (_g_alignof (TestShort) == _g_alignof (int));
Packit ae235b
G_STATIC_ASSERT (_g_alignof (TestInt) == _g_alignof (int));
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_mem_gc_friendly:
Packit ae235b
 *
Packit ae235b
 * This variable is %TRUE if the `G_DEBUG` environment variable
Packit ae235b
 * includes the key `gc-friendly`.
Packit ae235b
 */
Packit ae235b
#ifdef ENABLE_GC_FRIENDLY_DEFAULT
Packit ae235b
gboolean g_mem_gc_friendly = TRUE;
Packit ae235b
#else
Packit ae235b
gboolean g_mem_gc_friendly = FALSE;
Packit ae235b
#endif
Packit ae235b
GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING |
Packit ae235b
                                  G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
Packit ae235b
GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
debug_key_matches (const gchar *key,
Packit ae235b
                   const gchar *token,
Packit ae235b
                   guint        length)
Packit ae235b
{
Packit ae235b
  /* may not call GLib functions: see note in g_parse_debug_string() */
Packit ae235b
  for (; length; length--, key++, token++)
Packit ae235b
    {
Packit ae235b
      char k = (*key   == '_') ? '-' : tolower (*key  );
Packit ae235b
      char t = (*token == '_') ? '-' : tolower (*token);
Packit ae235b
Packit ae235b
      if (k != t)
Packit ae235b
        return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return *key == '\0';
Packit ae235b
}
Packit ae235b
Packit ae235b
/* The GVariant documentation indirectly says that int is at least 32 bits
Packit ae235b
 * (by saying that b, y, n, q, i, u, h are promoted to int). On any
Packit ae235b
 * reasonable platform, int is in fact *exactly* 32 bits long, because
Packit ae235b
 * otherwise, {signed char, short, int} wouldn't be sufficient to provide
Packit ae235b
 * {int8_t, int16_t, int32_t}. */
Packit ae235b
G_STATIC_ASSERT (sizeof (int) == sizeof (gint32));
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_parse_debug_string:
Packit ae235b
 * @string: (nullable): a list of debug options separated by colons, spaces, or
Packit ae235b
 * commas, or %NULL.
Packit ae235b
 * @keys: (array length=nkeys): pointer to an array of #GDebugKey which associate
Packit ae235b
 *     strings with bit flags.
Packit ae235b
 * @nkeys: the number of #GDebugKeys in the array.
Packit ae235b
 *
Packit ae235b
 * Parses a string containing debugging options
Packit ae235b
 * into a %guint containing bit flags. This is used
Packit ae235b
 * within GDK and GTK+ to parse the debug options passed on the
Packit ae235b
 * command line or through environment variables.
Packit ae235b
 *
Packit ae235b
 * If @string is equal to "all", all flags are set. Any flags
Packit ae235b
 * specified along with "all" in @string are inverted; thus,
Packit ae235b
 * "all,foo,bar" or "foo,bar,all" sets all flags except those
Packit ae235b
 * corresponding to "foo" and "bar".
Packit ae235b
 *
Packit ae235b
 * If @string is equal to "help", all the available keys in @keys
Packit ae235b
 * are printed out to standard error.
Packit ae235b
 *
Packit ae235b
 * Returns: the combined set of bit flags.
Packit ae235b
 */
Packit ae235b
guint
Packit ae235b
g_parse_debug_string  (const gchar     *string,
Packit ae235b
                       const GDebugKey *keys,
Packit ae235b
                       guint            nkeys)
Packit ae235b
{
Packit ae235b
  guint i;
Packit ae235b
  guint result = 0;
Packit ae235b
Packit ae235b
  if (string == NULL)
Packit ae235b
    return 0;
Packit ae235b
Packit ae235b
  /* this function is used during the initialisation of gmessages, gmem
Packit ae235b
   * and gslice, so it may not do anything that causes memory to be
Packit ae235b
   * allocated or risks messages being emitted.
Packit ae235b
   *
Packit ae235b
   * this means, more or less, that this code may not call anything
Packit ae235b
   * inside GLib.
Packit ae235b
   */
Packit ae235b
Packit ae235b
  if (!strcasecmp (string, "help"))
Packit ae235b
    {
Packit ae235b
      /* using stdio directly for the reason stated above */
Packit ae235b
      fprintf (stderr, "Supported debug values:");
Packit ae235b
      for (i = 0; i < nkeys; i++)
Packit ae235b
        fprintf (stderr, " %s", keys[i].key);
Packit ae235b
      fprintf (stderr, " all help\n");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      const gchar *p = string;
Packit ae235b
      const gchar *q;
Packit ae235b
      gboolean invert = FALSE;
Packit ae235b
Packit ae235b
      while (*p)
Packit ae235b
       {
Packit ae235b
         q = strpbrk (p, ":;, \t");
Packit ae235b
         if (!q)
Packit ae235b
           q = p + strlen (p);
Packit ae235b
Packit ae235b
         if (debug_key_matches ("all", p, q - p))
Packit ae235b
           {
Packit ae235b
             invert = TRUE;
Packit ae235b
           }
Packit ae235b
         else
Packit ae235b
           {
Packit ae235b
             for (i = 0; i < nkeys; i++)
Packit ae235b
               if (debug_key_matches (keys[i].key, p, q - p))
Packit ae235b
                 result |= keys[i].value;
Packit ae235b
           }
Packit ae235b
Packit ae235b
         p = q;
Packit ae235b
         if (*p)
Packit ae235b
           p++;
Packit ae235b
       }
Packit ae235b
Packit ae235b
      if (invert)
Packit ae235b
        {
Packit ae235b
          guint all_flags = 0;
Packit ae235b
Packit ae235b
          for (i = 0; i < nkeys; i++)
Packit ae235b
            all_flags |= keys[i].value;
Packit ae235b
Packit ae235b
          result = all_flags & (~result);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return result;
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint
Packit ae235b
g_parse_debug_envvar (const gchar     *envvar,
Packit ae235b
                      const GDebugKey *keys,
Packit ae235b
                      gint             n_keys,
Packit ae235b
                      guint            default_value)
Packit ae235b
{
Packit ae235b
  const gchar *value;
Packit ae235b
Packit ae235b
#ifdef OS_WIN32
Packit ae235b
  /* "fatal-warnings,fatal-criticals,all,help" is pretty short */
Packit ae235b
  gchar buffer[100];
Packit ae235b
Packit ae235b
  if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
Packit ae235b
    value = buffer;
Packit ae235b
  else
Packit ae235b
    return 0;
Packit ae235b
#else
Packit ae235b
  value = getenv (envvar);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  if (value == NULL)
Packit ae235b
    return default_value;
Packit ae235b
Packit ae235b
  return g_parse_debug_string (value, keys, n_keys);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_messages_prefixed_init (void)
Packit ae235b
{
Packit ae235b
  const GDebugKey keys[] = {
Packit ae235b
    { "error", G_LOG_LEVEL_ERROR },
Packit ae235b
    { "critical", G_LOG_LEVEL_CRITICAL },
Packit ae235b
    { "warning", G_LOG_LEVEL_WARNING },
Packit ae235b
    { "message", G_LOG_LEVEL_MESSAGE },
Packit ae235b
    { "info", G_LOG_LEVEL_INFO },
Packit ae235b
    { "debug", G_LOG_LEVEL_DEBUG }
Packit ae235b
  };
Packit ae235b
Packit ae235b
  g_log_msg_prefix = g_parse_debug_envvar ("G_MESSAGES_PREFIXED", keys, G_N_ELEMENTS (keys), g_log_msg_prefix);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_debug_init (void)
Packit ae235b
{
Packit ae235b
  const GDebugKey keys[] = {
Packit ae235b
    { "gc-friendly", 1 },
Packit ae235b
    {"fatal-warnings",  G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
Packit ae235b
    {"fatal-criticals", G_LOG_LEVEL_CRITICAL }
Packit ae235b
  };
Packit ae235b
  GLogLevelFlags flags;
Packit ae235b
Packit ae235b
  flags = g_parse_debug_envvar ("G_DEBUG", keys, G_N_ELEMENTS (keys), 0);
Packit ae235b
Packit ae235b
  g_log_always_fatal |= flags & G_LOG_LEVEL_MASK;
Packit ae235b
Packit ae235b
  g_mem_gc_friendly = flags & 1;
Packit ae235b
}
Packit ae235b
Packit ae235b
void
Packit ae235b
glib_init (void)
Packit ae235b
{
Packit ae235b
  static gboolean glib_inited;
Packit ae235b
Packit ae235b
  if (glib_inited)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  glib_inited = TRUE;
Packit ae235b
Packit ae235b
  g_messages_prefixed_init ();
Packit ae235b
  g_debug_init ();
Packit ae235b
  g_quark_init ();
Packit ae235b
}
Packit ae235b
Packit ae235b
#if defined (G_OS_WIN32)
Packit ae235b
Packit Service 948fd2
HMODULE glib_dll = NULL;
Packit Service 948fd2
Packit Service 948fd2
#if defined (DLL_EXPORT)
Packit Service 948fd2
Packit ae235b
BOOL WINAPI DllMain (HINSTANCE hinstDLL,
Packit ae235b
                     DWORD     fdwReason,
Packit ae235b
                     LPVOID    lpvReserved);
Packit ae235b
Packit ae235b
BOOL WINAPI
Packit ae235b
DllMain (HINSTANCE hinstDLL,
Packit ae235b
         DWORD     fdwReason,
Packit ae235b
         LPVOID    lpvReserved)
Packit ae235b
{
Packit ae235b
  switch (fdwReason)
Packit ae235b
    {
Packit ae235b
    case DLL_PROCESS_ATTACH:
Packit ae235b
      glib_dll = hinstDLL;
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case DLL_THREAD_DETACH:
Packit ae235b
#ifdef THREADS_WIN32
Packit ae235b
      g_thread_win32_thread_detach ();
Packit ae235b
#endif
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    case DLL_PROCESS_DETACH:
Packit ae235b
#ifdef THREADS_WIN32
Packit ae235b
      if (lpvReserved == NULL)
Packit ae235b
        g_thread_win32_process_detach ();
Packit ae235b
#endif
Packit ae235b
      break;
Packit ae235b
Packit ae235b
    default:
Packit ae235b
      /* do nothing */
Packit ae235b
      ;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit Service 948fd2
#endif /* defined (DLL_EXPORT) */
Packit Service 948fd2
#endif /* defined (G_OS_WIN32) */
Packit Service 948fd2
Packit Service 948fd2
#if defined (G_HAS_CONSTRUCTORS)
Packit ae235b
Packit ae235b
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
Packit ae235b
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
Packit ae235b
#endif
Packit ae235b
G_DEFINE_CONSTRUCTOR(glib_init_ctor)
Packit ae235b
Packit ae235b
static void
Packit ae235b
glib_init_ctor (void)
Packit ae235b
{
Packit Service 948fd2
#if defined (G_OS_WIN32)
Packit Service 948fd2
  g_clock_win32_init ();
Packit Service 948fd2
#ifdef THREADS_WIN32
Packit Service 948fd2
  g_thread_win32_init ();
Packit Service 948fd2
#endif /* defined (THREADS_WIN32) */
Packit Service 948fd2
#endif /* defined (G_OS_WIN32) */
Packit ae235b
  glib_init ();
Packit ae235b
}
Packit ae235b
Packit ae235b
#else
Packit ae235b
# error Your platform/compiler is missing constructor support
Packit ae235b
#endif