g_time_zone_new_local: cache the result

Add a function to drop the cache.
This commit is contained in:
Ryan Lortie 2011-03-18 23:09:52 -04:00
parent 29a074b87e
commit de3a3b181a
3 changed files with 60 additions and 1 deletions

View File

@ -1427,6 +1427,8 @@ g_time_zone_new
g_time_zone_new_local
g_time_zone_new_utc
<SUBSECTION>
g_time_zone_refresh_local
<SUBSECTION>
GTimeType
g_time_zone_find_interval
g_time_zone_adjust_time

View File

@ -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/*<string?, GTimeZone>*/ *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 */

View File

@ -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);