LCOV - code coverage report
Current view: top level - gio - gmemorymonitorpsi.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 67.7 % 164 111
Test Date: 2026-02-03 14:41:24 Functions: 94.7 % 19 18
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GIO - GLib Input, Output and Streaming Library
       2                 :             :  *
       3                 :             :  * Copyright 2025 Red Hat, Inc.
       4                 :             :  *
       5                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       6                 :             :  *
       7                 :             :  * This library is free software; you can redistribute it and/or
       8                 :             :  * modify it under the terms of the GNU Lesser General Public
       9                 :             :  * License as published by the Free Software Foundation; either
      10                 :             :  * version 2.1 of the License, or (at your option) any later version.
      11                 :             :  *
      12                 :             :  * This library is distributed in the hope that it will be useful,
      13                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :             :  * Lesser General Public License for more details.
      16                 :             :  *
      17                 :             :  * You should have received a copy of the GNU Lesser General
      18                 :             :  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19                 :             :  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : 
      23                 :             : #include "gcancellable.h"
      24                 :             : #include "gdbusnamewatching.h"
      25                 :             : #include "gdbusproxy.h"
      26                 :             : #include "ginitable.h"
      27                 :             : #include "gioerror.h"
      28                 :             : #include "giomodule-priv.h"
      29                 :             : #include "glibintl.h"
      30                 :             : #include "glib/glib-private.h"
      31                 :             : #include "glib/gstdio.h"
      32                 :             : #include "gmemorymonitor.h"
      33                 :             : #include "gmemorymonitorbase.h"
      34                 :             : #include "gmemorymonitorpsi.h"
      35                 :             : 
      36                 :             : #include <errno.h>
      37                 :             : #include <fcntl.h>
      38                 :             : #include <unistd.h>
      39                 :             : 
      40                 :             : /**
      41                 :             :  * GMemoryMonitorPsi:
      42                 :             :  *
      43                 :             :  * A Linux [iface@Gio.MemoryMonitor] which uses the kernel
      44                 :             :  * [pressure stall information](https://www.kernel.org/doc/html/latest/accounting/psi.html) (PSI).
      45                 :             :  *
      46                 :             :  * When it receives a PSI event, it emits
      47                 :             :  * [signal@Gio.MemoryMonitor::low-memory-warning] with an appropriate warning
      48                 :             :  * level.
      49                 :             :  *
      50                 :             :  * Since: 2.86
      51                 :             :  */
      52                 :             : 
      53                 :             : /* Unprivileged users can also create monitors, with
      54                 :             :  * the only limitation that the window size must be a
      55                 :             :  * `multiple of 2s`, in order to prevent excessive resource usage.
      56                 :             :  * see: https://www.kernel.org/doc/html/latest/accounting/psi.html*/
      57                 :             : #define PSI_WINDOW_SEC 2
      58                 :             : 
      59                 :             : typedef enum {
      60                 :             :   PROP_PROC_PATH = 1,
      61                 :             : } GMemoryMonitorPsiProperty;
      62                 :             : 
      63                 :             : typedef enum
      64                 :             : {
      65                 :             :   MEMORY_PRESSURE_MONITOR_TRIGGER_SOME,
      66                 :             :   MEMORY_PRESSURE_MONITOR_TRIGGER_FULL,
      67                 :             :   MEMORY_PRESSURE_MONITOR_TRIGGER_MFD
      68                 :             : } MemoryPressureMonitorTriggerType;
      69                 :             : 
      70                 :             : /* Each trigger here results in an open fd for the lifetime
      71                 :             :  * of the `GMemoryMonitor`, so don’t add too many */
      72                 :             : static const struct
      73                 :             : {
      74                 :             :   MemoryPressureMonitorTriggerType trigger_type;
      75                 :             :   int threshold_ms;
      76                 :             : } triggers[G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_COUNT] = {
      77                 :             :   { MEMORY_PRESSURE_MONITOR_TRIGGER_SOME, 70 },  /* 70ms out of 2sec for partial stall */
      78                 :             :   { MEMORY_PRESSURE_MONITOR_TRIGGER_SOME, 100 }, /* 100ms out of 2sec for partial stall */
      79                 :             :   { MEMORY_PRESSURE_MONITOR_TRIGGER_FULL, 100 }, /* 100ms out of 2sec for complete stall */
      80                 :             : };
      81                 :             : 
      82                 :             : typedef struct
      83                 :             : {
      84                 :             :   GSource source;
      85                 :             :   GPollFD *pollfd;
      86                 :             :   GMemoryMonitorLowMemoryLevel level_type;
      87                 :             :   GWeakRef monitor_weak;
      88                 :             : } MemoryMonitorSource;
      89                 :             : 
      90                 :             : typedef gboolean (*MemoryMonitorCallbackFunc) (GMemoryMonitorPsi            *monitor,
      91                 :             :                                                GMemoryMonitorLowMemoryLevel  level_type,
      92                 :             :                                                void                         *user_data);
      93                 :             : 
      94                 :             : #define G_MEMORY_MONITOR_PSI_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
      95                 :             : 
      96                 :             : static void g_memory_monitor_psi_iface_init (GMemoryMonitorInterface *iface);
      97                 :             : static void g_memory_monitor_psi_initable_iface_init (GInitableIface *iface);
      98                 :             : 
      99                 :             : struct _GMemoryMonitorPsi
     100                 :             : {
     101                 :             :   GMemoryMonitorBase parent_instance;
     102                 :             :   GMainContext *worker;  /* (unowned) */
     103                 :             :   GSource *triggers[G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_COUNT];  /* (owned) (nullable) */
     104                 :             : 
     105                 :             :   char *cg_path;
     106                 :             :   char *proc_path;
     107                 :             : 
     108                 :             :   gboolean proc_override;
     109                 :             : };
     110                 :             : 
     111                 :         284 : G_DEFINE_TYPE_WITH_CODE (GMemoryMonitorPsi, g_memory_monitor_psi, G_TYPE_MEMORY_MONITOR_BASE,
     112                 :             :                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
     113                 :             :                                                 g_memory_monitor_psi_initable_iface_init)
     114                 :             :                          G_IMPLEMENT_INTERFACE (G_TYPE_MEMORY_MONITOR,
     115                 :             :                                                 g_memory_monitor_psi_iface_init)
     116                 :             :                          _g_io_modules_ensure_extension_points_registered ();
     117                 :             :                          g_io_extension_point_implement (G_MEMORY_MONITOR_EXTENSION_POINT_NAME,
     118                 :             :                                                          g_define_type_id,
     119                 :             :                                                          "psi",
     120                 :             :                                                          20))
     121                 :             : 
     122                 :             : static void
     123                 :           1 : g_memory_monitor_psi_init (GMemoryMonitorPsi *psi)
     124                 :             : {
     125                 :           1 : }
     126                 :             : 
     127                 :             : static void
     128                 :           1 : g_memory_monitor_psi_set_property (GObject      *object,
     129                 :             :                                     guint         prop_id,
     130                 :             :                                     const GValue *value,
     131                 :             :                                     GParamSpec   *pspec)
     132                 :             : {
     133                 :           1 :   GMemoryMonitorPsi *monitor = G_MEMORY_MONITOR_PSI (object);
     134                 :             : 
     135                 :           1 :   switch ((GMemoryMonitorPsiProperty) prop_id)
     136                 :             :     {
     137                 :           1 :     case PROP_PROC_PATH:
     138                 :             :       /* Construct only */
     139                 :           1 :       g_assert (monitor->proc_path == NULL);
     140                 :           1 :       monitor->proc_path = g_value_dup_string (value);
     141                 :           1 :       if (monitor->proc_path != NULL)
     142                 :           1 :         monitor->proc_override = TRUE;
     143                 :           1 :       break;
     144                 :           0 :     default:
     145                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     146                 :           0 :       break;
     147                 :             :     }
     148                 :           1 : }
     149                 :             : 
     150                 :             : static void
     151                 :           0 : g_memory_monitor_psi_get_property (GObject    *object,
     152                 :             :                                    guint       prop_id,
     153                 :             :                                    GValue     *value,
     154                 :             :                                    GParamSpec *pspec)
     155                 :             : {
     156                 :           0 :   GMemoryMonitorPsi *monitor = G_MEMORY_MONITOR_PSI (object);
     157                 :             : 
     158                 :           0 :   switch ((GMemoryMonitorPsiProperty) prop_id)
     159                 :             :     {
     160                 :           0 :     case PROP_PROC_PATH:
     161                 :           0 :       g_value_set_string (value, monitor->proc_override ? monitor->proc_path : NULL);
     162                 :           0 :       break;
     163                 :           0 :     default:
     164                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     165                 :           0 :       break;
     166                 :             :     }
     167                 :           0 : }
     168                 :             : 
     169                 :             : static gboolean
     170                 :           3 : g_memory_monitor_low_trigger_cb (GMemoryMonitorPsi            *monitor,
     171                 :             :                                  GMemoryMonitorLowMemoryLevel  level_type,
     172                 :             :                                  void                         *user_data)
     173                 :             : {
     174                 :             :   gdouble mem_ratio;
     175                 :             : 
     176                 :             :   /* Should be executed in the worker context */
     177                 :           3 :   g_assert (g_main_context_is_owner (monitor->worker));
     178                 :             : 
     179                 :           3 :   mem_ratio = g_memory_monitor_base_query_mem_ratio ();
     180                 :             : 
     181                 :             :   /* if the test is running, skip memory ratio test */
     182                 :           3 :   if (!monitor->proc_override)
     183                 :             :     {
     184                 :             :       /* if mem free ratio > 0.5, don't signal */
     185                 :           0 :       if (mem_ratio < 0.0)
     186                 :           0 :         return G_SOURCE_REMOVE;
     187                 :           0 :       if (mem_ratio > 0.5)
     188                 :           0 :         return G_SOURCE_CONTINUE;
     189                 :             :     }
     190                 :             : 
     191                 :           3 :   g_memory_monitor_base_send_event_to_user (G_MEMORY_MONITOR_BASE (monitor), level_type);
     192                 :             : 
     193                 :           3 :   return G_SOURCE_CONTINUE;
     194                 :             : }
     195                 :             : 
     196                 :             : static gboolean
     197                 :           3 : event_check (GSource *source)
     198                 :             : {
     199                 :           3 :   MemoryMonitorSource *ev_source = (MemoryMonitorSource *) source;
     200                 :             : 
     201                 :           3 :   if (ev_source->pollfd->revents)
     202                 :           3 :     return G_SOURCE_CONTINUE;
     203                 :             : 
     204                 :           0 :   return G_SOURCE_REMOVE;
     205                 :             : }
     206                 :             : 
     207                 :             : static gboolean
     208                 :           3 : event_dispatch (GSource     *source,
     209                 :             :                 GSourceFunc  callback,
     210                 :             :                 gpointer     user_data)
     211                 :             : {
     212                 :           3 :   MemoryMonitorSource *ev_source = (MemoryMonitorSource *) source;
     213                 :           3 :   GMemoryMonitorPsi *monitor = NULL;
     214                 :             : 
     215                 :           3 :   monitor = g_weak_ref_get (&ev_source->monitor_weak);
     216                 :           3 :   if (monitor == NULL)
     217                 :           0 :     return G_SOURCE_REMOVE;
     218                 :             : 
     219                 :           3 :   if (monitor->proc_override)
     220                 :             :     {
     221                 :           3 :       if (!(g_source_query_unix_fd (source, ev_source->pollfd) & G_IO_IN))
     222                 :             :         {
     223                 :           0 :           g_object_unref (monitor);
     224                 :           0 :           return G_SOURCE_CONTINUE;
     225                 :             :         }
     226                 :             :     }
     227                 :             :   else
     228                 :             :     {
     229                 :           0 :       if (!(g_source_query_unix_fd (source, ev_source->pollfd) & G_IO_PRI))
     230                 :             :         {
     231                 :           0 :           g_object_unref (monitor);
     232                 :           0 :           return G_SOURCE_CONTINUE;
     233                 :             :         }
     234                 :             :     }
     235                 :             : 
     236                 :           3 :   if (callback)
     237                 :           3 :     ((MemoryMonitorCallbackFunc) callback) (monitor, ev_source->level_type, user_data);
     238                 :             : 
     239                 :           3 :   g_object_unref (monitor);
     240                 :             : 
     241                 :           3 :   return G_SOURCE_CONTINUE;
     242                 :             : }
     243                 :             : 
     244                 :             : static void
     245                 :           3 : event_finalize (GSource *source)
     246                 :             : {
     247                 :           3 :   MemoryMonitorSource *ev_source = (MemoryMonitorSource *) source;
     248                 :             : 
     249                 :           3 :   g_weak_ref_clear (&ev_source->monitor_weak);
     250                 :           3 : }
     251                 :             : 
     252                 :             : static GSourceFuncs memory_monitor_event_funcs = {
     253                 :             :   .check = event_check,
     254                 :             :   .dispatch = event_dispatch,
     255                 :             :   .finalize = event_finalize,
     256                 :             : };
     257                 :             : 
     258                 :             : static GSource *
     259                 :           3 : g_memory_monitor_create_source (GMemoryMonitorPsi            *monitor,
     260                 :             :                                 int                           fd,
     261                 :             :                                 GMemoryMonitorLowMemoryLevel  level_type,
     262                 :             :                                 gboolean                      is_path_override)
     263                 :             : {
     264                 :             :   MemoryMonitorSource *source;
     265                 :             : 
     266                 :           3 :   source = (MemoryMonitorSource *) g_source_new (&memory_monitor_event_funcs, sizeof (MemoryMonitorSource));
     267                 :           3 :   if (is_path_override)
     268                 :           3 :     source->pollfd = g_source_add_unix_fd ((GSource *) source, fd, G_IO_IN | G_IO_ERR);
     269                 :             :   else
     270                 :           0 :     source->pollfd = g_source_add_unix_fd ((GSource *) source, fd, G_IO_PRI | G_IO_ERR);
     271                 :           3 :   source->level_type = level_type;
     272                 :           3 :   g_weak_ref_init (&source->monitor_weak, monitor);
     273                 :             : 
     274                 :           3 :   return (GSource *) source;
     275                 :             : }
     276                 :             : 
     277                 :             : static gboolean
     278                 :           1 : g_memory_monitor_psi_calculate_mem_pressure_path (GMemoryMonitorPsi  *monitor,
     279                 :             :                                                   GError            **error)
     280                 :             : {
     281                 :             :   pid_t pid;
     282                 :           1 :   gchar *path_read = NULL;
     283                 :           1 :   gchar *replacement = NULL;
     284                 :             : 
     285                 :           1 :   if (!monitor->proc_override)
     286                 :             :     {
     287                 :           0 :       pid = getpid ();
     288                 :           0 :       monitor->proc_path = g_strdup_printf ("/proc/%d/cgroup", pid);
     289                 :             :     }
     290                 :             : 
     291                 :           1 :   if (!g_file_get_contents (monitor->proc_path, &path_read, NULL, error))
     292                 :             :     {
     293                 :           0 :       g_free (path_read);
     294                 :           0 :       return FALSE;
     295                 :             :     }
     296                 :             : 
     297                 :             :   /* cgroupv2 is only supported and the format is shown as follows:
     298                 :             :    * ex: 0::/user.slice/user-0.slice/session-c3.scope */
     299                 :           1 :   if (!g_str_has_prefix (path_read, "0::"))
     300                 :             :     {
     301                 :           0 :       g_debug ("Unsupported cgroup path information.");
     302                 :           0 :       g_free (path_read);
     303                 :           0 :       return FALSE;
     304                 :             :     }
     305                 :             : 
     306                 :             :   /* drop "0::" */
     307                 :           1 :   replacement = g_strdup (path_read + strlen ("0::"));
     308                 :           1 :   g_free (path_read);
     309                 :           1 :   if (replacement == NULL)
     310                 :             :     {
     311                 :           0 :       g_debug ("Unsupported cgroup path format.");
     312                 :           0 :       return FALSE;
     313                 :             :     }
     314                 :             : 
     315                 :           1 :   replacement = g_strstrip (replacement);
     316                 :             : 
     317                 :           1 :   if (monitor->proc_override)
     318                 :             :     {
     319                 :           1 :       monitor->cg_path = g_steal_pointer (&replacement);
     320                 :           1 :       return TRUE;
     321                 :             :     }
     322                 :             : 
     323                 :           0 :   monitor->cg_path = g_build_filename ("/sys/fs/cgroup", replacement, "memory.pressure", NULL);
     324                 :           0 :   g_debug ("cgroup path is %s", monitor->cg_path);
     325                 :             : 
     326                 :           0 :   g_free (replacement);
     327                 :           0 :   return g_file_test (monitor->cg_path, G_FILE_TEST_EXISTS);
     328                 :             : }
     329                 :             : 
     330                 :             : static GSource *
     331                 :           3 : g_memory_monitor_psi_setup_trigger (GMemoryMonitorPsi             *monitor,
     332                 :             :                                     GMemoryMonitorLowMemoryLevel   level_type,
     333                 :             :                                     int                            threshold_us,
     334                 :             :                                     int                            window_us,
     335                 :             :                                     GError                       **error)
     336                 :             : {
     337                 :             :   GSource *source;
     338                 :             :   int fd;
     339                 :             :   int ret;
     340                 :             :   size_t wlen;
     341                 :           3 :   gchar *trigger = NULL;
     342                 :             : 
     343                 :           3 :   fd = g_open (monitor->cg_path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
     344                 :           3 :   if (fd < 0)
     345                 :             :     {
     346                 :           0 :       int errsv = errno;
     347                 :           0 :       g_debug ("Error on opening %s: %s", monitor->cg_path, g_strerror (errsv));
     348                 :           0 :       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
     349                 :             :                    "Error on opening ‘%s’: %s", monitor->cg_path, g_strerror (errsv));
     350                 :           0 :       return NULL;
     351                 :             :     }
     352                 :             : 
     353                 :             :   /* The kernel PSI [1] trigger format is:
     354                 :             :    * <some|full> <stall amount in us> <time window in us>
     355                 :             :    * The “some” indicates the share of time in which at least some tasks are stalled on a given resource.
     356                 :             :    * The “full” indicates the share of time in which all non-idle tasks are stalled on a given resource simultaneously.
     357                 :             :    * "stall amount in us": The total stall time in us.
     358                 :             :    * "time window in us": The specific time window in us.
     359                 :             :    * e.g. writing "some 150000 1000000" would add 150ms threshold for partial memory stall measured within 1sec time window
     360                 :             :    *
     361                 :             :    * [1] https://docs.kernel.org/accounting/psi.html
     362                 :             :    */
     363                 :           3 :   trigger = g_strdup_printf ("%s %d %d",
     364                 :           3 :                              (triggers[level_type].trigger_type == MEMORY_PRESSURE_MONITOR_TRIGGER_SOME) ? "some" : "full",
     365                 :             :                              threshold_us,
     366                 :             :                              window_us);
     367                 :             : 
     368                 :           3 :   errno = 0;
     369                 :           3 :   wlen = strlen (trigger) + 1;
     370                 :           6 :   while (wlen > 0)
     371                 :             :     {
     372                 :             :       int errsv;
     373                 :           3 :       g_debug ("Write trigger %s", trigger);
     374                 :           3 :       ret = write (fd, trigger, wlen);
     375                 :           3 :       errsv = errno;
     376                 :           3 :       if (ret < 0)
     377                 :             :         {
     378                 :           0 :           if (errsv == EINTR)
     379                 :             :             {
     380                 :             :               /* interrupted by signal, retry */
     381                 :           0 :               continue;
     382                 :             :             }
     383                 :             :           else
     384                 :             :             {
     385                 :           0 :               g_set_error (error,
     386                 :             :                            G_IO_ERROR, G_IO_ERROR_FAILED,
     387                 :             :                            "Error on setting PSI configurations: %s",
     388                 :             :                            g_strerror (errsv));
     389                 :           0 :               g_free (trigger);
     390                 :           0 :               close (fd);
     391                 :           0 :               return NULL;
     392                 :             :             }
     393                 :             :         }
     394                 :           3 :       wlen -= ret;
     395                 :             :     }
     396                 :           3 :   g_free (trigger);
     397                 :             : 
     398                 :           3 :   source = g_memory_monitor_create_source (monitor, fd, level_type, monitor->proc_override);
     399                 :           3 :   g_source_set_callback (source, G_SOURCE_FUNC (g_memory_monitor_low_trigger_cb), NULL, NULL);
     400                 :             : 
     401                 :           3 :   return g_steal_pointer (&source);
     402                 :             : }
     403                 :             : 
     404                 :             : static gboolean
     405                 :           1 : g_memory_monitor_setup_psi (GMemoryMonitorPsi  *monitor,
     406                 :             :                             GError            **error)
     407                 :             : {
     408                 :           1 :   if (!g_memory_monitor_psi_calculate_mem_pressure_path (monitor, error))
     409                 :           0 :     return FALSE;
     410                 :             : 
     411                 :           4 :   for (size_t i = 0; i < G_N_ELEMENTS (triggers); i++)
     412                 :             :     {
     413                 :             :       /* the user defined PSI is estimated per second and the unit is in micro second(us). */
     414                 :           6 :       monitor->triggers[i] = g_memory_monitor_psi_setup_trigger (monitor,
     415                 :             :                                                                  i,
     416                 :           3 :                                                                  triggers[i].threshold_ms * 1000,
     417                 :             :                                                                  PSI_WINDOW_SEC * 1000 * 1000,
     418                 :             :                                                                  error);
     419                 :           3 :       if (monitor->triggers[i] == NULL)
     420                 :           0 :         return FALSE;
     421                 :             :     }
     422                 :             : 
     423                 :           1 :   return TRUE;
     424                 :             : }
     425                 :             : 
     426                 :             : static gboolean
     427                 :           1 : g_memory_monitor_psi_initable_init (GInitable     *initable,
     428                 :             :                                     GCancellable  *cancellable,
     429                 :             :                                     GError       **error)
     430                 :             : {
     431                 :           1 :   GMemoryMonitorPsi *monitor = G_MEMORY_MONITOR_PSI (initable);
     432                 :             : 
     433                 :           1 :   monitor->worker = GLIB_PRIVATE_CALL (g_get_worker_context) ();
     434                 :             : 
     435                 :           1 :   if (g_memory_monitor_setup_psi (monitor, error))
     436                 :             :     {
     437                 :           4 :       for (size_t i = 0; i < G_N_ELEMENTS (monitor->triggers); i++)
     438                 :             :         {
     439                 :           3 :           g_source_attach (monitor->triggers[i], monitor->worker);
     440                 :             :         }
     441                 :             :     }
     442                 :             :   else
     443                 :             :     {
     444                 :           0 :       g_debug ("PSI is not supported.");
     445                 :           0 :       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "PSI is not supported.");
     446                 :           0 :       return FALSE;
     447                 :             :     }
     448                 :             : 
     449                 :           1 :   return TRUE;
     450                 :             : }
     451                 :             : 
     452                 :             : static void
     453                 :           1 : g_memory_monitor_psi_finalize (GObject *object)
     454                 :             : {
     455                 :           1 :   GMemoryMonitorPsi *monitor = G_MEMORY_MONITOR_PSI (object);
     456                 :             : 
     457                 :           1 :   g_free (monitor->cg_path);
     458                 :           1 :   g_free (monitor->proc_path);
     459                 :             : 
     460                 :           4 :   for (size_t i = 0; i < G_N_ELEMENTS (monitor->triggers); i++)
     461                 :             :     {
     462                 :           3 :       g_source_destroy (monitor->triggers[i]);
     463                 :           3 :       g_source_unref (monitor->triggers[i]);
     464                 :             :     }
     465                 :             : 
     466                 :           1 :   G_OBJECT_CLASS (g_memory_monitor_psi_parent_class)->finalize (object);
     467                 :           1 : }
     468                 :             : 
     469                 :             : static void
     470                 :           1 : g_memory_monitor_psi_class_init (GMemoryMonitorPsiClass *klass)
     471                 :             : {
     472                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     473                 :             : 
     474                 :           1 :   object_class->set_property = g_memory_monitor_psi_set_property;
     475                 :           1 :   object_class->get_property = g_memory_monitor_psi_get_property;
     476                 :           1 :   object_class->finalize = g_memory_monitor_psi_finalize;
     477                 :             : 
     478                 :             :   /**
     479                 :             :    * GMemoryMonitorPsi:proc-path: (nullable)
     480                 :             :    *
     481                 :             :    * Kernel PSI path to use, if not the default.
     482                 :             :    *
     483                 :             :    * This is typically only used for test purposes.
     484                 :             :    *
     485                 :             :    * Since: 2.86
     486                 :             :    */
     487                 :           1 :   g_object_class_install_property (object_class,
     488                 :             :                                    PROP_PROC_PATH,
     489                 :             :                                    g_param_spec_string ("proc-path", NULL, NULL,
     490                 :             :                                                         NULL,
     491                 :             :                                                         G_PARAM_READWRITE |
     492                 :             :                                                         G_PARAM_CONSTRUCT_ONLY |
     493                 :             :                                                         G_PARAM_STATIC_STRINGS));
     494                 :           1 : }
     495                 :             : 
     496                 :             : static void
     497                 :           1 : g_memory_monitor_psi_iface_init (GMemoryMonitorInterface *monitor_iface)
     498                 :             : {
     499                 :           1 : }
     500                 :             : 
     501                 :             : static void
     502                 :           1 : g_memory_monitor_psi_initable_iface_init (GInitableIface *iface)
     503                 :             : {
     504                 :           1 :   iface->init = g_memory_monitor_psi_initable_init;
     505                 :           1 : }
        

Generated by: LCOV version 2.0-1