[glib: 3/4] gio/win32: add GMemoryMonitorWin32
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 3/4] gio/win32: add GMemoryMonitorWin32
- Date: Tue, 25 Jan 2022 18:11:54 +0000 (UTC)
commit bb1b9d90ec2141c1690e222edc4b26427cd8a26c
Author: Marc-André Lureau <marcandre lureau redhat com>
Date: Mon Jan 24 00:36:56 2022 +0400
gio/win32: add GMemoryMonitorWin32
Windows has CreateMemoryResourceNotification() API:
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-creatememoryresourcenotification
It only notifies whether "Available physical memory is running low."
Signed-off-by: Marc-André Lureau <marcandre lureau redhat com>
gio/giomodule.c | 2 +
gio/gmemorymonitorwin32.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++
gio/meson.build | 1 +
3 files changed, 264 insertions(+)
---
diff --git a/gio/giomodule.c b/gio/giomodule.c
index d34037a45..90af75118 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -1080,6 +1080,7 @@ extern GType _g_network_monitor_nm_get_type (void);
extern GType g_memory_monitor_dbus_get_type (void);
extern GType g_memory_monitor_portal_get_type (void);
+extern GType g_memory_monitor_win32_get_type (void);
extern GType g_power_profile_monitor_dbus_get_type (void);
#ifdef G_OS_UNIX
@@ -1315,6 +1316,7 @@ _g_io_modules_ensure_loaded (void)
#ifdef G_OS_WIN32
g_type_ensure (g_win32_notification_backend_get_type ());
g_type_ensure (_g_winhttp_vfs_get_type ());
+ g_type_ensure (g_memory_monitor_win32_get_type ());
#endif
g_type_ensure (_g_local_vfs_get_type ());
g_type_ensure (_g_dummy_proxy_resolver_get_type ());
diff --git a/gio/gmemorymonitorwin32.c b/gio/gmemorymonitorwin32.c
new file mode 100644
index 000000000..c0e09a5bf
--- /dev/null
+++ b/gio/gmemorymonitorwin32.c
@@ -0,0 +1,261 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gmemorymonitor.h"
+#include "gioerror.h"
+#include "ginitable.h"
+#include "giomodule-priv.h"
+#include "glibintl.h"
+#include "glib/gstdio.h"
+#include "gcancellable.h"
+
+#include <windows.h>
+
+#define G_TYPE_MEMORY_MONITOR_WIN32 (g_memory_monitor_win32_get_type ())
+G_DECLARE_FINAL_TYPE (GMemoryMonitorWin32, g_memory_monitor_win32, G, MEMORY_MONITOR_WIN32, GObject)
+
+#define G_MEMORY_MONITOR_WIN32_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE,
GInitable))
+
+static void g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *iface);
+static void g_memory_monitor_win32_initable_iface_init (GInitableIface *iface);
+
+struct _GMemoryMonitorWin32
+{
+ GObject parent_instance;
+
+ HANDLE event;
+ HANDLE mem;
+ HANDLE thread;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GMemoryMonitorWin32, g_memory_monitor_win32, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_memory_monitor_win32_initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_MEMORY_MONITOR,
+ g_memory_monitor_win32_iface_init)
+ _g_io_modules_ensure_extension_points_registered ();
+ g_io_extension_point_implement (G_MEMORY_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "win32",
+ 30))
+
+static void
+g_memory_monitor_win32_init (GMemoryMonitorWin32 *win32)
+{
+}
+
+static gboolean
+watch_handler (gpointer user_data)
+{
+ GMemoryMonitorWin32 *win32 = user_data;
+
+ g_signal_emit_by_name (win32, "low-memory-warning",
+ G_MEMORY_MONITOR_WARNING_LEVEL_LOW);
+
+ return G_SOURCE_REMOVE;
+}
+
+/* Thread which watches for win32 memory resource events */
+static DWORD WINAPI
+watch_thread_function (LPVOID parameter)
+{
+ GWeakRef *weak_ref = parameter;
+ GMemoryMonitorWin32 *win32 = NULL;
+ HANDLE handles[2] = { 0, };
+ DWORD result;
+ BOOL low_memory_state;
+
+ win32 = g_weak_ref_get (weak_ref);
+ if (!win32)
+ goto end;
+
+ if (!DuplicateHandle (GetCurrentProcess (),
+ win32->event,
+ GetCurrentProcess (),
+ &handles[0],
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ gchar *emsg;
+
+ emsg = g_win32_error_message (GetLastError ());
+ g_debug ("DuplicateHandle failed: %s", emsg);
+ g_free (emsg);
+ goto end;
+ }
+
+ if (!DuplicateHandle (GetCurrentProcess (),
+ win32->mem,
+ GetCurrentProcess (),
+ &handles[1],
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ gchar *emsg;
+
+ emsg = g_win32_error_message (GetLastError ());
+ g_debug ("DuplicateHandle failed: %s", emsg);
+ g_free (emsg);
+ goto end;
+ }
+
+ g_clear_object (&win32);
+
+ while (1)
+ {
+ if (!QueryMemoryResourceNotification (handles[1], &low_memory_state))
+ {
+ gchar *emsg;
+
+ emsg = g_win32_error_message (GetLastError ());
+ g_debug ("QueryMemoryResourceNotification failed: %s", emsg);
+ g_free (emsg);
+ break;
+ }
+
+ win32 = g_weak_ref_get (weak_ref);
+ if (!win32)
+ break;
+
+ if (low_memory_state)
+ {
+ g_idle_add_full (G_PRIORITY_DEFAULT,
+ watch_handler,
+ g_steal_pointer (&win32),
+ g_object_unref);
+ /* throttle a bit the loop */
+ g_usleep (G_USEC_PER_SEC);
+ continue;
+ }
+
+ g_clear_object (&win32);
+
+ result = WaitForMultipleObjects (G_N_ELEMENTS (handles), handles, FALSE, INFINITE);
+ switch (result)
+ {
+ case WAIT_OBJECT_0 + 1:
+ continue;
+
+ case WAIT_FAILED:
+ {
+ gchar *emsg;
+
+ emsg = g_win32_error_message (GetLastError ());
+ g_debug ("WaitForMultipleObjects failed: %s", emsg);
+ g_free (emsg);
+ }
+ G_GNUC_FALLTHROUGH;
+ default:
+ goto end;
+ }
+ }
+
+end:
+ if (handles[0])
+ CloseHandle (handles[0]);
+ if (handles[1])
+ CloseHandle (handles[1]);
+ g_clear_object (&win32);
+ g_weak_ref_clear (weak_ref);
+ g_free (weak_ref);
+ return 0;
+}
+
+static gboolean
+g_memory_monitor_win32_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GMemoryMonitorWin32 *win32 = G_MEMORY_MONITOR_WIN32 (initable);
+ GWeakRef *weak_ref = NULL;
+
+ win32->event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (win32->event == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
+ "Failed to create event");
+ return FALSE;
+ }
+
+ win32->mem = CreateMemoryResourceNotification (LowMemoryResourceNotification);
+ if (win32->mem == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
+ "Failed to create resource notification handle");
+ return FALSE;
+ }
+
+ weak_ref = g_new0 (GWeakRef, 1);
+ g_weak_ref_init (weak_ref, win32);
+ /* Use CreateThread (not GThread) with a small stack to make it more lightweight. */
+ win32->thread = CreateThread (NULL, 1024, watch_thread_function, weak_ref, 0, NULL);
+ if (win32->thread == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()),
+ "Failed to create memory resource notification thread");
+ g_weak_ref_clear (weak_ref);
+ g_free (weak_ref);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+g_memory_monitor_win32_finalize (GObject *object)
+{
+ GMemoryMonitorWin32 *win32 = G_MEMORY_MONITOR_WIN32 (object);
+
+ if (win32->thread)
+ {
+ SetEvent (win32->event);
+ WaitForSingleObject (win32->thread, INFINITE);
+ CloseHandle (win32->thread);
+ }
+
+ if (win32->event)
+ CloseHandle (win32->event);
+
+ if (win32->mem)
+ CloseHandle (win32->mem);
+
+ G_OBJECT_CLASS (g_memory_monitor_win32_parent_class)->finalize (object);
+}
+
+static void
+g_memory_monitor_win32_class_init (GMemoryMonitorWin32Class *nl_class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
+
+ gobject_class->finalize = g_memory_monitor_win32_finalize;
+}
+
+static void
+g_memory_monitor_win32_iface_init (GMemoryMonitorInterface *monitor_iface)
+{
+}
+
+static void
+g_memory_monitor_win32_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_memory_monitor_win32_initable_init;
+}
diff --git a/gio/meson.build b/gio/meson.build
index dbe903db2..43c9c41cc 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -423,6 +423,7 @@ else
platform_deps += uwp_gio_deps
win32_sources += files(
+ 'gmemorymonitorwin32.c',
'gwin32registrykey.c',
'gwin32mount.c',
'gwin32volumemonitor.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]