LCOV - code coverage report
Current view: top level - gio - gmemorymonitorbase.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 87.5 % 48 42
Test Date: 2026-02-03 14:41:24 Functions: 92.9 % 14 13
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 "ginitable.h"
      25                 :             : #include "gioerror.h"
      26                 :             : #include "giomodule-priv.h"
      27                 :             : #include "glib/gstdio.h"
      28                 :             : #include "glibintl.h"
      29                 :             : #include "gmemorymonitor.h"
      30                 :             : #include "gmemorymonitorbase.h"
      31                 :             : 
      32                 :             : #ifdef HAVE_SYSINFO
      33                 :             : #include <sys/sysinfo.h>
      34                 :             : #elif defined(HAVE_UNISTD_H)
      35                 :             : #include <unistd.h>
      36                 :             : #endif
      37                 :             : 
      38                 :             : /**
      39                 :             :  * GMemoryMonitorBase:
      40                 :             :  *
      41                 :             :  * An abstract base class for implementations of [iface@Gio.MemoryMonitor] which
      42                 :             :  * provides several defined warning levels (`GLowMemoryLevel`) and tracks how
      43                 :             :  * often they are notified to the user via [signal@Gio.MemoryMonitor::low-memory-warning]
      44                 :             :  * to limit the number of signal emissions to one every 15 seconds for each level.
      45                 :             :  * [method@Gio.MemoryMonitorBase.send_event_to_user] is provided for this purpose.
      46                 :             :  */
      47                 :             : 
      48                 :             : /* The interval between sending a signal in second */
      49                 :             : #define RECOVERY_INTERVAL_SEC 15
      50                 :             : 
      51                 :             : #define G_MEMORY_MONITOR_BASE_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
      52                 :             : 
      53                 :             : static void g_memory_monitor_base_iface_init (GMemoryMonitorInterface *iface);
      54                 :             : static void g_memory_monitor_base_initable_iface_init (GInitableIface *iface);
      55                 :             : 
      56                 :             : typedef struct
      57                 :             : {
      58                 :             :   GObject parent_instance;
      59                 :             : 
      60                 :             :   guint64 last_trigger_us[G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_COUNT];
      61                 :             : } GMemoryMonitorBasePrivate;
      62                 :             : 
      63                 :             : 
      64                 :         433 : G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GMemoryMonitorBase, g_memory_monitor_base, G_TYPE_OBJECT,
      65                 :             :                                   G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
      66                 :             :                                     g_memory_monitor_base_initable_iface_init)
      67                 :             :                                   G_IMPLEMENT_INTERFACE (G_TYPE_MEMORY_MONITOR,
      68                 :             :                                       g_memory_monitor_base_iface_init)
      69                 :             :                                   G_ADD_PRIVATE (GMemoryMonitorBase))
      70                 :             : 
      71                 :             : gdouble
      72                 :           6 : g_memory_monitor_base_query_mem_ratio (void)
      73                 :             : {
      74                 :             : #ifdef HAVE_SYSINFO
      75                 :             :   struct sysinfo info;
      76                 :             : 
      77                 :           6 :   if (sysinfo (&info))
      78                 :           0 :     return -1.0;
      79                 :             : 
      80                 :           6 :   if (info.totalram == 0)
      81                 :           0 :     return -1.0;
      82                 :             : 
      83                 :           6 :   return (gdouble) ((gdouble) info.freeram / (gdouble) info.totalram);
      84                 :             : #elif defined(_SC_PHYS_PAGES) && defined(_SC_AVPHYS_PAGES)
      85                 :             :   /* Implementation for Solaris, where sysinfo() does not return RAM usage information */
      86                 :             :   long totalram = sysconf (_SC_PHYS_PAGES);
      87                 :             :   long freeram = sysconf (_SC_AVPHYS_PAGES);
      88                 :             : 
      89                 :             :   if (totalram <= 0 || freeram < 0)
      90                 :             :     return -1.0;
      91                 :             : 
      92                 :             :   return (gdouble) ((gdouble) freeram / (gdouble) totalram);
      93                 :             : #else
      94                 :             :   return -1.0;
      95                 :             : #endif
      96                 :             : }
      97                 :             : 
      98                 :             : GMemoryMonitorWarningLevel
      99                 :           6 : g_memory_monitor_base_level_enum_to_byte (GMemoryMonitorLowMemoryLevel level)
     100                 :             : {
     101                 :           6 :   const GMemoryMonitorWarningLevel level_bytes[G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_COUNT] = {
     102                 :             :     [G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_LOW] = 50,
     103                 :             :     [G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_MEDIUM] = 100,
     104                 :             :     [G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_CRITICAL] = 255
     105                 :             :   };
     106                 :             : 
     107                 :           6 :   if ((int) level < G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_INVALID ||
     108                 :             :       (int) level >= G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_COUNT)
     109                 :             :     g_assert_not_reached ();
     110                 :             : 
     111                 :           6 :   if (level == G_MEMORY_MONITOR_LOW_MEMORY_LEVEL_INVALID)
     112                 :           0 :     return 0;
     113                 :             : 
     114                 :           6 :   return level_bytes[level];
     115                 :             : }
     116                 :             : 
     117                 :             : typedef struct
     118                 :             : {
     119                 :             :   GWeakRef monitor_weak;
     120                 :             :   GMemoryMonitorWarningLevel level;
     121                 :             : } SendEventData;
     122                 :             : 
     123                 :             : static void
     124                 :           5 : send_event_data_free (SendEventData *data)
     125                 :             : {
     126                 :           5 :   g_weak_ref_clear (&data->monitor_weak);
     127                 :           5 :   g_free (data);
     128                 :           5 : }
     129                 :             : 
     130                 :             : /* Invoked in the global default main context */
     131                 :             : static gboolean
     132                 :           5 : send_event_cb (void *user_data)
     133                 :             : {
     134                 :           5 :   SendEventData *data = user_data;
     135                 :           5 :   GMemoryMonitor *monitor = g_weak_ref_get (&data->monitor_weak);
     136                 :             : 
     137                 :           5 :   if (monitor != NULL)
     138                 :           5 :     g_signal_emit_by_name (monitor, "low-memory-warning", data->level);
     139                 :             : 
     140                 :           5 :   g_clear_object (&monitor);
     141                 :             : 
     142                 :           5 :   return G_SOURCE_REMOVE;
     143                 :             : }
     144                 :             : 
     145                 :             : void
     146                 :           6 : g_memory_monitor_base_send_event_to_user (GMemoryMonitorBase              *monitor,
     147                 :             :                                           GMemoryMonitorLowMemoryLevel     warning_level)
     148                 :             : {
     149                 :             :   gint64 current_time;
     150                 :           6 :   GMemoryMonitorBasePrivate *priv = g_memory_monitor_base_get_instance_private (monitor);
     151                 :             : 
     152                 :           6 :   current_time = g_get_monotonic_time ();
     153                 :             : 
     154                 :           6 :   if (priv->last_trigger_us[warning_level] == 0 ||
     155                 :           0 :       (current_time - priv->last_trigger_us[warning_level]) > (RECOVERY_INTERVAL_SEC * G_USEC_PER_SEC))
     156                 :             :     {
     157                 :           6 :       SendEventData *data = NULL;
     158                 :             : 
     159                 :           6 :       g_debug ("Send low memory signal with warning level %u", warning_level);
     160                 :             : 
     161                 :             :       /* The signal has to be emitted in the global default main context,
     162                 :             :        * because the `GMemoryMonitor` is a singleton which may have been created
     163                 :             :        * in an arbitrary thread, or which may be calling this function from the
     164                 :             :        * GLib worker thread. */
     165                 :           6 :       data = g_new0 (SendEventData, 1);
     166                 :           6 :       g_weak_ref_init (&data->monitor_weak, monitor);
     167                 :           6 :       data->level = g_memory_monitor_base_level_enum_to_byte (warning_level);
     168                 :           6 :       g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT, send_event_cb,
     169                 :             :                                   g_steal_pointer (&data), (GDestroyNotify) send_event_data_free);
     170                 :           6 :       priv->last_trigger_us[warning_level] = current_time;
     171                 :             :     }
     172                 :           6 : }
     173                 :             : 
     174                 :             : static gboolean
     175                 :           0 : g_memory_monitor_base_initable_init (GInitable     *initable,
     176                 :             :                                         GCancellable  *cancellable,
     177                 :             :                                         GError       **error)
     178                 :             : {
     179                 :           0 :   return TRUE;
     180                 :             : }
     181                 :             : 
     182                 :             : static void
     183                 :           5 : g_memory_monitor_base_init (GMemoryMonitorBase *monitor)
     184                 :             : {
     185                 :           5 : }
     186                 :             : 
     187                 :             : static void
     188                 :           2 : g_memory_monitor_base_class_init (GMemoryMonitorBaseClass *klass)
     189                 :             : {
     190                 :           2 : }
     191                 :             : 
     192                 :             : static void
     193                 :           2 : g_memory_monitor_base_iface_init (GMemoryMonitorInterface *monitor_iface)
     194                 :             : {
     195                 :           2 : }
     196                 :             : 
     197                 :             : static void
     198                 :           2 : g_memory_monitor_base_initable_iface_init (GInitableIface *iface)
     199                 :             : {
     200                 :           2 :   iface->init = g_memory_monitor_base_initable_init;
     201                 :           2 : }
        

Generated by: LCOV version 2.0-1