2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* ---------------------------- included header files ---------------------- */
23 #include "safemalloc.h"
26 /* ---------------------------- local definitions -------------------------- */
28 /* ---------------------------- local macros ------------------------------- */
30 /* ---------------------------- imports ------------------------------------ */
32 /* ---------------------------- included code files ------------------------ */
34 /* ---------------------------- local types -------------------------------- */
36 /* ---------------------------- forward declarations ----------------------- */
38 /* ---------------------------- local variables ---------------------------- */
40 typedef struct fqueue_record
42 struct fqueue_record
*next
;
46 unsigned is_scheduled_for_deletion
;
47 unsigned is_just_created
;
51 /* ---------------------------- exported variables (globals) --------------- */
53 /* ---------------------------- local functions ---------------------------- */
55 /* ---------------------------- interface functions ------------------------ */
57 /* Make newly added items permanent and destroy items scheduled for deletion. */
58 static void fqueue_cleanup_queue(
59 fqueue
*fq
, destroy_fqueue_object_t destroy_func
)
67 for (head
= NULL
, tail
= NULL
, prev
= NULL
, rec
= fq
->first
;
68 rec
!= NULL
; rec
= next
)
70 if (rec
->flags
.is_scheduled_for_deletion
)
72 /* destroy and skip it */
74 if (rec
->object
!= NULL
&& destroy_func
!= NULL
)
76 destroy_func(rec
->object
);
86 rec
->flags
.is_just_created
= 0;
102 /* Recursively lock the queue. While locked, objects are not deleted from the
103 * queue but marked for later deletion. New objects are marked as such and are
104 * skipped by the queue functions. */
105 static void fqueue_lock_queue(fqueue
*fq
)
112 /* Remove one lock level */
113 static void fqueue_unlock_queue(
114 fqueue
*fq
, destroy_fqueue_object_t destroy_func
)
116 switch (fq
->lock_level
)
122 if (fq
->flags
.is_dirty
)
124 fqueue_cleanup_queue(fq
, destroy_func
);
135 /* Chack and possibly execute the action associated with a queue object.
136 * Schedule the object for deletion if it was executed. */
137 static void fqueue_operate(
138 fqueue
*fq
, fqueue_record
*rec
,
139 check_fqueue_object_t check_func
,
140 operate_fqueue_object_t operate_func
,
143 if (rec
== NULL
|| rec
->flags
.is_scheduled_for_deletion
)
147 if (check_func
== NULL
|| check_func(rec
->object
, operate_args
) == 1)
149 if (operate_func
!= NULL
)
151 operate_func(rec
->object
, operate_args
);
153 rec
->flags
.is_scheduled_for_deletion
= 1;
154 fq
->flags
.is_dirty
= 1;
160 /* ---------------------------- builtin commands --------------------------- */
163 * Basic queue management
166 void fqueue_init(fqueue
*fq
)
168 memset(fq
, 0, sizeof(*fq
));
173 unsigned int fqueue_get_length(fqueue
*fq
)
178 for (t
= fq
->first
, len
= 0; t
!= NULL
; t
= t
->next
)
180 if (!t
->flags
.is_scheduled_for_deletion
)
190 * Add record to queue
193 void fqueue_add_at_front(
194 fqueue
*fq
, void *object
)
198 rec
= (fqueue_record
*)safemalloc(sizeof(fqueue_record
));
199 memset(rec
, 0, sizeof(*rec
));
200 rec
->object
= object
;
201 rec
->next
= fq
->first
;
202 if (fq
->lock_level
> 0)
204 rec
->flags
.is_just_created
= 1;
205 fq
->flags
.is_dirty
= 1;
212 void fqueue_add_at_end(
213 fqueue
*fq
, void *object
)
217 rec
= (fqueue_record
*)safemalloc(sizeof(fqueue_record
));
218 memset(rec
, 0, sizeof(*rec
));
219 rec
->object
= object
;
220 if (fq
->lock_level
> 0)
222 rec
->flags
.is_just_created
= 1;
223 fq
->flags
.is_dirty
= 1;
225 if (fq
->first
== NULL
)
231 fq
->last
->next
= rec
;
239 void fqueue_add_inside(
240 fqueue
*fq
, void *object
, cmp_objects_t cmp_objects
, void *cmp_args
)
246 rec
= (fqueue_record
*)safemalloc(sizeof(fqueue_record
));
247 memset(rec
, 0, sizeof(*rec
));
248 rec
->object
= object
;
249 if (fq
->lock_level
> 0)
251 rec
->flags
.is_just_created
= 1;
252 fq
->flags
.is_dirty
= 1;
255 /* search place to insert record */
256 for (p
= NULL
, t
= fq
->first
;
257 t
!= NULL
&& cmp_objects(object
, t
->object
, cmp_args
) >= 0;
260 /* nothing to do here */
265 /* insert at start */
266 rec
->next
= fq
->first
;
284 * Fetch queue objects
287 /* Returns the object of the first queue record throuch *ret_object. Returns
288 * 0 if the queue is empty and 1 otherwise. */
289 int fqueue_get_first(
290 fqueue
*fq
, void **ret_object
)
294 for (rec
= fq
->first
;
295 rec
!= NULL
&& rec
->flags
.is_scheduled_for_deletion
;
304 *ret_object
= rec
->object
;
310 * Operate on queue objects and possibly remove them from the queue
313 /* Runs the operate_func on the first record in the queue. If that function
314 * is NULL or returns 1, the record is removed from the queue. The object of
315 * the queue record must have been freed in operate_func. */
316 void fqueue_remove_or_operate_from_front(
318 check_fqueue_object_t check_func
,
319 operate_fqueue_object_t operate_func
,
320 destroy_fqueue_object_t destroy_func
,
323 fqueue_lock_queue(fq
);
324 fqueue_operate(fq
, fq
->first
, check_func
, operate_func
, operate_args
);
325 fqueue_unlock_queue(fq
, destroy_func
);
330 /* Same as above but operates on last record in queue */
331 void fqueue_remove_or_operate_from_end(
333 check_fqueue_object_t check_func
,
334 operate_fqueue_object_t operate_func
,
335 destroy_fqueue_object_t destroy_func
,
338 fqueue_lock_queue(fq
);
339 fqueue_operate( fq
, fq
->last
, check_func
, operate_func
, operate_args
);
340 fqueue_unlock_queue(fq
, destroy_func
);
345 /* Same as above but operates on all records in the queue. */
346 void fqueue_remove_or_operate_all(
348 check_fqueue_object_t check_func
,
349 operate_fqueue_object_t operate_func
,
350 destroy_fqueue_object_t destroy_func
,
355 if (fq
->first
== NULL
)
359 fqueue_lock_queue(fq
);
360 /* search record(s) to remove */
361 for (t
= fq
->first
; t
!= NULL
; t
= t
->next
)
363 if (t
->flags
.is_just_created
||
364 t
->flags
.is_scheduled_for_deletion
)
369 fqueue_operate(fq
, t
, check_func
, operate_func
, operate_args
);
371 fqueue_unlock_queue(fq
, destroy_func
);