2 Virtual File System garbage collection code
4 Copyright (C) 2003-2024
5 Free Software Foundation, Inc.
13 This file is part of the Midnight Commander.
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.
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.
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/>.
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
44 #include "lib/global.h"
45 #include "lib/event.h"
46 #include "lib/util.h" /* MC_PTR_FREE */
54 * The garbage collection mechanism is based on "stamps".
56 * A stamp is a record that says "I'm a filesystem which is no longer in
57 * use. Free me when you get a chance."
59 * This file contains a set of functions used for managing this stamp. You
60 * should use them when you write your own filesystem. Here are some rules
63 * (1) When the last open file in your filesystem gets closed, conditionally
64 * create a stamp. You do this with vfs_stamp_create(). (The meaning
65 * of "conditionally" is explained below.)
67 * (2) When a file in your filesystem is opened, delete the stamp. You do
68 * this with vfs_rmstamp().
70 * (3) When a path inside your filesystem is invoked, call vfs_stamp() to
71 * postpone the free'ing of your filesystem a bit. (This simply updates
72 * a timestamp variable inside the stamp.)
74 * Additionally, when a user navigates to a new directory in a panel (or a
75 * programmer uses mc_chdir()), a stamp is conditionally created for the
76 * previous directory's filesystem. This ensures that that filesystem is
77 * free'ed. (see: _do_panel_cd() -> vfs_release_path(); mc_chdir()).
79 * We've spoken here of "conditionally creating" a stamp. What we mean is
80 * that vfs_stamp_create() is to be used: this function creates a stamp
81 * only if no directories are open (aka "active") in your filesystem. (If
82 * there _are_ directories open, it means that the filesystem is in use, in
83 * which case we don't want to free it.)
86 /*** global variables ****************************************************************************/
88 int vfs_timeout
= 60; /* VFS timeout in seconds */
90 /*** file scope macro definitions ****************************************************************/
92 #define VFS_STAMPING(a) ((struct vfs_stamping *)(a))
94 /*** file scope type declarations ****************************************************************/
103 /*** forward declarations (file scope functions) *************************************************/
105 /*** file scope variables ************************************************************************/
107 static GSList
*stamps
= NULL
;
109 /* --------------------------------------------------------------------------------------------- */
110 /*** file scope functions ************************************************************************/
111 /* --------------------------------------------------------------------------------------------- */
114 vfs_stamp_compare (gconstpointer a
, gconstpointer b
)
116 const struct vfs_stamping
*vsa
= (const struct vfs_stamping
*) a
;
117 const struct vfs_stamping
*vsb
= (const struct vfs_stamping
*) b
;
119 return (vsa
== NULL
|| vsb
== NULL
|| (vsa
->v
== vsb
->v
&& vsa
->id
== vsb
->id
)) ? 0 : 1;
122 /* --------------------------------------------------------------------------------------------- */
125 vfs_addstamp (struct vfs_class
*v
, vfsid id
)
127 if ((v
->flags
& VFSF_LOCAL
) == 0 && id
!= NULL
&& !vfs_stamp (v
, id
))
129 struct vfs_stamping
*stamp
;
131 stamp
= g_new (struct vfs_stamping
, 1);
134 stamp
->time
= g_get_monotonic_time ();
136 stamps
= g_slist_append (stamps
, stamp
);
140 /* --------------------------------------------------------------------------------------------- */
141 /*** public functions ****************************************************************************/
142 /* --------------------------------------------------------------------------------------------- */
145 vfs_stamp (struct vfs_class
*v
, vfsid id
)
147 struct vfs_stamping what
= {
152 gboolean ret
= FALSE
;
154 stamp
= g_slist_find_custom (stamps
, &what
, vfs_stamp_compare
);
155 if (stamp
!= NULL
&& stamp
->data
!= NULL
)
157 VFS_STAMPING (stamp
->data
)->time
= g_get_monotonic_time ();
164 /* --------------------------------------------------------------------------------------------- */
167 vfs_rmstamp (struct vfs_class
*v
, vfsid id
)
169 struct vfs_stamping what
= {
175 stamp
= g_slist_find_custom (stamps
, &what
, vfs_stamp_compare
);
178 g_free (stamp
->data
);
179 stamps
= g_slist_delete_link (stamps
, stamp
);
183 /* --------------------------------------------------------------------------------------------- */
186 vfs_stamp_path (const vfs_path_t
*vpath
)
189 struct vfs_class
*me
;
191 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
192 id
= vfs_getid (vpath
);
193 vfs_addstamp (me
, id
);
196 /* --------------------------------------------------------------------------------------------- */
198 * Create a new timestamp item by VFS class and VFS id.
202 vfs_stamp_create (struct vfs_class
*vclass
, vfsid id
)
206 ev_vfs_stamp_create_t event_data
= { vclass
, id
, FALSE
};
207 const vfs_path_t
*vpath
;
208 struct vfs_class
*me
;
210 /* There are three directories we have to take care of: current_dir,
211 current_panel->cwd and other_panel->cwd. Although most of the time either
212 current_dir and current_panel->cwd or current_dir and other_panel->cwd are the
213 same, it's possible that all three are different -- Norbert */
215 if (!mc_event_present (MCEVENT_GROUP_CORE
, "vfs_timestamp"))
218 vpath
= vfs_get_raw_current_dir ();
219 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
221 nvfsid
= vfs_getid (vpath
);
222 vfs_rmstamp (me
, nvfsid
);
224 if (!(id
== NULL
|| (me
== vclass
&& nvfsid
== id
)))
226 mc_event_raise (MCEVENT_GROUP_CORE
, "vfs_timestamp", (gpointer
) & event_data
);
228 if (!event_data
.ret
&& vclass
!= NULL
&& vclass
->nothingisopen
!= NULL
229 && vclass
->nothingisopen (id
))
230 vfs_addstamp (vclass
, id
);
234 /* --------------------------------------------------------------------------------------------- */
235 /** This is called from timeout handler with now = FALSE,
236 or can be called with now = TRUE to force freeing all filesystems */
239 vfs_expire (gboolean now
)
241 static gboolean locked
= FALSE
;
242 gint64 curr_time
, exp_time
;
245 /* Avoid recursive invocation, e.g. when one of the free functions
251 curr_time
= g_get_monotonic_time ();
252 exp_time
= curr_time
- vfs_timeout
* G_USEC_PER_SEC
;
256 /* reverse list to free nested VFSes at first */
257 stamps
= g_slist_reverse (stamps
);
260 /* NULLize stamps that point to expired VFS */
261 for (stamp
= stamps
; stamp
!= NULL
; stamp
= g_slist_next (stamp
))
263 struct vfs_stamping
*stamping
= VFS_STAMPING (stamp
->data
);
267 /* free VFS forced */
268 if (stamping
->v
->free
!= NULL
)
269 stamping
->v
->free (stamping
->id
);
270 MC_PTR_FREE (stamp
->data
);
272 else if (stamping
->time
<= exp_time
)
274 /* update timestamp of VFS that is in use, or free unused VFS */
275 if (stamping
->v
->nothingisopen
!= NULL
&& !stamping
->v
->nothingisopen (stamping
->id
))
276 stamping
->time
= curr_time
;
279 if (stamping
->v
->free
!= NULL
)
280 stamping
->v
->free (stamping
->id
);
281 MC_PTR_FREE (stamp
->data
);
286 /* then remove NULLized stamps */
287 stamps
= g_slist_remove_all (stamps
, NULL
);
292 /* --------------------------------------------------------------------------------------------- */
294 * Return the number of seconds remaining to the vfs timeout.
295 * FIXME: The code should be improved to actually return the number of
296 * seconds until the next item times out.
302 return stamps
!= NULL
? 10 : 0;
305 /* --------------------------------------------------------------------------------------------- */
308 vfs_timeout_handler (void)
313 /* --------------------------------------------------------------------------------------------- */
316 vfs_release_path (const vfs_path_t
*vpath
)
319 struct vfs_class
*me
;
321 me
= VFS_CLASS (vfs_path_get_last_path_vfs (vpath
));
322 id
= vfs_getid (vpath
);
323 vfs_stamp_create (me
, id
);
326 /* --------------------------------------------------------------------------------------------- */
335 /* --------------------------------------------------------------------------------------------- */