2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/tsq.c - Thread-safe queues
11 This file implements thread-safe queues for Parrot.
21 #include "parrot/parrot.h"
23 /* HEADERIZER HFILE: include/parrot/tsq.h */
27 =item C<QUEUE_ENTRY * pop_entry(QUEUE *queue)>
29 Does a synchronized removal of the head entry off the queue and returns it.
35 PARROT_CAN_RETURN_NULL
37 pop_entry(ARGMOD(QUEUE
*queue
))
39 ASSERT_ARGS(pop_entry
)
40 QUEUE_ENTRY
*returnval
;
42 returnval
= nosync_pop_entry(queue
);
49 =item C<QUEUE_ENTRY * peek_entry(const QUEUE *queue)>
51 This does no locking, so the result might have changed by the time you
52 get the entry, but a synchronized C<pop_entry()> will check again and
53 return C<NULL> if the queue is empty.
59 PARROT_CAN_RETURN_NULL
60 PARROT_WARN_UNUSED_RESULT
62 peek_entry(ARGIN(const QUEUE
*queue
))
64 ASSERT_ARGS(peek_entry
)
70 =item C<QUEUE_ENTRY * nosync_pop_entry(QUEUE *queue)>
72 Grab an entry off the queue with no synchronization. Internal only,
73 because it's darned evil and shouldn't be used outside the module. It's
74 in here so we don't have to duplicate pop code.
80 PARROT_CANNOT_RETURN_NULL
82 nosync_pop_entry(ARGMOD(QUEUE
*queue
))
84 ASSERT_ARGS(nosync_pop_entry
)
85 QUEUE_ENTRY
*returnval
;
89 returnval
= queue
->head
;
90 if (queue
->head
== queue
->tail
) {
95 queue
->head
= queue
->head
->next
;
97 returnval
->next
= NULL
;
103 =item C<QUEUE_ENTRY * wait_for_entry(QUEUE *queue)>
105 Does a synchronized removal of the head entry off the queue, waiting if
106 necessary until there is an entry, and then returns it.
112 PARROT_CAN_RETURN_NULL
114 wait_for_entry(ARGMOD(QUEUE
*queue
))
116 ASSERT_ARGS(wait_for_entry
)
117 QUEUE_ENTRY
*returnval
;
120 while (queue
->head
== NULL
) {
123 returnval
= nosync_pop_entry(queue
);
131 =item C<void push_entry(QUEUE *queue, QUEUE_ENTRY *entry)>
133 Does a synchronized insertion of C<entry> onto the tail of the queue.
140 push_entry(ARGMOD(QUEUE
*queue
), ARGIN(QUEUE_ENTRY
*entry
))
142 ASSERT_ARGS(push_entry
)
144 /* Is there something in the queue? */
146 queue
->tail
->next
= entry
;
153 queue_signal(queue
); /* assumes only one waiter */
159 =item C<void unshift_entry(QUEUE *queue, QUEUE_ENTRY *entry)>
161 Does a synchronized insertion of C<entry> into the head of the queue.
168 unshift_entry(ARGMOD(QUEUE
*queue
), ARGIN(QUEUE_ENTRY
*entry
))
170 ASSERT_ARGS(unshift_entry
)
176 /* empty just set head */
190 =item C<void nosync_insert_entry(QUEUE *queue, QUEUE_ENTRY *entry)>
192 Inserts a timed event according to C<abstime>. The caller has to hold the
200 nosync_insert_entry(ARGMOD(QUEUE
*queue
), ARGIN(QUEUE_ENTRY
*entry
))
202 ASSERT_ARGS(nosync_insert_entry
)
203 QUEUE_ENTRY
*cur
= queue
->head
;
208 PARROT_ASSERT(entry
->type
== QUEUE_ENTRY_TYPE_TIMED_EVENT
);
210 * empty queue - just insert
219 event
= (parrot_event
*)entry
->data
;
220 abs_time
= event
->u
.timer_event
.abs_time
;
222 while (cur
&& cur
->type
== QUEUE_ENTRY_TYPE_TIMED_EVENT
) {
223 const parrot_event
* const cur_event
= (parrot_event
*)cur
->data
;
224 if (abs_time
> cur_event
->u
.timer_event
.abs_time
) {
235 if (prev
== queue
->tail
)
243 =item C<void insert_entry(QUEUE *queue, QUEUE_ENTRY *entry)>
245 Does a synchronized insert of C<entry>.
252 insert_entry(ARGMOD(QUEUE
*queue
), ARGIN(QUEUE_ENTRY
*entry
))
254 ASSERT_ARGS(insert_entry
)
256 nosync_insert_entry(queue
, entry
);
263 =item C<void queue_lock(QUEUE *queue)>
265 Locks the queue's mutex.
272 queue_lock(ARGMOD(QUEUE
*queue
))
274 ASSERT_ARGS(queue_lock
)
275 LOCK(queue
->queue_mutex
);
280 =item C<void queue_unlock(QUEUE *queue)>
282 Unlocks the queue's mutex.
289 queue_unlock(ARGMOD(QUEUE
*queue
))
291 ASSERT_ARGS(queue_unlock
)
292 UNLOCK(queue
->queue_mutex
);
297 =item C<void queue_broadcast(QUEUE *queue)>
299 This function wakes up I<every> thread waiting on the queue.
306 queue_broadcast(ARGMOD(QUEUE
*queue
))
308 ASSERT_ARGS(queue_broadcast
)
309 COND_BROADCAST(queue
->queue_condition
);
314 =item C<void queue_signal(QUEUE *queue)>
321 queue_signal(ARGMOD(QUEUE
*queue
))
323 ASSERT_ARGS(queue_signal
)
324 COND_SIGNAL(queue
->queue_condition
);
329 =item C<void queue_wait(QUEUE *queue)>
331 Instructs the queue to wait.
338 queue_wait(ARGMOD(QUEUE
*queue
))
340 ASSERT_ARGS(queue_wait
)
341 COND_WAIT(queue
->queue_condition
, queue
->queue_mutex
);
346 =item C<void queue_timedwait(QUEUE *queue, const struct timespec *abs_time)>
348 Instructs the queue to wait for C<abs_time> seconds (?).
355 queue_timedwait(ARGMOD(QUEUE
*queue
), ARGIN(const struct timespec
*abs_time
))
357 ASSERT_ARGS(queue_timedwait
)
358 COND_TIMED_WAIT(queue
->queue_condition
, queue
->queue_mutex
, abs_time
);
363 =item C<QUEUE* queue_init(UINTVAL prio)>
365 Initializes the queue, setting C<prio> as the queue's priority.
371 PARROT_CAN_RETURN_NULL
374 queue_init(UINTVAL prio
)
376 ASSERT_ARGS(queue_init
)
377 QUEUE
* const queue
= mem_allocate_typed(QUEUE
);
379 queue
->head
= queue
->tail
= NULL
;
380 queue
->max_prio
= prio
;
381 COND_INIT(queue
->queue_condition
);
382 MUTEX_INIT(queue
->queue_mutex
);
388 =item C<void queue_destroy(QUEUE *queue)>
390 Destroys the queue, raising an exception if it is not empty.
397 queue_destroy(ARGMOD(QUEUE
*queue
))
399 ASSERT_ARGS(queue_destroy
)
400 if (peek_entry(queue
))
401 exit_fatal(1, "Queue not empty on destroy");
403 COND_DESTROY(queue
->queue_condition
);
404 MUTEX_DESTROY(queue
->queue_mutex
);
414 F<include/parrot/tsq.h>.
423 * c-file-style: "parrot"
425 * vim: expandtab shiftwidth=4: