• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011 Canonical Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Ryan Lortie <desrt@desrt.ca>
18  */
19 
20 #include "config.h"
21 
22 #include "glib-init.h"
23 #include "gmacros.h"
24 #include "gtypes.h"
25 #include "gutils.h"     /* for GDebugKey */
26 #include "gconstructor.h"
27 #include "gmem.h"       /* for g_mem_gc_friendly */
28 
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 
34 /* This seems as good a place as any to make static assertions about platform
35  * assumptions we make throughout GLib. */
36 
37 /* We do not support 36-bit bytes or other historical curiosities. */
38 G_STATIC_ASSERT (CHAR_BIT == 8);
39 
40 /* We assume that data pointers are the same size as function pointers... */
41 G_STATIC_ASSERT (sizeof (gpointer) == sizeof (GFunc));
42 G_STATIC_ASSERT (G_ALIGNOF (gpointer) == G_ALIGNOF (GFunc));
43 /* ... and that all function pointers are the same size. */
44 G_STATIC_ASSERT (sizeof (GFunc) == sizeof (GCompareDataFunc));
45 G_STATIC_ASSERT (G_ALIGNOF (GFunc) == G_ALIGNOF (GCompareDataFunc));
46 
47 /* We assume that "small" enums (those where all values fit in INT32_MIN
48  * to INT32_MAX) are exactly int-sized. In particular, we assume that if
49  * an enum has no members that exceed the range of char/short, the
50  * compiler will make it int-sized anyway, so adding a member later that
51  * *does* exceed the range of char/short is not an ABI break. */
52 typedef enum {
53     TEST_CHAR_0 = 0
54 } TestChar;
55 typedef enum {
56     TEST_SHORT_0 = 0,
57     TEST_SHORT_256 = 256
58 } TestShort;
59 typedef enum {
60     TEST_INT32_MIN = G_MININT32,
61     TEST_INT32_MAX = G_MAXINT32
62 } TestInt;
63 G_STATIC_ASSERT (sizeof (TestChar) == sizeof (int));
64 G_STATIC_ASSERT (sizeof (TestShort) == sizeof (int));
65 G_STATIC_ASSERT (sizeof (TestInt) == sizeof (int));
66 G_STATIC_ASSERT (G_ALIGNOF (TestChar) == G_ALIGNOF (int));
67 G_STATIC_ASSERT (G_ALIGNOF (TestShort) == G_ALIGNOF (int));
68 G_STATIC_ASSERT (G_ALIGNOF (TestInt) == G_ALIGNOF (int));
69 
70 /**
71  * g_mem_gc_friendly:
72  *
73  * This variable is %TRUE if the `G_DEBUG` environment variable
74  * includes the key `gc-friendly`.
75  */
76 gboolean g_mem_gc_friendly = FALSE;
77 
78 GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING |
79                                   G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
80 GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
81 
82 static gboolean
debug_key_matches(const gchar * key,const gchar * token,guint length)83 debug_key_matches (const gchar *key,
84                    const gchar *token,
85                    guint        length)
86 {
87   /* may not call GLib functions: see note in g_parse_debug_string() */
88   for (; length; length--, key++, token++)
89     {
90       char k = (*key   == '_') ? '-' : tolower (*key  );
91       char t = (*token == '_') ? '-' : tolower (*token);
92 
93       if (k != t)
94         return FALSE;
95     }
96 
97   return *key == '\0';
98 }
99 
100 /* The GVariant documentation indirectly says that int is at least 32 bits
101  * (by saying that b, y, n, q, i, u, h are promoted to int). On any
102  * reasonable platform, int is in fact *exactly* 32 bits long, because
103  * otherwise, {signed char, short, int} wouldn't be sufficient to provide
104  * {int8_t, int16_t, int32_t}. */
105 G_STATIC_ASSERT (sizeof (int) == sizeof (gint32));
106 
107 /**
108  * g_parse_debug_string:
109  * @string: (nullable): a list of debug options separated by colons, spaces, or
110  * commas, or %NULL.
111  * @keys: (array length=nkeys): pointer to an array of #GDebugKey which associate
112  *     strings with bit flags.
113  * @nkeys: the number of #GDebugKeys in the array.
114  *
115  * Parses a string containing debugging options
116  * into a %guint containing bit flags. This is used
117  * within GDK and GTK+ to parse the debug options passed on the
118  * command line or through environment variables.
119  *
120  * If @string is equal to "all", all flags are set. Any flags
121  * specified along with "all" in @string are inverted; thus,
122  * "all,foo,bar" or "foo,bar,all" sets all flags except those
123  * corresponding to "foo" and "bar".
124  *
125  * If @string is equal to "help", all the available keys in @keys
126  * are printed out to standard error.
127  *
128  * Returns: the combined set of bit flags.
129  */
130 guint
g_parse_debug_string(const gchar * string,const GDebugKey * keys,guint nkeys)131 g_parse_debug_string  (const gchar     *string,
132                        const GDebugKey *keys,
133                        guint            nkeys)
134 {
135   guint i;
136   guint result = 0;
137 
138   if (string == NULL)
139     return 0;
140 
141   /* this function is used during the initialisation of gmessages, gmem
142    * and gslice, so it may not do anything that causes memory to be
143    * allocated or risks messages being emitted.
144    *
145    * this means, more or less, that this code may not call anything
146    * inside GLib.
147    */
148 
149   if (!strcasecmp (string, "help"))
150     {
151       /* using stdio directly for the reason stated above */
152       fprintf (stderr, "Supported debug values:");
153       for (i = 0; i < nkeys; i++)
154         fprintf (stderr, " %s", keys[i].key);
155       fprintf (stderr, " all help\n");
156     }
157   else
158     {
159       const gchar *p = string;
160       const gchar *q;
161       gboolean invert = FALSE;
162 
163       while (*p)
164        {
165          q = strpbrk (p, ":;, \t");
166          if (!q)
167            q = p + strlen (p);
168 
169          if (debug_key_matches ("all", p, q - p))
170            {
171              invert = TRUE;
172            }
173          else
174            {
175              for (i = 0; i < nkeys; i++)
176                if (debug_key_matches (keys[i].key, p, q - p))
177                  result |= keys[i].value;
178            }
179 
180          p = q;
181          if (*p)
182            p++;
183        }
184 
185       if (invert)
186         {
187           guint all_flags = 0;
188 
189           for (i = 0; i < nkeys; i++)
190             all_flags |= keys[i].value;
191 
192           result = all_flags & (~result);
193         }
194     }
195 
196   return result;
197 }
198 
199 static guint
g_parse_debug_envvar(const gchar * envvar,const GDebugKey * keys,gint n_keys,guint default_value)200 g_parse_debug_envvar (const gchar     *envvar,
201                       const GDebugKey *keys,
202                       gint             n_keys,
203                       guint            default_value)
204 {
205   const gchar *value;
206 
207 #ifdef OS_WIN32
208   /* "fatal-warnings,fatal-criticals,all,help" is pretty short */
209   gchar buffer[100];
210 
211   if (GetEnvironmentVariable (envvar, buffer, 100) < 100)
212     value = buffer;
213   else
214     return 0;
215 #else
216   value = getenv (envvar);
217 #endif
218 
219   if (value == NULL)
220     return default_value;
221 
222   return g_parse_debug_string (value, keys, n_keys);
223 }
224 
225 static void
g_messages_prefixed_init(void)226 g_messages_prefixed_init (void)
227 {
228   const GDebugKey keys[] = {
229     { "error", G_LOG_LEVEL_ERROR },
230     { "critical", G_LOG_LEVEL_CRITICAL },
231     { "warning", G_LOG_LEVEL_WARNING },
232     { "message", G_LOG_LEVEL_MESSAGE },
233     { "info", G_LOG_LEVEL_INFO },
234     { "debug", G_LOG_LEVEL_DEBUG }
235   };
236 
237   g_log_msg_prefix = g_parse_debug_envvar ("G_MESSAGES_PREFIXED", keys, G_N_ELEMENTS (keys), g_log_msg_prefix);
238 }
239 
240 static void
g_debug_init(void)241 g_debug_init (void)
242 {
243   const GDebugKey keys[] = {
244     { "gc-friendly", 1 },
245     {"fatal-warnings",  G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL },
246     {"fatal-criticals", G_LOG_LEVEL_CRITICAL }
247   };
248   GLogLevelFlags flags;
249 
250   flags = g_parse_debug_envvar ("G_DEBUG", keys, G_N_ELEMENTS (keys), 0);
251 
252   g_log_always_fatal |= flags & G_LOG_LEVEL_MASK;
253 
254   g_mem_gc_friendly = flags & 1;
255 }
256 
257 void
glib_init(void)258 glib_init (void)
259 {
260   static gboolean glib_inited;
261 
262   if (glib_inited)
263     return;
264 
265   glib_inited = TRUE;
266 
267   g_messages_prefixed_init ();
268   g_debug_init ();
269   g_quark_init ();
270 }
271 
272 #if defined (G_OS_WIN32)
273 
274 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
275                      DWORD     fdwReason,
276                      LPVOID    lpvReserved);
277 
278 HMODULE glib_dll;
279 
280 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)281 DllMain (HINSTANCE hinstDLL,
282          DWORD     fdwReason,
283          LPVOID    lpvReserved)
284 {
285   switch (fdwReason)
286     {
287     case DLL_PROCESS_ATTACH:
288       glib_dll = hinstDLL;
289       g_crash_handler_win32_init ();
290       g_clock_win32_init ();
291 #ifdef THREADS_WIN32
292       g_thread_win32_init ();
293 #endif
294       glib_init ();
295       /* must go after glib_init */
296       g_console_win32_init ();
297       break;
298 
299     case DLL_THREAD_DETACH:
300 #ifdef THREADS_WIN32
301       g_thread_win32_thread_detach ();
302 #endif
303       break;
304 
305     case DLL_PROCESS_DETACH:
306 #ifdef THREADS_WIN32
307       if (lpvReserved == NULL)
308         g_thread_win32_process_detach ();
309 #endif
310       g_crash_handler_win32_deinit ();
311       break;
312 
313     default:
314       /* do nothing */
315       ;
316     }
317 
318   return TRUE;
319 }
320 
321 #elif defined (G_HAS_CONSTRUCTORS)
322 
323 #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
324 #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor)
325 #endif
G_DEFINE_CONSTRUCTOR(glib_init_ctor)326 G_DEFINE_CONSTRUCTOR(glib_init_ctor)
327 
328 static void
329 glib_init_ctor (void)
330 {
331   glib_init ();
332 }
333 
334 #else
335 # error Your platform/compiler is missing constructor support
336 #endif
337