diff --git a/timezone-madness-pt2.patch b/timezone-madness-pt2.patch index c5ad4a3..4ecb35c 100644 --- a/timezone-madness-pt2.patch +++ b/timezone-madness-pt2.patch @@ -1,61 +1,3 @@ -From b411f518b8dc7a99bad52884048436d991c89b77 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= - =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= -Date: Mon, 5 Oct 2020 17:07:29 +0000 -Subject: [PATCH 1/2] Add a test for the 6-days-until-EOM bug - ---- - glib/tests/gdatetime.c | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c -index 52eec1e46..0731f01f2 100644 ---- a/glib/tests/gdatetime.c -+++ b/glib/tests/gdatetime.c -@@ -2192,6 +2192,31 @@ test_z (void) - g_time_zone_unref (tz); - } - -+static void -+test_6_days_util_end_of_the_month (void) -+{ -+ GTimeZone *tz; -+ GDateTime *dt; -+ gchar *p; -+ -+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2215"); -+ -+#ifdef G_OS_UNIX -+ tz = g_time_zone_new ("Europe/Paris"); -+#elif defined (G_OS_WIN32) -+ tz = g_time_zone_new ("Romance Standard Time"); -+#endif -+ dt = g_date_time_new (tz, 2020, 10, 5, 1, 1, 1); -+ -+ p = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S%z"); -+ /* Incorrect output is "2020-10-05 01:01:01+0100" */ -+ g_assert_cmpstr (p, ==, "2020-10-05 01:01:01+0200"); -+ g_free (p); -+ -+ g_date_time_unref (dt); -+ g_time_zone_unref (tz); -+} -+ - static void - test_format_iso8601 (void) - { -@@ -2785,6 +2810,7 @@ main (gint argc, - g_test_add_func ("/GDateTime/new_from_iso8601/2", test_GDateTime_new_from_iso8601_2); - g_test_add_func ("/GDateTime/new_full", test_GDateTime_new_full); - g_test_add_func ("/GDateTime/now", test_GDateTime_now); -+ g_test_add_func ("/GDateTime/test-6-days-util-end-of-the-month", test_6_days_util_end_of_the_month); - g_test_add_func ("/GDateTime/printf", test_GDateTime_printf); - g_test_add_func ("/GDateTime/non_utf8_printf", test_non_utf8_printf); - g_test_add_func ("/GDateTime/format_unrepresentable", test_format_unrepresentable); --- -GitLab - - From 4a120c2e2e0a26e1cd5ce7cb4ebe906ef6d588d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= diff --git a/timezone-madness.patch b/timezone-madness.patch index 62b945a..3b00159 100644 --- a/timezone-madness.patch +++ b/timezone-madness.patch @@ -1,579 +1,27 @@ -From b4138bd4acc04ad572dfa042a384aaaa6e4621ad Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= -Date: Wed, 23 Sep 2020 18:13:47 +0100 -Subject: [PATCH 1/4] gtimezone: Split out fallback timezone identification for - unix - -When the TZ environment variable is not set, we get the local timezone -identifier by reading specific files. - -We are going to need these identifiers earlier, so split this logic into -its own function, in preparation for the next commit. - -Based on idea proposed by Sebastian Keller . ---- - glib/gtimezone.c | 127 +++++++++++++++++++++++++++-------------------- - 1 file changed, 73 insertions(+), 54 deletions(-) - -diff --git a/glib/gtimezone.c b/glib/gtimezone.c -index ef67ec50b..d90a9bb73 100644 ---- a/glib/gtimezone.c -+++ b/glib/gtimezone.c -@@ -438,11 +438,80 @@ zone_for_constant_offset (GTimeZone *gtz, const gchar *name) - } - - #ifdef G_OS_UNIX -+static gchar * -+zone_identifier_unix (void) -+{ -+ gchar *resolved_identifier = NULL; -+ gsize prefix_len = 0; -+ gchar *canonical_path = NULL; -+ GError *read_link_err = NULL; -+ const gchar *tzdir; -+ -+ /* Resolve the actual timezone pointed to by /etc/localtime. */ -+ resolved_identifier = g_file_read_link ("/etc/localtime", &read_link_err); -+ if (resolved_identifier == NULL) -+ { -+ gboolean not_a_symlink = g_error_matches (read_link_err, -+ G_FILE_ERROR, -+ G_FILE_ERROR_INVAL); -+ g_clear_error (&read_link_err); -+ -+ /* Fallback to the content of /var/db/zoneinfo or /etc/timezone -+ * if /etc/localtime is not a symlink. /var/db/zoneinfo is -+ * where 'tzsetup' program on FreeBSD and DragonflyBSD stores -+ * the timezone chosen by the user. /etc/timezone is where user -+ * choice is expressed on Gentoo OpenRC and others. */ -+ if (not_a_symlink && (g_file_get_contents ("/var/db/zoneinfo", -+ &resolved_identifier, -+ NULL, NULL) || -+ g_file_get_contents ("/etc/timezone", -+ &resolved_identifier, -+ NULL, NULL))) -+ g_strchomp (resolved_identifier); -+ else -+ { -+ /* Error */ -+ g_assert (resolved_identifier == NULL); -+ goto out; -+ } -+ } -+ else -+ { -+ /* Resolve relative path */ -+ canonical_path = g_canonicalize_filename (resolved_identifier, "/etc"); -+ g_free (resolved_identifier); -+ resolved_identifier = g_steal_pointer (&canonical_path); -+ } -+ -+ tzdir = g_getenv ("TZDIR"); -+ if (tzdir == NULL) -+ tzdir = "/usr/share/zoneinfo"; -+ -+ /* Strip the prefix and slashes if possible. */ -+ if (g_str_has_prefix (resolved_identifier, tzdir)) -+ { -+ prefix_len = strlen (tzdir); -+ while (*(resolved_identifier + prefix_len) == '/') -+ prefix_len++; -+ } -+ -+ if (prefix_len > 0) -+ memmove (resolved_identifier, resolved_identifier + prefix_len, -+ strlen (resolved_identifier) - prefix_len + 1 /* nul terminator */); -+ -+ g_assert (resolved_identifier != NULL); -+ -+out: -+ g_free (canonical_path); -+ -+ return resolved_identifier; -+} -+ - static GBytes* - zone_info_unix (const gchar *identifier, - gchar **out_identifier) - { -- gchar *filename; -+ gchar *filename = NULL; - GMappedFile *file = NULL; - GBytes *zoneinfo = NULL; - gchar *resolved_identifier = NULL; -@@ -470,61 +539,11 @@ zone_info_unix (const gchar *identifier, - } - else - { -- gsize prefix_len = 0; -- gchar *canonical_path = NULL; -- GError *read_link_err = NULL; -- -- filename = g_strdup ("/etc/localtime"); -- -- /* Resolve the actual timezone pointed to by /etc/localtime. */ -- resolved_identifier = g_file_read_link (filename, &read_link_err); -+ resolved_identifier = zone_identifier_unix (); - if (resolved_identifier == NULL) -- { -- gboolean not_a_symlink = g_error_matches (read_link_err, -- G_FILE_ERROR, -- G_FILE_ERROR_INVAL); -- g_clear_error (&read_link_err); -- -- /* Fallback to the content of /var/db/zoneinfo or /etc/timezone -- * if /etc/localtime is not a symlink. /var/db/zoneinfo is -- * where 'tzsetup' program on FreeBSD and DragonflyBSD stores -- * the timezone chosen by the user. /etc/timezone is where user -- * choice is expressed on Gentoo OpenRC and others. */ -- if (not_a_symlink && (g_file_get_contents ("/var/db/zoneinfo", -- &resolved_identifier, -- NULL, NULL) || -- g_file_get_contents ("/etc/timezone", -- &resolved_identifier, -- NULL, NULL))) -- g_strchomp (resolved_identifier); -- else -- { -- /* Error */ -- g_assert (resolved_identifier == NULL); -- goto out; -- } -- } -- else -- { -- /* Resolve relative path */ -- canonical_path = g_canonicalize_filename (resolved_identifier, "/etc"); -- g_free (resolved_identifier); -- resolved_identifier = g_steal_pointer (&canonical_path); -- } -+ goto out; - -- /* Strip the prefix and slashes if possible. */ -- if (g_str_has_prefix (resolved_identifier, tzdir)) -- { -- prefix_len = strlen (tzdir); -- while (*(resolved_identifier + prefix_len) == '/') -- prefix_len++; -- } -- -- if (prefix_len > 0) -- memmove (resolved_identifier, resolved_identifier + prefix_len, -- strlen (resolved_identifier) - prefix_len + 1 /* nul terminator */); -- -- g_free (canonical_path); -+ filename = g_strdup ("/etc/localtime"); - } - - file = g_mapped_file_new (filename, FALSE, NULL); --- -GitLab - - -From 7e59a4c0d5ab8e08fe2cf596fb9512708e183de8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= -Date: Wed, 23 Sep 2020 18:28:40 +0100 -Subject: [PATCH 2/4] gtimezone: Set resolved_identifier earlier - -We have been passing a &resolved_identifier address around for multiple -functions to set it. Each function may either: - - 1. leaving it for the next function to set, if returning early; - 2. set it to a duplicate of the passed identifier, if not NULL; - 3. get a fallback value and set it, otherwise. - -This can be simplified by setting it early to either: - - 1. a duplicate of the passed identifier, if not NULL; - 2. a fallback value, otherwise. - -This way we can avoid some unnecessary string duplication and freeing. -Also, on Windows, we avoid calling windows_default_tzname() twice. - -But the main motivation for this change is enabling the performance -optimization in the next commit. ---- - glib/gtimezone.c | 76 ++++++++++++++++-------------------------------- - 1 file changed, 25 insertions(+), 51 deletions(-) - -diff --git a/glib/gtimezone.c b/glib/gtimezone.c -index d90a9bb73..40064c9ab 100644 ---- a/glib/gtimezone.c -+++ b/glib/gtimezone.c -@@ -508,13 +508,12 @@ out: - } - - static GBytes* --zone_info_unix (const gchar *identifier, -- gchar **out_identifier) -+zone_info_unix (const gchar *identifier, -+ const gchar *resolved_identifier) - { - gchar *filename = NULL; - GMappedFile *file = NULL; - GBytes *zoneinfo = NULL; -- gchar *resolved_identifier = NULL; - const gchar *tzdir; - - tzdir = g_getenv ("TZDIR"); -@@ -527,8 +526,6 @@ zone_info_unix (const gchar *identifier, - glibc allows both syntaxes, so we should too */ - if (identifier != NULL) - { -- resolved_identifier = g_strdup (identifier); -- - if (*identifier == ':') - identifier ++; - -@@ -539,7 +536,6 @@ zone_info_unix (const gchar *identifier, - } - else - { -- resolved_identifier = zone_identifier_unix (); - if (resolved_identifier == NULL) - goto out; - -@@ -559,10 +555,6 @@ zone_info_unix (const gchar *identifier, - g_assert (resolved_identifier != NULL); - - out: -- if (out_identifier != NULL) -- *out_identifier = g_steal_pointer (&resolved_identifier); -- -- g_free (resolved_identifier); - g_free (filename); - - return zoneinfo; -@@ -834,14 +826,13 @@ register_tzi_to_tzi (RegTZI *reg, TIME_ZONE_INFORMATION *tzi) - - static guint - rules_from_windows_time_zone (const gchar *identifier, -- gchar **out_identifier, -- TimeZoneRule **rules, -- gboolean copy_identifier) -+ const gchar *resolved_identifier, -+ TimeZoneRule **rules) - { - HKEY key; - gchar *subkey = NULL; - gchar *subkey_dynamic = NULL; -- gchar *key_name = NULL; -+ const gchar *key_name; - const gchar *reg_key = - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"; - TIME_ZONE_INFORMATION tzi; -@@ -856,19 +847,15 @@ rules_from_windows_time_zone (const gchar *identifier, - if (GetSystemDirectoryW (winsyspath, MAX_PATH) == 0) - return 0; - -- g_assert (copy_identifier == FALSE || out_identifier != NULL); - g_assert (rules != NULL); - -- if (copy_identifier) -- *out_identifier = NULL; -- - *rules = NULL; - key_name = NULL; - - if (!identifier) -- key_name = windows_default_tzname (); -+ key_name = resolved_identifier; - else -- key_name = g_strdup (identifier); -+ key_name = identifier; - - if (!key_name) - return 0; -@@ -1011,16 +998,9 @@ utf16_conv_failed: - else - (*rules)[rules_num - 1].start_year = (*rules)[rules_num - 2].start_year + 1; - -- if (copy_identifier) -- *out_identifier = g_steal_pointer (&key_name); -- else -- g_free (key_name); -- - return rules_num; - } - -- g_free (key_name); -- - return 0; - } - -@@ -1521,16 +1501,13 @@ parse_identifier_boundaries (gchar **pos, TimeZoneRule *tzr) - */ - static guint - rules_from_identifier (const gchar *identifier, -- gchar **out_identifier, - TimeZoneRule **rules) - { - gchar *pos; - TimeZoneRule tzr; - -- g_assert (out_identifier != NULL); - g_assert (rules != NULL); - -- *out_identifier = NULL; - *rules = NULL; - - if (!identifier) -@@ -1545,7 +1522,6 @@ rules_from_identifier (const gchar *identifier, - - if (*pos == 0) - { -- *out_identifier = g_strdup (identifier); - return create_ruleset_from_rule (rules, &tzr); - } - -@@ -1566,14 +1542,8 @@ rules_from_identifier (const gchar *identifier, - /* Use US rules, Windows' default is Pacific Standard Time */ - if ((rules_num = rules_from_windows_time_zone ("Pacific Standard Time", - NULL, -- rules, -- FALSE))) -+ rules))) - { -- /* We don't want to hardcode our identifier here as -- * "Pacific Standard Time", use what was passed in -- */ -- *out_identifier = g_strdup (identifier); -- - for (i = 0; i < rules_num - 1; i++) - { - (*rules)[i].std_offset = - tzr.std_offset; -@@ -1594,7 +1564,6 @@ rules_from_identifier (const gchar *identifier, - if (!parse_identifier_boundaries (&pos, &tzr)) - return 0; - -- *out_identifier = g_strdup (identifier); - return create_ruleset_from_rule (rules, &tzr); - } - -@@ -1605,17 +1574,13 @@ parse_footertz (const gchar *footer, size_t footerlen) - gchar *tzstring = g_strndup (footer + 1, footerlen - 2); - GTimeZone *footertz = NULL; - -- /* FIXME: it might make sense to modify rules_from_identifier to -- allow NULL to be passed instead of &ident, saving the strdup/free -- pair. The allocation for tzstring could also be avoided by -+ /* FIXME: The allocation for tzstring could be avoided by - passing a gsize identifier_len argument to rules_from_identifier - and changing the code in that function to stop assuming that - identifier is nul-terminated. */ -- gchar *ident; - TimeZoneRule *rules; -- guint rules_num = rules_from_identifier (tzstring, &ident, &rules); -+ guint rules_num = rules_from_identifier (tzstring, &rules); - -- g_free (ident); - g_free (tzstring); - if (rules_num > 1) - { -@@ -1723,6 +1688,16 @@ g_time_zone_new (const gchar *identifier) - G_UNLOCK (time_zones); - return tz; - } -+ else -+ resolved_identifier = g_strdup (identifier); -+ } -+ else -+ { -+#ifdef G_OS_UNIX -+ resolved_identifier = zone_identifier_unix (); -+#elif defined (G_OS_WIN32) -+ resolved_identifier = windows_default_tzname (); -+#endif - } - - tz = g_slice_new0 (GTimeZone); -@@ -1731,7 +1706,7 @@ g_time_zone_new (const gchar *identifier) - zone_for_constant_offset (tz, identifier); - - if (tz->t_info == NULL && -- (rules_num = rules_from_identifier (identifier, &resolved_identifier, &rules))) -+ (rules_num = rules_from_identifier (identifier, &rules))) - { - init_zone_from_rules (tz, rules, rules_num, g_steal_pointer (&resolved_identifier)); - g_free (rules); -@@ -1740,7 +1715,7 @@ g_time_zone_new (const gchar *identifier) - if (tz->t_info == NULL) - { - #ifdef G_OS_UNIX -- GBytes *zoneinfo = zone_info_unix (identifier, &resolved_identifier); -+ GBytes *zoneinfo = zone_info_unix (identifier, resolved_identifier); - if (zoneinfo != NULL) - { - init_zone_from_iana_info (tz, zoneinfo, g_steal_pointer (&resolved_identifier)); -@@ -1748,9 +1723,8 @@ g_time_zone_new (const gchar *identifier) - } - #elif defined (G_OS_WIN32) - if ((rules_num = rules_from_windows_time_zone (identifier, -- &resolved_identifier, -- &rules, -- TRUE))) -+ resolved_identifier, -+ &rules))) - { - init_zone_from_rules (tz, rules, rules_num, g_steal_pointer (&resolved_identifier)); - g_free (rules); -@@ -1777,7 +1751,7 @@ g_time_zone_new (const gchar *identifier) - rules[0].start_year = MIN_TZYEAR; - rules[1].start_year = MAX_TZYEAR; - -- init_zone_from_rules (tz, rules, 2, windows_default_tzname ()); -+ init_zone_from_rules (tz, rules, 2, g_steal_pointer (&resolved_identifier)); - } - - g_free (rules); --- -GitLab - - -From 5237b4984306847dff05db54b5c12c83662f2f1d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= -Date: Thu, 1 Oct 2020 21:11:44 +0100 -Subject: [PATCH 3/4] gtimezone: Cache default timezone indefinitely - -We cache GTimeZone instances to avoid expensive construction when the -same id is requested again. - -However, if the NULL id is passed to g_time_zone_new(), we always -construct a new instance for the default/fallback timezone. - -With the recent introduction of some heavy calculations[1], repeated -instance construction in such cases has visible performance impact in -nautilus list view and other such GtkTreeView consumers. - -To avoid this, cache reference to a constructed default timezone and -use it the next time g_time_zone_new() is called with NULL argument, -as long as the default identifier doesn't change. We already did the -same for the local timezone[2]. - -Fixes: https://gitlab.gnome.org/GNOME/glib/-/issues/2204 - -Based on idea proposed by Sebastian Keller . - -[1] 25d950b61f92f25cc9ab20d683aa4d6969f93098 -[2] 551e83662de9815d161a82c760cfa77995905740 ---- - glib/gtimezone.c | 37 ++++++++++++++++++++++++++++++++----- - 1 file changed, 32 insertions(+), 5 deletions(-) - -diff --git a/glib/gtimezone.c b/glib/gtimezone.c -index 40064c9ab..035da2f45 100644 ---- a/glib/gtimezone.c -+++ b/glib/gtimezone.c -@@ -195,6 +195,8 @@ struct _GTimeZone - - G_LOCK_DEFINE_STATIC (time_zones); - static GHashTable/**/ *time_zones; -+G_LOCK_DEFINE_STATIC (tz_default); -+static GTimeZone *tz_default = NULL; - G_LOCK_DEFINE_STATIC (tz_local); - static gchar *tzenv_cached = NULL; - static GTimeZone *tz_local = NULL; -@@ -1675,12 +1677,12 @@ g_time_zone_new (const gchar *identifier) - gint rules_num; - gchar *resolved_identifier = NULL; - -- G_LOCK (time_zones); -- if (time_zones == NULL) -- time_zones = g_hash_table_new (g_str_hash, g_str_equal); -- - if (identifier) - { -+ G_LOCK (time_zones); -+ if (time_zones == NULL) -+ time_zones = g_hash_table_new (g_str_hash, g_str_equal); -+ - tz = g_hash_table_lookup (time_zones, identifier); - if (tz) - { -@@ -1693,11 +1695,26 @@ g_time_zone_new (const gchar *identifier) - } - else - { -+ G_LOCK (tz_default); - #ifdef G_OS_UNIX - resolved_identifier = zone_identifier_unix (); - #elif defined (G_OS_WIN32) - resolved_identifier = windows_default_tzname (); - #endif -+ if (tz_default) -+ { -+ /* Flush default if changed */ -+ if (g_strcmp0 (tz_default->name, resolved_identifier)) -+ g_clear_pointer (&tz_default, g_time_zone_unref); -+ else -+ { -+ tz = g_time_zone_ref (tz_default); -+ G_UNLOCK (tz_default); -+ -+ g_free (resolved_identifier); -+ return tz; -+ } -+ } - } - - tz = g_slice_new0 (GTimeZone); -@@ -1773,9 +1790,19 @@ g_time_zone_new (const gchar *identifier) - { - if (identifier) - g_hash_table_insert (time_zones, tz->name, tz); -+ else if (tz->name) -+ { -+ /* Caching reference */ -+ g_atomic_int_inc (&tz->ref_count); -+ tz_default = tz; -+ } - } - g_atomic_int_inc (&tz->ref_count); -- G_UNLOCK (time_zones); -+ -+ if (identifier) -+ G_UNLOCK (time_zones); -+ else -+ G_UNLOCK (tz_default); - - return tz; - } --- -GitLab - - -From 02753644b33660a175d1a9b1ea9e8717c314ef23 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= -Date: Wed, 23 Sep 2020 19:36:49 +0100 -Subject: [PATCH 4/4] Revert "gtimezone: Cache timezones based on the - identifier they were created by" +From c355b0970521bd8b3e5f4fee6a2a170c65b9d723 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Wed, 14 Oct 2020 15:30:18 -0500 +Subject: [PATCH] Revert "gtimezone: Cache timezones based on the identifier + they were created by" This reverts commit 851241f19a3fd9ec693b3dd8f37a84c7f970984a. - -That commit avoids a performance regression but introduces a behavior regression: -changes to /etc/localtime have no effect for the remaining of the application's -runtime. - -With the optimization introduced by the previous commit, we can pass NULL to -g_time_zone_new() repeatedly with no performance drawback, so we no longer have -to workaround this case. --- glib/gtimezone.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/glib/gtimezone.c b/glib/gtimezone.c -index 035da2f45..8e38bb549 100644 +index ef67ec50b..8e0621e54 100644 --- a/glib/gtimezone.c +++ b/glib/gtimezone.c -@@ -198,7 +198,6 @@ static GHashTable/**/ *time_zones; - G_LOCK_DEFINE_STATIC (tz_default); - static GTimeZone *tz_default = NULL; +@@ -196,7 +196,6 @@ struct _GTimeZone + G_LOCK_DEFINE_STATIC (time_zones); + static GHashTable/**/ *time_zones; G_LOCK_DEFINE_STATIC (tz_local); -static gchar *tzenv_cached = NULL; static GTimeZone *tz_local = NULL; #define MIN_TZYEAR 1916 /* Daylight Savings started in WWI */ -@@ -1863,17 +1862,11 @@ g_time_zone_new_local (void) +@@ -1843,17 +1842,11 @@ g_time_zone_new_local (void) G_LOCK (tz_local); /* Is time zone changed and must be flushed? */ @@ -595,5 +43,4 @@ index 035da2f45..8e38bb549 100644 tz = g_time_zone_ref (tz_local); -- -GitLab - +2.28.0