1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-async-job-map.c
4 Copyright (C) 2001 Eazel Inc.
6 The Gnome Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The Gnome Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the Gnome Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Author: Pavel Cisler <pavel@eazel.com> */
24 #include "gnome-vfs-async-job-map.h"
26 #include "gnome-vfs-job.h"
27 #include <glib/ghash.h>
28 #include <glib/gmessages.h>
30 /* job map bits guarded by this lock */
31 static GStaticRecMutex async_job_map_lock = G_STATIC_REC_MUTEX_INIT;
32 static guint async_job_map_next_id;
33 static int async_job_map_locked = 0;
34 static gboolean async_job_map_shutting_down;
35 static GHashTable *async_job_map;
37 /* callback map bits guarded by this lock */
38 static GStaticMutex async_job_callback_map_lock = G_STATIC_MUTEX_INIT;
39 static GHashTable *async_job_callback_map;
40 static guint async_job_callback_map_next_id;
42 void async_job_callback_map_destroy (void);
45 _gnome_vfs_async_job_map_init (void)
50 _gnome_vfs_async_job_map_get_job (const GnomeVFSAsyncHandle *handle)
52 _gnome_vfs_async_job_map_assert_locked ();
53 g_assert (async_job_map != NULL);
55 return g_hash_table_lookup (async_job_map, handle);
59 _gnome_vfs_async_job_map_add_job (GnomeVFSJob *job)
61 _gnome_vfs_async_job_map_lock ();
63 g_assert (!async_job_map_shutting_down);
65 /* Assign a unique id to each job. The GnomeVFSAsyncHandle pointers each
66 * async op call deals with this will really be these unique IDs
68 job->job_handle = GUINT_TO_POINTER (++async_job_map_next_id);
70 if (async_job_map == NULL) {
71 /* First job, allocate a new hash table. */
72 async_job_map = g_hash_table_new (NULL, NULL);
75 g_hash_table_insert (async_job_map, job->job_handle, job);
77 _gnome_vfs_async_job_map_unlock ();
81 _gnome_vfs_async_job_map_remove_job (GnomeVFSJob *job)
83 _gnome_vfs_async_job_map_lock ();
85 g_assert (async_job_map);
87 g_hash_table_remove (async_job_map, job->job_handle);
89 _gnome_vfs_async_job_map_unlock ();
94 gnome_vfs_async_job_map_destroy (void)
96 _gnome_vfs_async_job_map_assert_locked ();
97 g_assert (async_job_map_shutting_down);
98 g_assert (async_job_map != NULL);
100 g_hash_table_destroy (async_job_map);
101 async_job_map = NULL;
105 _gnome_vfs_async_job_completed (GnomeVFSAsyncHandle *handle)
109 _gnome_vfs_async_job_map_lock ();
111 JOB_DEBUG (("%d", GPOINTER_TO_UINT (handle)));
112 /* Job done, remove it's id from the map */
114 g_assert (async_job_map != NULL);
116 job = _gnome_vfs_async_job_map_get_job (handle);
118 g_hash_table_remove (async_job_map, handle);
121 if (async_job_map_shutting_down && g_hash_table_size (async_job_map) == 0) {
122 /* We were the last active job, turn the lights off. */
123 gnome_vfs_async_job_map_destroy ();
126 _gnome_vfs_async_job_map_unlock ();
132 _gnome_vfs_async_job_map_shutdown (void)
134 _gnome_vfs_async_job_map_lock ();
138 /* tell the async jobs it's quitting time */
139 async_job_map_shutting_down = TRUE;
141 if (g_hash_table_size (async_job_map) == 0) {
142 /* No more outstanding jobs to finish, just delete
143 * the hash table directly.
145 gnome_vfs_async_job_map_destroy ();
149 /* The last expiring job will delete the hash table. */
150 _gnome_vfs_async_job_map_unlock ();
152 async_job_callback_map_destroy ();
156 _gnome_vfs_async_job_map_lock (void)
158 g_static_rec_mutex_lock (&async_job_map_lock);
159 async_job_map_locked++;
163 _gnome_vfs_async_job_map_unlock (void)
165 async_job_map_locked--;
166 g_static_rec_mutex_unlock (&async_job_map_lock);
170 _gnome_vfs_async_job_map_assert_locked (void)
172 g_assert (async_job_map_locked);
176 _gnome_vfs_async_job_callback_valid (guint callback_id,
180 GnomeVFSNotifyResult *notify_result;
182 g_static_mutex_lock (&async_job_callback_map_lock);
184 if (async_job_callback_map == NULL) {
185 g_assert (async_job_map_shutting_down);
190 notify_result = (GnomeVFSNotifyResult *) g_hash_table_lookup
191 (async_job_callback_map, GUINT_TO_POINTER (callback_id));
193 *valid = notify_result != NULL;
194 *cancelled = notify_result != NULL && notify_result->cancelled;
196 g_static_mutex_unlock (&async_job_callback_map_lock);
200 _gnome_vfs_async_job_add_callback (GnomeVFSJob *job, GnomeVFSNotifyResult *notify_result)
204 g_static_mutex_lock (&async_job_callback_map_lock);
206 g_assert (!async_job_map_shutting_down);
208 /* Assign a unique id to each job callback. Use unique IDs instead of the
209 * notify_results pointers to avoid aliasing problems.
211 notify_result->callback_id = ++async_job_callback_map_next_id;
213 JOB_DEBUG (("adding callback %d ", notify_result->callback_id));
215 if (async_job_callback_map == NULL) {
216 /* First job, allocate a new hash table. */
217 async_job_callback_map = g_hash_table_new (NULL, NULL);
220 /* we are using async_job_callback_map_lock to ensure atomicity of
221 * checking/clearing job->cancelled and adding/cancelling callbacks
223 cancelled = job->cancelled;
226 g_hash_table_insert (async_job_callback_map, GUINT_TO_POINTER (notify_result->callback_id),
229 g_static_mutex_unlock (&async_job_callback_map_lock);
235 _gnome_vfs_async_job_remove_callback (guint callback_id)
237 g_assert (async_job_callback_map != NULL);
239 JOB_DEBUG (("removing callback %d ", callback_id));
240 g_static_mutex_lock (&async_job_callback_map_lock);
242 g_hash_table_remove (async_job_callback_map, GUINT_TO_POINTER (callback_id));
244 g_static_mutex_unlock (&async_job_callback_map_lock);
248 callback_map_cancel_one (gpointer key, gpointer value, gpointer user_data)
250 GnomeVFSNotifyResult *notify_result;
252 notify_result = (GnomeVFSNotifyResult *) value;
254 if (notify_result->job_handle == (GnomeVFSAsyncHandle *)user_data) {
255 JOB_DEBUG (("cancelling callback %u - job %u cancelled",
256 GPOINTER_TO_UINT (key),
257 GPOINTER_TO_UINT (user_data)));
258 notify_result->cancelled = TRUE;
263 _gnome_vfs_async_job_cancel_job_and_callbacks (GnomeVFSAsyncHandle *job_handle, GnomeVFSJob *job)
265 g_static_mutex_lock (&async_job_callback_map_lock);
268 job->cancelled = TRUE;
271 if (async_job_callback_map == NULL) {
272 JOB_DEBUG (("job %u, no callbacks scheduled yet",
273 GPOINTER_TO_UINT (job_handle)));
275 g_hash_table_foreach (async_job_callback_map,
276 callback_map_cancel_one, job_handle);
279 g_static_mutex_unlock (&async_job_callback_map_lock);
283 async_job_callback_map_destroy (void)
285 g_static_mutex_lock (&async_job_callback_map_lock);
287 if (async_job_callback_map) {
288 g_hash_table_destroy (async_job_callback_map);
289 async_job_callback_map = NULL;
292 g_static_mutex_unlock (&async_job_callback_map_lock);