+ --debug is now --imcc-debug; make this more consistent with -D.
[parrot.git] / src / tsq.c
blob4166dac619cc8319f45b0dfb9a47eac986da103e
1 /*
2 Copyright (C) 2001-2007, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/tsq.c - Thread-safe queues
9 =head1 DESCRIPTION
11 =head2 Functions
13 =over 4
15 =cut
19 #include "parrot/parrot.h"
21 /* HEADERIZER HFILE: include/parrot/tsq.h */
25 =item C<QUEUE_ENTRY * pop_entry>
27 Does a synchronized removal of the head entry off the queue and returns it.
29 =cut
33 PARROT_CAN_RETURN_NULL
34 QUEUE_ENTRY *
35 pop_entry(ARGMOD(QUEUE *queue))
37 QUEUE_ENTRY *returnval;
38 queue_lock(queue);
39 returnval = nosync_pop_entry(queue);
40 queue_unlock(queue);
41 return returnval;
46 =item C<QUEUE_ENTRY * peek_entry>
48 This does no locking, so the result might have changed by the time you
49 get the entry, but a synchronized C<pop_entry()> will check again and
50 return C<NULL> if the queue is empty.
52 =cut
56 PARROT_CAN_RETURN_NULL
57 PARROT_WARN_UNUSED_RESULT
58 QUEUE_ENTRY *
59 peek_entry(ARGIN(const QUEUE *queue))
61 return queue->head;
66 =item C<QUEUE_ENTRY * nosync_pop_entry>
68 Grab an entry off the queue with no synchronization. Internal only,
69 because it's darned evil and shouldn't be used outside the module. It's
70 in here so we don't have to duplicate pop code.
72 =cut
76 PARROT_CAN_RETURN_NULL
77 QUEUE_ENTRY *
78 nosync_pop_entry(ARGMOD(QUEUE *queue))
80 QUEUE_ENTRY *returnval;
81 if (!queue->head) {
82 return NULL;
84 returnval = queue->head;
85 if (queue->head == queue->tail) {
86 queue->head = NULL;
87 queue->tail = NULL;
89 else {
90 queue->head = queue->head->next;
92 returnval->next = NULL;
93 return returnval;
98 =item C<QUEUE_ENTRY * wait_for_entry>
100 Does a synchronized removal of the head entry off the queue, waiting if
101 necessary until there is an entry, and then returns it.
103 =cut
107 PARROT_CAN_RETURN_NULL
108 QUEUE_ENTRY *
109 wait_for_entry(ARGMOD(QUEUE *queue))
111 QUEUE_ENTRY *returnval;
113 queue_lock(queue);
114 while (queue->head == NULL) {
115 queue_wait(queue);
117 returnval = nosync_pop_entry(queue);
118 queue_unlock(queue);
119 return returnval;
125 =item C<void push_entry>
127 Does a synchronized insertion of C<entry> onto the tail of the queue.
129 =cut
133 void
134 push_entry(ARGMOD(QUEUE *queue), ARGIN(QUEUE_ENTRY *entry))
136 queue_lock(queue);
137 /* Is there something in the queue? */
138 if (queue->tail) {
139 queue->tail->next = entry;
140 queue->tail = entry;
142 else {
143 queue->head = entry;
144 queue->tail = entry;
146 queue_signal(queue); /* assumes only one waiter */
147 queue_unlock(queue);
152 =item C<void unshift_entry>
154 Does a synchronized insertion of C<entry> into the head of the queue.
156 =cut
160 void
161 unshift_entry(ARGMOD(QUEUE *queue), ARGIN(QUEUE_ENTRY *entry))
163 QUEUE_ENTRY *cur;
165 queue_lock(queue);
166 cur = queue->head;
167 if (!cur) {
168 /* empty just set head */
169 queue->head = entry;
170 queue->tail = entry;
172 else {
173 queue->head = entry;
174 entry->next = cur;
176 queue_signal(queue);
177 queue_unlock(queue);
182 =item C<void nosync_insert_entry>
184 Inserts a timed event according to C<abstime>. The caller has to hold the
185 queue mutex.
187 =cut
191 void
192 nosync_insert_entry(ARGMOD(QUEUE *queue), ARGIN(QUEUE_ENTRY *entry))
194 QUEUE_ENTRY *cur = queue->head;
195 QUEUE_ENTRY *prev;
196 parrot_event *event;
197 FLOATVAL abs_time;
199 PARROT_ASSERT(entry->type == QUEUE_ENTRY_TYPE_TIMED_EVENT);
201 * empty queue - just insert
203 if (!cur) {
204 queue->head = entry;
205 queue->tail = entry;
206 return;
209 prev = NULL;
210 event = (parrot_event *)entry->data;
211 abs_time = event->u.timer_event.abs_time;
213 while (cur && cur->type == QUEUE_ENTRY_TYPE_TIMED_EVENT) {
214 const parrot_event * const cur_event = (parrot_event *)cur->data;
215 if (abs_time > cur_event->u.timer_event.abs_time) {
216 prev = cur;
217 cur = cur->next;
219 else
220 break;
222 if (!prev)
223 queue->head = entry;
224 else {
225 prev->next = entry;
226 if (prev == queue->tail)
227 queue->tail = entry;
229 entry->next = cur;
234 =item C<void insert_entry>
236 Does a synchronized insert of C<entry>.
238 =cut
242 void
243 insert_entry(ARGMOD(QUEUE *queue), ARGIN(QUEUE_ENTRY *entry))
245 queue_lock(queue);
246 nosync_insert_entry(queue, entry);
247 queue_signal(queue);
248 queue_unlock(queue);
253 =item C<void queue_lock>
255 Locks the queue's mutex.
257 =cut
261 void
262 queue_lock(ARGMOD(QUEUE *queue))
264 LOCK(queue->queue_mutex);
269 =item C<void queue_unlock>
271 Unlocks the queue's mutex.
273 =cut
277 void
278 queue_unlock(ARGMOD(QUEUE *queue))
280 UNLOCK(queue->queue_mutex);
285 =item C<void queue_broadcast>
287 This function wakes up I<every> thread waiting on the queue.
289 =cut
293 void
294 queue_broadcast(ARGMOD(QUEUE *queue))
296 COND_BROADCAST(queue->queue_condition);
301 =item C<void queue_signal>
303 XXX Needs a description
305 =cut
309 void
310 queue_signal(ARGMOD(QUEUE *queue))
312 COND_SIGNAL(queue->queue_condition);
317 =item C<void queue_wait>
319 Instructs the queue to wait.
321 =cut
325 void
326 queue_wait(ARGMOD(QUEUE *queue))
328 COND_WAIT(queue->queue_condition, queue->queue_mutex);
333 =item C<void queue_timedwait>
335 Instructs the queue to wait for C<abs_time> seconds (?).
337 =cut
341 void
342 queue_timedwait(ARGMOD(QUEUE *queue), ARGIN(const struct timespec *abs_time))
344 COND_TIMED_WAIT(queue->queue_condition, queue->queue_mutex, abs_time);
349 =item C<QUEUE* queue_init>
351 Initializes the queue, setting C<prio> as the queue's priority.
353 =cut
357 PARROT_CAN_RETURN_NULL
358 PARROT_MALLOC
359 QUEUE*
360 queue_init(UINTVAL prio)
362 QUEUE * const queue = mem_allocate_typed(QUEUE);
364 queue->head = queue->tail = NULL;
365 queue->max_prio = prio;
366 COND_INIT(queue->queue_condition);
367 MUTEX_INIT(queue->queue_mutex);
368 return queue;
373 =item C<void queue_destroy>
375 Destroys the queue, raising an exception if it is not empty.
377 =cut
381 void
382 queue_destroy(ARGMOD(QUEUE *queue))
384 if (peek_entry(queue))
385 internal_exception(1, "Queue not empty on destroy");
387 COND_DESTROY(queue->queue_condition);
388 MUTEX_DESTROY(queue->queue_mutex);
389 mem_sys_free(queue);
394 =back
396 =head1 SEE ALSO
398 F<include/parrot/tsq.h>.
400 =cut
406 * Local variables:
407 * c-file-style: "parrot"
408 * End:
409 * vim: expandtab shiftwidth=4: