context: Add a new API to raise and restore NOFILE limits

Wayland, especially when using SHM buffers, can use a lot of file
descriptors and can possibly reach the NOFILE soft limit.

Add a new API to MetaContext to raise and restore the NOFILE limit so
that the Wayland compositor can use as many file descriptors as the hard
limit allows.

See-also: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1283
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2235>
This commit is contained in:
Olivier Fourdan 2022-01-14 11:33:22 +01:00
parent 38f3bf6ee2
commit 8b9341131a
2 changed files with 121 additions and 0 deletions

View File

@ -23,6 +23,7 @@
#include "core/meta-context-private.h" #include "core/meta-context-private.h"
#include <locale.h> #include <locale.h>
#include <sys/resource.h>
#include "backends/meta-backend-private.h" #include "backends/meta-backend-private.h"
#include "compositor/meta-plugin-manager.h" #include "compositor/meta-plugin-manager.h"
@ -77,6 +78,9 @@ typedef struct _MetaContextPrivate
GMainLoop *main_loop; GMainLoop *main_loop;
GError *termination_error; GError *termination_error;
#ifdef RLIMIT_NOFILE
struct rlimit saved_rlimit_nofile;
#endif
} MetaContextPrivate; } MetaContextPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaContext, meta_context, G_TYPE_OBJECT) G_DEFINE_TYPE_WITH_PRIVATE (MetaContext, meta_context, G_TYPE_OBJECT)
@ -492,6 +496,108 @@ meta_context_set_unsafe_mode (MetaContext *context,
g_object_notify_by_pspec (G_OBJECT (context), obj_props[PROP_UNSAFE_MODE]); g_object_notify_by_pspec (G_OBJECT (context), obj_props[PROP_UNSAFE_MODE]);
} }
static gboolean
meta_context_save_rlimit_nofile (MetaContext *context,
GError **error)
{
#ifdef RLIMIT_NOFILE
MetaContextPrivate *priv = meta_context_get_instance_private (context);
if (getrlimit (RLIMIT_NOFILE, &priv->saved_rlimit_nofile) != 0)
{
priv->saved_rlimit_nofile.rlim_cur = 0;
priv->saved_rlimit_nofile.rlim_max = 0;
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"getrlimit failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
#else
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
"Missing support for RLIMIT_NOFILE");
return FALSE;
#endif
}
/**
* meta_context_raise_rlimit_nofile:
* @context: a #MetaContext
* @error: a return location for errors
*
* Raises the RLIMIT_NOFILE limit value to the hard limit.
*/
gboolean
meta_context_raise_rlimit_nofile (MetaContext *context,
GError **error)
{
#ifdef RLIMIT_NOFILE
struct rlimit new_rlimit;
if (getrlimit (RLIMIT_NOFILE, &new_rlimit) != 0)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"getrlimit failed: %s", g_strerror (errno));
return FALSE;
}
/* Raise the rlimit_nofile value to the hard limit */
new_rlimit.rlim_cur = new_rlimit.rlim_max;
if (setrlimit (RLIMIT_NOFILE, &new_rlimit) != 0)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"setrlimit failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
#else
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
"Missing support for RLIMIT_NOFILE");
return FALSE;
#endif
}
/**
* meta_context_restore_rlimit_nofile:
* @context: a #MetaContext
* @error: a return location for errors
*
* Restores the RLIMIT_NOFILE limits from when the #MetaContext was created.
*/
gboolean
meta_context_restore_rlimit_nofile (MetaContext *context,
GError **error)
{
#ifdef RLIMIT_NOFILE
MetaContextPrivate *priv = meta_context_get_instance_private (context);
if (priv->saved_rlimit_nofile.rlim_cur == 0)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
"RLIMIT_NOFILE not saved");
return FALSE;
}
if (setrlimit (RLIMIT_NOFILE, &priv->saved_rlimit_nofile) != 0)
{
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"setrlimit failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
#else
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS,
"Missing support for RLIMIT_NOFILE");
return FALSE;
#endif
}
static void static void
meta_context_get_property (GObject *object, meta_context_get_property (GObject *object,
guint prop_id, guint prop_id,
@ -618,6 +724,7 @@ static void
meta_context_init (MetaContext *context) meta_context_init (MetaContext *context)
{ {
MetaContextPrivate *priv = meta_context_get_instance_private (context); MetaContextPrivate *priv = meta_context_get_instance_private (context);
g_autoptr (GError) error = NULL;
priv->plugin_gtype = G_TYPE_NONE; priv->plugin_gtype = G_TYPE_NONE;
priv->gnome_wm_keybindings = g_strdup ("Mutter"); priv->gnome_wm_keybindings = g_strdup ("Mutter");
@ -631,4 +738,10 @@ meta_context_init (MetaContext *context)
g_option_context_set_main_group (priv->option_context, g_option_context_set_main_group (priv->option_context,
g_option_group_new (NULL, NULL, NULL, g_option_group_new (NULL, NULL, NULL,
context, NULL)); context, NULL));
if (!meta_context_save_rlimit_nofile (context, &error))
{
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOSYS))
g_warning ("Failed to save the nofile limit: %s", error->message);
}
} }

View File

@ -98,4 +98,12 @@ MetaBackend * meta_context_get_backend (MetaContext *context);
META_EXPORT META_EXPORT
MetaDisplay * meta_context_get_display (MetaContext *context); MetaDisplay * meta_context_get_display (MetaContext *context);
META_EXPORT
gboolean meta_context_raise_rlimit_nofile (MetaContext *context,
GError **error);
META_EXPORT
gboolean meta_context_restore_rlimit_nofile (MetaContext *context,
GError **error);
#endif /* META_CONTEXT_H */ #endif /* META_CONTEXT_H */