ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/gnome-vfs2-2.3.8-1.src.rpm
[gnome-vfs-httpcaptive.git] / libgnomevfs / gnome-vfs-async-job-map.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-async-job-map.c
3
4    Copyright (C) 2001 Eazel Inc.
5
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.
10
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.
15
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.
20
21    Author: Pavel Cisler <pavel@eazel.com> */
22
23 #include <config.h>
24 #include "gnome-vfs-async-job-map.h"
25
26 #include "gnome-vfs-job.h"
27 #include <glib/ghash.h>
28 #include <glib/gmessages.h>
29
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;
36
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;
41
42 void async_job_callback_map_destroy (void);
43
44 void 
45 _gnome_vfs_async_job_map_init (void)
46 {
47 }
48
49 GnomeVFSJob *
50 _gnome_vfs_async_job_map_get_job (const GnomeVFSAsyncHandle *handle)
51 {
52         _gnome_vfs_async_job_map_assert_locked ();
53         g_assert (async_job_map != NULL);
54
55         return g_hash_table_lookup (async_job_map, handle);
56 }
57
58 void
59 _gnome_vfs_async_job_map_add_job (GnomeVFSJob *job)
60 {
61         _gnome_vfs_async_job_map_lock ();
62
63         g_assert (!async_job_map_shutting_down);
64
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
67          */
68         job->job_handle = GUINT_TO_POINTER (++async_job_map_next_id);
69
70         if (async_job_map == NULL) {
71                 /* First job, allocate a new hash table. */
72                 async_job_map = g_hash_table_new (NULL, NULL);
73         }
74
75         g_hash_table_insert (async_job_map, job->job_handle, job);
76
77         _gnome_vfs_async_job_map_unlock ();
78 }
79
80 void
81 _gnome_vfs_async_job_map_remove_job (GnomeVFSJob *job)
82 {
83         _gnome_vfs_async_job_map_lock ();
84         
85         g_assert (async_job_map);
86
87         g_hash_table_remove (async_job_map, job->job_handle);
88         
89         _gnome_vfs_async_job_map_unlock ();
90 }
91
92
93 static void
94 gnome_vfs_async_job_map_destroy (void)
95 {
96         _gnome_vfs_async_job_map_assert_locked ();
97         g_assert (async_job_map_shutting_down);
98         g_assert (async_job_map != NULL);
99         
100         g_hash_table_destroy (async_job_map);
101         async_job_map = NULL;
102 }
103
104 gboolean 
105 _gnome_vfs_async_job_completed (GnomeVFSAsyncHandle *handle)
106 {
107         GnomeVFSJob *job;
108
109         _gnome_vfs_async_job_map_lock ();
110
111         JOB_DEBUG (("%d", GPOINTER_TO_UINT (handle)));
112         /* Job done, remove it's id from the map */
113
114         g_assert (async_job_map != NULL);
115
116         job = _gnome_vfs_async_job_map_get_job (handle);
117         if (job != NULL) {
118                 g_hash_table_remove (async_job_map, handle);
119         }
120         
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 ();
124         }
125         
126         _gnome_vfs_async_job_map_unlock ();
127         
128         return job != NULL;
129 }
130
131 void
132 _gnome_vfs_async_job_map_shutdown (void)
133 {
134         _gnome_vfs_async_job_map_lock ();
135         
136         if (async_job_map) {
137
138                 /* tell the async jobs it's quitting time */
139                 async_job_map_shutting_down = TRUE;
140
141                 if (g_hash_table_size (async_job_map) == 0) {
142                         /* No more outstanding jobs to finish, just delete
143                          * the hash table directly.
144                          */
145                         gnome_vfs_async_job_map_destroy ();
146                 }
147         }
148
149         /* The last expiring job will delete the hash table. */
150         _gnome_vfs_async_job_map_unlock ();
151         
152         async_job_callback_map_destroy ();
153 }
154
155 void 
156 _gnome_vfs_async_job_map_lock (void)
157 {
158         g_static_rec_mutex_lock (&async_job_map_lock);
159         async_job_map_locked++;
160 }
161
162 void 
163 _gnome_vfs_async_job_map_unlock (void)
164 {
165         async_job_map_locked--;
166         g_static_rec_mutex_unlock (&async_job_map_lock);
167 }
168
169 void 
170 _gnome_vfs_async_job_map_assert_locked (void)
171 {
172         g_assert (async_job_map_locked);
173 }
174
175 void 
176 _gnome_vfs_async_job_callback_valid (guint     callback_id,
177                                     gboolean *valid,
178                                     gboolean *cancelled)
179 {
180         GnomeVFSNotifyResult *notify_result;
181         
182         g_static_mutex_lock (&async_job_callback_map_lock);
183         
184         if (async_job_callback_map == NULL) {
185                 g_assert (async_job_map_shutting_down);
186                 *valid = FALSE;
187                 *cancelled = FALSE;
188         }
189
190         notify_result = (GnomeVFSNotifyResult *) g_hash_table_lookup
191                 (async_job_callback_map, GUINT_TO_POINTER (callback_id));
192         
193         *valid = notify_result != NULL;
194         *cancelled = notify_result != NULL && notify_result->cancelled;
195
196         g_static_mutex_unlock (&async_job_callback_map_lock);
197 }
198
199 gboolean 
200 _gnome_vfs_async_job_add_callback (GnomeVFSJob *job, GnomeVFSNotifyResult *notify_result)
201 {
202         gboolean cancelled;
203
204         g_static_mutex_lock (&async_job_callback_map_lock);
205
206         g_assert (!async_job_map_shutting_down);
207         
208         /* Assign a unique id to each job callback. Use unique IDs instead of the
209          * notify_results pointers to avoid aliasing problems.
210          */
211         notify_result->callback_id = ++async_job_callback_map_next_id;
212
213         JOB_DEBUG (("adding callback %d ", notify_result->callback_id));
214
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);
218         }
219
220         /* we are using async_job_callback_map_lock to ensure atomicity of
221          * checking/clearing job->cancelled and adding/cancelling callbacks
222          */
223         cancelled = job->cancelled;
224         
225         if (!cancelled) {
226                 g_hash_table_insert (async_job_callback_map, GUINT_TO_POINTER (notify_result->callback_id),
227                         notify_result);
228         }
229         g_static_mutex_unlock (&async_job_callback_map_lock);
230         
231         return !cancelled;
232 }
233
234 void 
235 _gnome_vfs_async_job_remove_callback (guint callback_id)
236 {
237         g_assert (async_job_callback_map != NULL);
238
239         JOB_DEBUG (("removing callback %d ", callback_id));
240         g_static_mutex_lock (&async_job_callback_map_lock);
241
242         g_hash_table_remove (async_job_callback_map, GUINT_TO_POINTER (callback_id));
243
244         g_static_mutex_unlock (&async_job_callback_map_lock);
245 }
246
247 static void
248 callback_map_cancel_one (gpointer key, gpointer value, gpointer user_data)
249 {
250         GnomeVFSNotifyResult *notify_result;
251         
252         notify_result = (GnomeVFSNotifyResult *) value;
253         
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;
259         }
260 }
261
262 void
263 _gnome_vfs_async_job_cancel_job_and_callbacks (GnomeVFSAsyncHandle *job_handle, GnomeVFSJob *job)
264 {
265         g_static_mutex_lock (&async_job_callback_map_lock);
266         
267         if (job != NULL) {
268                 job->cancelled = TRUE;
269         }
270         
271         if (async_job_callback_map == NULL) {
272                 JOB_DEBUG (("job %u, no callbacks scheduled yet",
273                             GPOINTER_TO_UINT (job_handle)));
274         } else {
275                 g_hash_table_foreach (async_job_callback_map,
276                                       callback_map_cancel_one, job_handle);
277         }
278
279         g_static_mutex_unlock (&async_job_callback_map_lock);
280 }
281
282 void
283 async_job_callback_map_destroy (void)
284 {
285         g_static_mutex_lock (&async_job_callback_map_lock);
286
287         if (async_job_callback_map) {
288                 g_hash_table_destroy (async_job_callback_map);
289                 async_job_callback_map = NULL;
290         }
291
292         g_static_mutex_unlock (&async_job_callback_map_lock);
293 }