From 311d2606a70528e14093dd93178a2c7170718333 Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Tue, 13 Feb 2024 14:22:11 +0000 Subject: glib-2.0: backport memory monitor test fixes We've been seeing the memory-monitor-dbus test case fail occasionally on the autobuilder. Luckily there have been a series of fixes upstream to fix races in the test case, so backport these and hopefully they fix the issue. [ YOCTO #15362 ] Signed-off-by: Ross Burton Signed-off-by: Richard Purdie --- .../glib-2.0/glib-2.0/memory-monitor.patch | 364 +++++++++++++++++++++ meta/recipes-core/glib-2.0/glib-2.0_2.78.3.bb | 1 + 2 files changed, 365 insertions(+) create mode 100644 meta/recipes-core/glib-2.0/glib-2.0/memory-monitor.patch (limited to 'meta/recipes-core/glib-2.0') diff --git a/meta/recipes-core/glib-2.0/glib-2.0/memory-monitor.patch b/meta/recipes-core/glib-2.0/glib-2.0/memory-monitor.patch new file mode 100644 index 0000000000..f9dfc5bb05 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/memory-monitor.patch @@ -0,0 +1,364 @@ +From df7506918efc8748dac8b8398021e1b79d694ba4 Mon Sep 17 00:00:00 2001 +From: Philip Withnall +Date: Tue, 23 Jan 2024 11:16:52 +0000 +Subject: [PATCH] Merge branch '2887-memory-monitor-tests' into 'main' + +tests: Fix race condition in memory-monitor-dbus.test + +Closes #2887 + +See merge request GNOME/glib!3844 + +Hopefully these commits fix the occasional failures we've been seeing: +https://bugzilla.yoctoproject.org/show_bug.cgi?id=15362 + +Upstream-Status: Backport +Signed-off-by: Ross Burton +--- + gio/tests/memory-monitor-dbus.py.in | 64 +++++++++++++------- + gio/tests/memory-monitor-portal.py.in | 54 ++++++++++------- + gio/tests/power-profile-monitor-dbus.py.in | 35 ++++++----- + gio/tests/power-profile-monitor-portal.py.in | 34 ++++++----- + 4 files changed, 113 insertions(+), 74 deletions(-) + +diff --git a/gio/tests/memory-monitor-dbus.py.in b/gio/tests/memory-monitor-dbus.py.in +index bf3291847..7aae01e70 100755 +--- a/gio/tests/memory-monitor-dbus.py.in ++++ b/gio/tests/memory-monitor-dbus.py.in +@@ -16,7 +16,6 @@ import sys + import subprocess + import fcntl + import os +-import time + + import taptestrunner + +@@ -57,53 +56,74 @@ try: + fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) + self.last_warning = -1 + self.dbusmock = dbus.Interface(self.obj_lmm, dbusmock.MOCK_IFACE) ++ ++ try: ++ self.wait_for_bus_object('org.freedesktop.LowMemoryMonitor', ++ '/org/freedesktop/LowMemoryMonitor', ++ system_bus=True) ++ except: ++ raise ++ + self.memory_monitor = Gio.MemoryMonitor.dup_default() ++ assert("GMemoryMonitorDBus" in str(self.memory_monitor)) + self.memory_monitor.connect("low-memory-warning", self.memory_warning_cb) + self.mainloop = GLib.MainLoop() + self.main_context = self.mainloop.get_context() + ++ # The LowMemoryMonitor API is stateless: it doesn’t expose any ++ # properties, just a warning signal. Emit the signal in a loop until ++ # the GMemoryMonitor instance has initialised and synchronised to ++ # the right state. ++ def emit_warning(level): ++ self.dbusmock.EmitWarning(level) ++ return GLib.SOURCE_CONTINUE ++ ++ idle_id = GLib.idle_add(emit_warning, 0) ++ while self.last_warning != 0: ++ self.main_context.iteration(True) ++ GLib.source_remove(idle_id) ++ + def tearDown(self): + self.p_mock.terminate() + self.p_mock.wait() + +- def assertEventually(self, condition, message=None, timeout=50): ++ def assertEventually(self, condition, message=None, timeout=5): + '''Assert that condition function eventually returns True. + +- Timeout is in deciseconds, defaulting to 50 (5 seconds). message is ++ Timeout is in seconds, defaulting to 5 seconds. message is + printed on failure. + ''' +- while timeout >= 0: +- context = GLib.MainContext.default() +- while context.iteration(False): +- pass +- if condition(): +- break +- timeout -= 1 +- time.sleep(0.1) +- else: +- self.fail(message or 'timed out waiting for ' + str(condition)) ++ if not message: ++ message = 'timed out waiting for ' + str(condition) ++ ++ def timed_out_cb(message): ++ self.fail(message) ++ return GLib.SOURCE_REMOVE ++ ++ timeout_source = GLib.timeout_source_new_seconds(timeout) ++ timeout_source.set_callback(timed_out_cb, message) ++ timeout_source.attach(self.main_context) ++ ++ while not condition(): ++ self.main_context.iteration(True) ++ ++ timeout_source.destroy() + + def memory_warning_cb(self, monitor, level): ++ print("Received memory warning signal, level", level) + self.last_warning = level + self.main_context.wakeup() + + def test_low_memory_warning_signal(self): + '''LowMemoryWarning signal''' + +- # Wait 2 seconds +- timeout = 2 +- while timeout > 0: +- time.sleep(0.5) +- timeout -= 0.5 +- self.main_context.iteration(False) +- + self.dbusmock.EmitWarning(100) + # Wait 2 seconds or until warning +- self.assertEventually(lambda: self.last_warning == 100, "'100' low-memory warning not received", 20) ++ self.assertEventually(lambda: self.last_warning == 100, "'100' low-memory warning not received", 2) + + self.dbusmock.EmitWarning(255) + # Wait 2 seconds or until warning +- self.assertEventually(lambda: self.last_warning == 255, "'255' low-memory warning not received", 20) ++ self.assertEventually(lambda: self.last_warning == 255, "'255' low-memory warning not received", 2) + + except ImportError as e: + @unittest.skip("Cannot import %s" % e.name) +diff --git a/gio/tests/memory-monitor-portal.py.in b/gio/tests/memory-monitor-portal.py.in +index 748cee850..f570508f9 100755 +--- a/gio/tests/memory-monitor-portal.py.in ++++ b/gio/tests/memory-monitor-portal.py.in +@@ -16,7 +16,6 @@ import sys + import subprocess + import fcntl + import os +-import time + + import taptestrunner + +@@ -80,26 +79,44 @@ try: + self.mainloop = GLib.MainLoop() + self.main_context = self.mainloop.get_context() + ++ # The LowMemoryMonitor API is stateless: it doesn’t expose any ++ # properties, just a warning signal. Emit the signal in a loop until ++ # the GMemoryMonitor instance has initialised and synchronised to ++ # the right state. ++ def emit_warning(level): ++ self.dbusmock.EmitWarning(level) ++ return GLib.SOURCE_CONTINUE ++ ++ idle_id = GLib.idle_add(self.emit_warning, 0) ++ while self.last_warning != 0: ++ self.main_context.iteration(True) ++ GLib.source_remove(idle_id) ++ + def tearDown(self): + self.p_mock.terminate() + self.p_mock.wait() + +- def assertEventually(self, condition, message=None, timeout=50): ++ def assertEventually(self, condition, message=None, timeout=5): + '''Assert that condition function eventually returns True. + +- Timeout is in deciseconds, defaulting to 50 (5 seconds). message is ++ Timeout is in seconds, defaulting to 5 seconds. message is + printed on failure. + ''' +- while timeout >= 0: +- context = GLib.MainContext.default() +- while context.iteration(False): +- pass +- if condition(): +- break +- timeout -= 1 +- time.sleep(0.1) +- else: +- self.fail(message or 'timed out waiting for ' + str(condition)) ++ if not message: ++ message = 'timed out waiting for ' + str(condition) ++ ++ def timed_out_cb(message): ++ self.fail(message) ++ return GLib.SOURCE_REMOVE ++ ++ timeout_source = GLib.timeout_source_new_seconds(timeout) ++ timeout_source.set_callback(timed_out_cb, message) ++ timeout_source.attach(self.main_context) ++ ++ while not condition(): ++ self.main_context.iteration(True) ++ ++ timeout_source.destroy() + + def portal_memory_warning_cb(self, monitor, level): + self.last_warning = level +@@ -108,20 +125,13 @@ try: + def test_low_memory_warning_portal_signal(self): + '''LowMemoryWarning signal''' + +- # Wait 2 seconds +- timeout = 2 +- while timeout > 0: +- time.sleep(0.5) +- timeout -= 0.5 +- self.main_context.iteration(False) +- + self.dbusmock.EmitWarning(100) + # Wait 2 seconds or until warning +- self.assertEventually(lambda: self.last_warning == 100, "'100' low-memory warning not received", 20) ++ self.assertEventually(lambda: self.last_warning == 100, "'100' low-memory warning not received", 2) + + self.dbusmock.EmitWarning(255) + # Wait 2 seconds or until warning +- self.assertEventually(lambda: self.last_warning == 255, "'255' low-memory warning not received", 20) ++ self.assertEventually(lambda: self.last_warning == 255, "'255' low-memory warning not received", 2) + + except ImportError as e: + @unittest.skip("Cannot import %s" % e.name) +diff --git a/gio/tests/power-profile-monitor-dbus.py.in b/gio/tests/power-profile-monitor-dbus.py.in +index 06e594f4a..f955afc80 100755 +--- a/gio/tests/power-profile-monitor-dbus.py.in ++++ b/gio/tests/power-profile-monitor-dbus.py.in +@@ -16,7 +16,6 @@ import sys + import subprocess + import fcntl + import os +-import time + + import taptestrunner + +@@ -58,6 +57,7 @@ try: + self.power_saver_enabled = False + self.dbus_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE) + self.power_profile_monitor = Gio.PowerProfileMonitor.dup_default() ++ assert("GPowerProfileMonitorDBus" in str(self.power_profile_monitor)) + self.power_profile_monitor.connect("notify::power-saver-enabled", self.power_saver_enabled_cb) + self.mainloop = GLib.MainLoop() + self.main_context = self.mainloop.get_context() +@@ -66,22 +66,27 @@ try: + self.p_mock.terminate() + self.p_mock.wait() + +- def assertEventually(self, condition, message=None, timeout=50): ++ def assertEventually(self, condition, message=None, timeout=5): + '''Assert that condition function eventually returns True. + +- Timeout is in deciseconds, defaulting to 50 (5 seconds). message is ++ Timeout is in seconds, defaulting to 5 seconds. message is + printed on failure. + ''' +- while timeout >= 0: +- context = GLib.MainContext.default() +- while context.iteration(False): +- pass +- if condition(): +- break +- timeout -= 1 +- time.sleep(0.1) +- else: +- self.fail(message or 'timed out waiting for ' + str(condition)) ++ if not message: ++ message = 'timed out waiting for ' + str(condition) ++ ++ def timed_out_cb(message): ++ self.fail(message) ++ return GLib.SOURCE_REMOVE ++ ++ timeout_source = GLib.timeout_source_new_seconds(timeout) ++ timeout_source.set_callback(timed_out_cb, message) ++ timeout_source.attach(self.main_context) ++ ++ while not condition(): ++ self.main_context.iteration(True) ++ ++ timeout_source.destroy() + + def power_saver_enabled_cb(self, spec, data): + self.power_saver_enabled = self.power_profile_monitor.get_power_saver_enabled() +@@ -92,10 +97,10 @@ try: + + self.assertEqual(self.power_profile_monitor.get_power_saver_enabled(), False) + self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('power-saver', variant_level=1)) +- self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 10) ++ self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 1) + + self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('balanced', variant_level=1)) +- self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 10) ++ self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 1) + + except ImportError as e: + @unittest.skip("Cannot import %s" % e.name) +diff --git a/gio/tests/power-profile-monitor-portal.py.in b/gio/tests/power-profile-monitor-portal.py.in +index 09e9a450d..ad2abf621 100755 +--- a/gio/tests/power-profile-monitor-portal.py.in ++++ b/gio/tests/power-profile-monitor-portal.py.in +@@ -16,7 +16,6 @@ import sys + import subprocess + import fcntl + import os +-import time + + import taptestrunner + +@@ -90,22 +89,27 @@ try: + self.p_mock.terminate() + self.p_mock.wait() + +- def assertEventually(self, condition, message=None, timeout=50): ++ def assertEventually(self, condition, message=None, timeout=5): + '''Assert that condition function eventually returns True. + +- Timeout is in deciseconds, defaulting to 50 (5 seconds). message is ++ Timeout is in seconds, defaulting to 5 seconds. message is + printed on failure. + ''' +- while timeout >= 0: +- context = GLib.MainContext.default() +- while context.iteration(False): +- pass +- if condition(): +- break +- timeout -= 1 +- time.sleep(0.1) +- else: +- self.fail(message or 'timed out waiting for ' + str(condition)) ++ if not message: ++ message = 'timed out waiting for ' + str(condition) ++ ++ def timed_out_cb(message): ++ self.fail(message) ++ return GLib.SOURCE_REMOVE ++ ++ timeout_source = GLib.timeout_source_new_seconds(timeout) ++ timeout_source.set_callback(timed_out_cb, message) ++ timeout_source.attach(self.main_context) ++ ++ while not condition(): ++ self.main_context.iteration(True) ++ ++ timeout_source.destroy() + + def power_saver_enabled_cb(self, spec, data): + self.power_saver_enabled = self.power_profile_monitor.get_power_saver_enabled() +@@ -116,10 +120,10 @@ try: + + self.assertEqual(self.power_profile_monitor.get_power_saver_enabled(), False) + self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('power-saver', variant_level=1)) +- self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 10) ++ self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 1) + + self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('balanced', variant_level=1)) +- self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 10) ++ self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 1) + + def test_power_profile_power_saver_enabled_portal_default(self): + '''power-saver-enabled property default value''' +-- +2.34.1 + diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.78.3.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.78.3.bb index 2729b2a596..42814ba544 100644 --- a/meta/recipes-core/glib-2.0/glib-2.0_2.78.3.bb +++ b/meta/recipes-core/glib-2.0/glib-2.0_2.78.3.bb @@ -14,6 +14,7 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ file://0001-Do-not-write-bindir-into-pkg-config-files.patch \ file://0001-meson-Run-atomics-test-on-clang-as-well.patch \ file://0001-gio-tests-resources.c-comment-out-a-build-host-only-.patch \ + file://memory-monitor.patch \ file://native-gtkdoc.patch \ " SRC_URI:append:class-native = " file://relocate-modules.patch \ -- cgit 1.2.3-korg