root/lib/vfs/gc.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. timeoutcmp
  2. vfs_stamp_compare
  3. vfs_addstamp
  4. vfs_stamp
  5. vfs_rmstamp
  6. vfs_stamp_path
  7. vfs_stamp_create
  8. vfs_expire
  9. vfs_timeouts
  10. vfs_timeout_handler
  11. vfs_release_path
  12. vfs_gc_done

   1 /*
   2    Virtual File System garbage collection code
   3 
   4    Copyright (C) 2003-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Miguel de Icaza, 1995
   9    Jakub Jelinek, 1995
  10    Pavel Machek, 1998
  11    Pavel Roskin, 2003
  12 
  13    This file is part of the Midnight Commander.
  14 
  15    The Midnight Commander is free software: you can redistribute it
  16    and/or modify it under the terms of the GNU General Public License as
  17    published by the Free Software Foundation, either version 3 of the License,
  18    or (at your option) any later version.
  19 
  20    The Midnight Commander is distributed in the hope that it will be useful,
  21    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23    GNU General Public License for more details.
  24 
  25    You should have received a copy of the GNU General Public License
  26    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  27  */
  28 
  29 /**
  30  * \file
  31  * \brief Source: Virtual File System: garbage collection code
  32  * \author Miguel de Icaza
  33  * \author Jakub Jelinek
  34  * \author Pavel Machek
  35  * \author Pavel Roskin
  36  * \date 1995, 1998, 2003
  37  */
  38 
  39 
  40 #include <config.h>
  41 
  42 #include <stdlib.h>             /* For atol() */
  43 #include <sys/types.h>
  44 #include <sys/time.h>           /* gettimeofday() */
  45 
  46 #include "lib/global.h"
  47 #include "lib/event.h"
  48 #include "lib/util.h"           /* MC_PTR_FREE */
  49 
  50 #include "vfs.h"
  51 #include "utilvfs.h"
  52 
  53 #include "gc.h"
  54 
  55 /*
  56  * The garbage collection mechanism is based on "stamps".
  57  *
  58  * A stamp is a record that says "I'm a filesystem which is no longer in
  59  * use. Free me when you get a chance."
  60  *
  61  * This file contains a set of functions used for managing this stamp. You
  62  * should use them when you write your own filesystem. Here are some rules
  63  * of thumb:
  64  *
  65  * (1) When the last open file in your filesystem gets closed, conditionally
  66  *     create a stamp. You do this with vfs_stamp_create(). (The meaning
  67  *     of "conditionaly" is explained below.)
  68  *
  69  * (2) When a file in your filesystem is opened, delete the stamp. You do
  70  *     this with vfs_rmstamp().
  71  *
  72  * (3) When a path inside your filesystem is invoked, call vfs_stamp() to
  73  *     postpone the free'ing of your filesystem a bit. (This simply updates
  74  *     a timestamp variable inside the stamp.)
  75  *
  76  * Additionally, when a user navigates to a new directory in a panel (or a
  77  * programmer uses mc_chdir()), a stamp is conditionally created for the
  78  * previous directory's filesystem. This ensures that that filesystem is
  79  * free'ed. (see: _do_panel_cd() -> vfs_release_path(); mc_chdir()).
  80  *
  81  * We've spoken here of "conditionally creating" a stamp. What we mean is
  82  * that vfs_stamp_create() is to be used: this function creates a stamp
  83  * only if no directories are open (aka "active") in your filesystem. (If
  84  * there _are_ directories open, it means that the filesystem is in use, in
  85  * which case we don't want to free it.)
  86  */
  87 
  88 /*** global variables ****************************************************************************/
  89 
  90 int vfs_timeout = 60;           /* VFS timeout in seconds */
  91 
  92 /*** file scope macro definitions ****************************************************************/
  93 
  94 #define VFS_STAMPING(a) ((struct vfs_stamping *)(a))
  95 
  96 /*** file scope type declarations ****************************************************************/
  97 
  98 struct vfs_stamping
  99 {
 100     struct vfs_class *v;
 101     vfsid id;
 102     struct timeval time;
 103 };
 104 
 105 /*** file scope variables ************************************************************************/
 106 
 107 static GSList *stamps = NULL;
 108 
 109 /* --------------------------------------------------------------------------------------------- */
 110 /*** file scope functions ************************************************************************/
 111 /* --------------------------------------------------------------------------------------------- */
 112 
 113 /** Compare two timeval structures. Return TRUE if t1 is less than t2. */
 114 
 115 static gboolean
 116 timeoutcmp (const struct timeval *t1, const struct timeval *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 117 {
 118     return ((t1->tv_sec < t2->tv_sec)
 119             || ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec <= t2->tv_usec)));
 120 }
 121 
 122 /* --------------------------------------------------------------------------------------------- */
 123 
 124 static gint
 125 vfs_stamp_compare (gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 126 {
 127     const struct vfs_stamping *vsa = (const struct vfs_stamping *) a;
 128     const struct vfs_stamping *vsb = (const struct vfs_stamping *) b;
 129 
 130     return (vsa->v == vsb->v && vsa->id == vsb->id) ? 0 : 1;
 131 }
 132 
 133 /* --------------------------------------------------------------------------------------------- */
 134 
 135 static void
 136 vfs_addstamp (struct vfs_class *v, vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 137 {
 138     if ((v->flags & VFS_LOCAL) == 0 && id != NULL && !vfs_stamp (v, id))
 139     {
 140         struct vfs_stamping *stamp;
 141 
 142         stamp = g_new (struct vfs_stamping, 1);
 143         stamp->v = v;
 144         stamp->id = id;
 145         gettimeofday (&(stamp->time), NULL);
 146 
 147         stamps = g_slist_append (stamps, stamp);
 148     }
 149 }
 150 
 151 /* --------------------------------------------------------------------------------------------- */
 152 /*** public functions ****************************************************************************/
 153 /* --------------------------------------------------------------------------------------------- */
 154 
 155 gboolean
 156 vfs_stamp (struct vfs_class *v, vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 157 {
 158     struct vfs_stamping what = {
 159         .v = v,
 160         .id = id
 161     };
 162     GSList *stamp;
 163     gboolean ret = FALSE;
 164 
 165     stamp = g_slist_find_custom (stamps, &what, vfs_stamp_compare);
 166     if (stamp != NULL)
 167     {
 168         gettimeofday (&(VFS_STAMPING (stamp->data)->time), NULL);
 169         ret = TRUE;
 170     }
 171 
 172     return ret;
 173 }
 174 
 175 /* --------------------------------------------------------------------------------------------- */
 176 
 177 void
 178 vfs_rmstamp (struct vfs_class *v, vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 179 {
 180     struct vfs_stamping what = {
 181         .v = v,
 182         .id = id
 183     };
 184     GSList *stamp;
 185 
 186     stamp = g_slist_find_custom (stamps, &what, vfs_stamp_compare);
 187     if (stamp != NULL)
 188     {
 189         g_free (stamp->data);
 190         stamps = g_slist_delete_link (stamps, stamp);
 191     }
 192 }
 193 
 194 /* --------------------------------------------------------------------------------------------- */
 195 
 196 void
 197 vfs_stamp_path (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 198 {
 199     vfsid id;
 200     const vfs_path_element_t *path_element;
 201 
 202     path_element = vfs_path_get_by_index (vpath, -1);
 203 
 204     id = vfs_getid (vpath);
 205     vfs_addstamp (path_element->class, id);
 206 }
 207 
 208 /* --------------------------------------------------------------------------------------------- */
 209 /**
 210  * Create a new timestamp item by VFS class and VFS id.
 211  */
 212 
 213 void
 214 vfs_stamp_create (struct vfs_class *vclass, vfsid id)
     /* [previous][next][first][last][top][bottom][index][help]  */
 215 {
 216     vfsid nvfsid;
 217 
 218     ev_vfs_stamp_create_t event_data = { vclass, id, FALSE };
 219     const vfs_path_t *vpath;
 220     const vfs_path_element_t *path_element;
 221 
 222     /* There are three directories we have to take care of: current_dir,
 223        current_panel->cwd and other_panel->cwd. Athough most of the time either
 224        current_dir and current_panel->cwd or current_dir and other_panel->cwd are the
 225        same, it's possible that all three are different -- Norbert */
 226 
 227     if (!mc_event_present (MCEVENT_GROUP_CORE, "vfs_timestamp"))
 228         return;
 229 
 230     vpath = vfs_get_raw_current_dir ();
 231     path_element = vfs_path_get_by_index (vpath, -1);
 232 
 233     nvfsid = vfs_getid (vpath);
 234     vfs_rmstamp (path_element->class, nvfsid);
 235 
 236     if (!(id == NULL || (path_element->class == vclass && nvfsid == id)))
 237     {
 238         mc_event_raise (MCEVENT_GROUP_CORE, "vfs_timestamp", (gpointer) & event_data);
 239 
 240         if (!event_data.ret && vclass != NULL && vclass->nothingisopen != NULL
 241             && vclass->nothingisopen (id))
 242             vfs_addstamp (vclass, id);
 243     }
 244 }
 245 
 246 /* --------------------------------------------------------------------------------------------- */
 247 /** This is called from timeout handler with now = FALSE,
 248     or can be called with now = TRUE to force freeing all filesystems */
 249 
 250 void
 251 vfs_expire (gboolean now)
     /* [previous][next][first][last][top][bottom][index][help]  */
 252 {
 253     static gboolean locked = FALSE;
 254     struct timeval curr_time, exp_time;
 255     GSList *stamp;
 256 
 257     /* Avoid recursive invocation, e.g. when one of the free functions
 258        calls message */
 259     if (locked)
 260         return;
 261     locked = TRUE;
 262 
 263     gettimeofday (&curr_time, NULL);
 264     exp_time.tv_sec = curr_time.tv_sec - vfs_timeout;
 265     exp_time.tv_usec = curr_time.tv_usec;
 266 
 267     if (now)
 268     {
 269         /* reverse list to free nested VFSes at first */
 270         stamps = g_slist_reverse (stamps);
 271     }
 272 
 273     /* NULLize stamps that point to expired VFS */
 274     for (stamp = stamps; stamp != NULL; stamp = g_slist_next (stamp))
 275     {
 276         struct vfs_stamping *stamping = VFS_STAMPING (stamp->data);
 277 
 278         if (now)
 279         {
 280             /* free VFS forced */
 281             if (stamping->v->free != NULL)
 282                 stamping->v->free (stamping->id);
 283             MC_PTR_FREE (stamp->data);
 284         }
 285         else if (timeoutcmp (&stamping->time, &exp_time))
 286         {
 287             /* update timestamp of VFS that is in use, or free unused VFS */
 288             if (stamping->v->nothingisopen != NULL && !stamping->v->nothingisopen (stamping->id))
 289                 stamping->time = curr_time;
 290             else
 291             {
 292                 if (stamping->v->free != NULL)
 293                     stamping->v->free (stamping->id);
 294                 MC_PTR_FREE (stamp->data);
 295             }
 296         }
 297     }
 298 
 299     /* then remove NULLized stamps */
 300     stamps = g_slist_remove_all (stamps, NULL);
 301 
 302     locked = FALSE;
 303 }
 304 
 305 /* --------------------------------------------------------------------------------------------- */
 306 /*
 307  * Return the number of seconds remaining to the vfs timeout.
 308  * FIXME: The code should be improved to actually return the number of
 309  * seconds until the next item times out.
 310  */
 311 
 312 int
 313 vfs_timeouts (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 314 {
 315     return stamps != NULL ? 10 : 0;
 316 }
 317 
 318 /* --------------------------------------------------------------------------------------------- */
 319 
 320 void
 321 vfs_timeout_handler (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 322 {
 323     vfs_expire (FALSE);
 324 }
 325 
 326 /* --------------------------------------------------------------------------------------------- */
 327 
 328 void
 329 vfs_release_path (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 330 {
 331     const vfs_path_element_t *path_element;
 332 
 333     path_element = vfs_path_get_by_index (vpath, -1);
 334     vfs_stamp_create (path_element->class, vfs_getid (vpath));
 335 }
 336 
 337 /* --------------------------------------------------------------------------------------------- */
 338 /* Free all data */
 339 
 340 void
 341 vfs_gc_done (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 342 {
 343     vfs_expire (TRUE);
 344 }
 345 
 346 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */