From de3a3b181a97d43acd29bcdcdbd7406233b7ee9f Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Fri, 18 Mar 2011 23:09:52 -0400 Subject: [PATCH] g_time_zone_new_local: cache the result Add a function to drop the cache. --- docs/reference/glib/glib-sections.txt | 2 ++ glib/gtimezone.c | 57 ++++++++++++++++++++++++++++++++++- glib/gtimezone.h | 2 ++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index ca512b2..c1c68b0 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1427,6 +1427,8 @@ g_time_zone_new g_time_zone_new_local g_time_zone_new_utc +g_time_zone_refresh_local + GTimeType g_time_zone_find_interval g_time_zone_adjust_time diff --git a/glib/gtimezone.c b/glib/gtimezone.c index c8cd948..637a5ad 100644 --- a/glib/gtimezone.c +++ b/glib/gtimezone.c @@ -129,6 +129,9 @@ struct _GTimeZone gint ref_count; }; +G_LOCK_DEFINE_STATIC (local_timezone); +static GTimeZone *local_timezone; + G_LOCK_DEFINE_STATIC (time_zones); static GHashTable/**/ *time_zones; @@ -147,6 +150,22 @@ g_time_zone_unref (GTimeZone *tz) if (g_atomic_int_dec_and_test (&tz->ref_count)) { + if G_UNLIKELY (tz == local_timezone) + { + g_critical ("The last reference on the local timezone was just " + "dropped, but GTimeZone itself still owns one. This " + "means that g_time_zone_unref() was called too many " + "times. Restoring the refcount to 1."); + + /* We don't want to just inc this back again since if there + * are refcounting bugs in the code then maybe we are already + * at -1 and inc will just take us back to 0. Set to 1 to be + * sure. + */ + tz->ref_count = 1; + return; + } + if (tz->name != NULL) { G_LOCK(time_zones); @@ -449,7 +468,43 @@ g_time_zone_new_utc (void) GTimeZone * g_time_zone_new_local (void) { - return g_time_zone_new (getenv ("TZ")); + GTimeZone *result; + + G_LOCK (local_timezone); + if (local_timezone == NULL) + local_timezone = g_time_zone_new (getenv ("TZ")); + + result = g_time_zone_ref (local_timezone); + G_UNLOCK (local_timezone); + + return result; +} + +/** + * g_time_zone_refresh_local: + * + * Notifies #GTimeZone that the local timezone may have changed. + * + * In response, #GTimeZone will drop its cache of the local time zone. + * No existing #GTimeZone will be modified and no #GDateTime will change + * its timezone but future calls to g_time_zone_new_local() will start + * returning the new timezone. + * + * #GTimeZone does no monitoring of the local timezone on its own, which + * is why you have to call this function to notify it of the change. + **/ +void +g_time_zone_refresh_local (void) +{ + GTimeZone *drop_this_ref = NULL; + + G_LOCK (local_timezone); + drop_this_ref = local_timezone; + local_timezone = NULL; + G_UNLOCK (local_timezone); + + if (drop_this_ref) + g_time_zone_unref (drop_this_ref); } /* Internal helpers {{{1 */ diff --git a/glib/gtimezone.h b/glib/gtimezone.h index 8bc6684..bc72c20 100644 --- a/glib/gtimezone.h +++ b/glib/gtimezone.h @@ -54,6 +54,8 @@ typedef enum G_TIME_TYPE_UNIVERSAL } GTimeType; +void g_time_zone_refresh_local (void); + GTimeZone * g_time_zone_new (const gchar *identifier); GTimeZone * g_time_zone_new_utc (void); GTimeZone * g_time_zone_new_local (void); -- 2.7.4