applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[platform/upstream/glib.git] / glib / gasyncqueue.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GAsyncQueue: asyncronous queue implementation, based on Gqueue.
5  * Copyright (C) 2000 Sebastian Wilhelmi; University of Karlsruhe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * MT safe
25  */
26
27 #include "glib.h"
28
29 struct _GAsyncQueue
30 {
31   GMutex *mutex;
32   GCond *cond;
33   GQueue *queue;
34   guint waiting_threads;
35   guint ref_count;
36 };
37
38 GAsyncQueue*
39 g_async_queue_new ()
40 {
41   GAsyncQueue* retval = g_new (GAsyncQueue, 1);
42   retval->mutex = g_mutex_new ();
43   retval->cond = g_cond_new ();
44   retval->queue = g_queue_new ();
45   retval->waiting_threads = 0;
46   retval->ref_count = 1;
47   return retval;
48 }
49
50 void 
51 g_async_queue_ref (GAsyncQueue *queue)
52 {
53   g_return_if_fail (queue);
54   g_return_if_fail (queue->ref_count > 0);
55   
56   g_mutex_lock (queue->mutex);
57   queue->ref_count++;
58   g_mutex_unlock (queue->mutex);
59 }
60
61 void 
62 g_async_queue_ref_unlocked (GAsyncQueue *queue)
63 {
64   g_return_if_fail (queue);
65   g_return_if_fail (queue->ref_count > 0);
66   
67   queue->ref_count++;
68 }
69
70 void 
71 g_async_queue_unref_and_unlock (GAsyncQueue *queue)
72 {
73   gboolean stop;
74
75   g_return_if_fail (queue);
76   g_return_if_fail (queue->ref_count > 0);
77
78   queue->ref_count--;
79   stop = (queue->ref_count == 0);
80   g_mutex_unlock (queue->mutex);
81   
82   if (stop)
83     {
84       g_return_if_fail (queue->waiting_threads == 0);
85       g_mutex_free (queue->mutex);
86       g_cond_free (queue->cond);
87       g_queue_free (queue->queue);
88       g_free (queue);
89     }
90 }
91
92 void 
93 g_async_queue_unref (GAsyncQueue *queue)
94 {
95   g_return_if_fail (queue);
96   g_return_if_fail (queue->ref_count > 0);
97
98   g_mutex_lock (queue->mutex);
99   g_async_queue_unref_and_unlock (queue);
100 }
101
102 void
103 g_async_queue_lock (GAsyncQueue *queue)
104 {
105   g_return_if_fail (queue);
106   g_return_if_fail (queue->ref_count > 0);
107
108   g_mutex_lock (queue->mutex);
109 }
110
111 void 
112 g_async_queue_unlock (GAsyncQueue *queue)
113 {
114   g_return_if_fail (queue);
115   g_return_if_fail (queue->ref_count > 0);
116
117   g_mutex_unlock (queue->mutex);
118 }
119
120 void
121 g_async_queue_push (GAsyncQueue* queue, gpointer data)
122 {
123   g_return_if_fail (queue);
124   g_return_if_fail (queue->ref_count > 0);
125   g_return_if_fail (data);
126
127   g_mutex_lock (queue->mutex);
128   g_async_queue_push_unlocked (queue, data);
129   g_mutex_unlock (queue->mutex);
130 }
131
132 void
133 g_async_queue_push_unlocked (GAsyncQueue* queue, gpointer data)
134 {
135   g_return_if_fail (queue);
136   g_return_if_fail (queue->ref_count > 0);
137   g_return_if_fail (data);
138
139   g_queue_push_head (queue->queue, data);
140   g_cond_signal (queue->cond);
141 }
142
143 static gpointer
144 g_async_queue_pop_intern_unlocked (GAsyncQueue* queue, gboolean try, 
145                                    GTimeVal *end_time)
146 {
147   gpointer retval;
148
149   if (!g_queue_peek_tail (queue->queue))
150     {
151       if (try)
152         return NULL;
153       if (!end_time)
154         {
155           queue->waiting_threads++;
156           while (!g_queue_peek_tail (queue->queue))
157             g_cond_wait(queue->cond, queue->mutex);
158           queue->waiting_threads--;
159         }
160       else
161         {
162           queue->waiting_threads++;
163           while (!g_queue_peek_tail (queue->queue))
164             if (!g_cond_timed_wait (queue->cond, queue->mutex, end_time))
165               break;
166           queue->waiting_threads--;
167           if (!g_queue_peek_tail (queue->queue))
168             return NULL;
169         }
170     }
171
172   retval = g_queue_pop_tail (queue->queue);
173
174   g_assert (retval);
175
176   return retval;
177 }
178
179 gpointer
180 g_async_queue_pop (GAsyncQueue* queue)
181 {
182   gpointer retval;
183
184   g_return_val_if_fail (queue, NULL);
185   g_return_val_if_fail (queue->ref_count > 0, NULL);
186
187   g_mutex_lock (queue->mutex);
188   retval = g_async_queue_pop_intern_unlocked (queue, FALSE, NULL);
189   g_mutex_unlock (queue->mutex);
190
191   return retval;
192 }
193
194 gpointer
195 g_async_queue_pop_unlocked (GAsyncQueue* queue)
196 {
197   g_return_val_if_fail (queue, NULL);
198   g_return_val_if_fail (queue->ref_count > 0, NULL);
199
200   return g_async_queue_pop_intern_unlocked (queue, FALSE, NULL);
201 }
202
203 gpointer
204 g_async_queue_try_pop (GAsyncQueue* queue)
205 {
206   gpointer retval;
207
208   g_return_val_if_fail (queue, NULL);
209   g_return_val_if_fail (queue->ref_count > 0, NULL);
210
211   g_mutex_lock (queue->mutex);
212   retval = g_async_queue_pop_intern_unlocked (queue, TRUE, NULL);
213   g_mutex_unlock (queue->mutex);
214
215   return retval;
216 }
217
218 gpointer
219 g_async_queue_try_pop_unlocked (GAsyncQueue* queue)
220 {
221   g_return_val_if_fail (queue, NULL);
222   g_return_val_if_fail (queue->ref_count > 0, NULL);
223
224   return g_async_queue_pop_intern_unlocked (queue, TRUE, NULL);
225 }
226
227 gpointer
228 g_async_queue_timed_pop (GAsyncQueue* queue, GTimeVal *end_time)
229 {
230   gpointer retval;
231
232   g_return_val_if_fail (queue, NULL);
233   g_return_val_if_fail (queue->ref_count > 0, NULL);
234
235   g_mutex_lock (queue->mutex);
236   retval = g_async_queue_pop_intern_unlocked (queue, FALSE, end_time);
237   g_mutex_unlock (queue->mutex);
238
239   return retval;  
240 }
241
242 gpointer
243 g_async_queue_timed_pop_unlocked (GAsyncQueue* queue, GTimeVal *end_time)
244 {
245   g_return_val_if_fail (queue, NULL);
246   g_return_val_if_fail (queue->ref_count > 0, NULL);
247
248   return g_async_queue_pop_intern_unlocked (queue, FALSE, end_time);
249 }
250
251 gint
252 g_async_queue_length_unlocked (GAsyncQueue* queue)
253 {
254   g_return_val_if_fail (queue, 0);
255   g_return_val_if_fail (queue->ref_count > 0, 0);
256
257   return queue->queue->length - queue->waiting_threads;
258 }
259
260 gint
261 g_async_queue_length(GAsyncQueue* queue)
262 {
263   glong retval;
264
265   g_return_val_if_fail (queue, 0);
266   g_return_val_if_fail (queue->ref_count > 0, 0);
267
268   g_mutex_lock (queue->mutex);
269   retval = queue->queue->length - queue->waiting_threads;
270   g_mutex_unlock (queue->mutex);
271
272   return retval;
273 }
274