1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-message-queue.c: Message queue
5 * Copyright (C) 2003 Novell, Inc.
6 * Copyright (C) 2008 Red Hat, Inc.
13 #include "soup-message-queue.h"
16 * SECTION:soup-message-queue
18 * This is an internal structure used by #SoupSession and its
19 * subclasses to keep track of the status of messages currently being
22 * The #SoupMessageQueue itself is mostly just a linked list of
23 * #SoupMessageQueueItem, with some added cleverness to allow the list
24 * to be walked safely while other threads / re-entrant loops are
25 * adding items to and removing items from it. In particular, this is
26 * handled by refcounting items and then keeping "removed" items in
27 * the list until their ref_count drops to 0, but skipping over the
28 * "removed" ones when walking the queue.
31 struct SoupMessageQueue {
35 SoupMessageQueueItem *head, *tail;
39 soup_message_queue_new (SoupSession *session)
41 SoupMessageQueue *queue;
43 queue = g_slice_new0 (SoupMessageQueue);
44 queue->session = session;
45 queue->mutex = g_mutex_new ();
50 soup_message_queue_destroy (SoupMessageQueue *queue)
52 g_return_if_fail (queue->head == NULL);
54 g_mutex_free (queue->mutex);
55 g_slice_free (SoupMessageQueue, queue);
59 * soup_message_queue_append:
60 * @queue: a #SoupMessageQueue
61 * @msg: a #SoupMessage
62 * @callback: the callback for @msg
63 * @user_data: the data to pass to @callback
65 * Creates a new #SoupMessageQueueItem and appends it to @queue.
67 * Return value: the new item, which you must unref with
68 * soup_message_queue_unref_item() when you are done with.
70 SoupMessageQueueItem *
71 soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg,
72 SoupSessionCallback callback, gpointer user_data)
74 SoupMessageQueueItem *item;
76 item = g_slice_new0 (SoupMessageQueueItem);
77 item->session = queue->session;
79 item->msg = g_object_ref (msg);
80 item->callback = callback;
81 item->callback_data = user_data;
82 item->cancellable = g_cancellable_new ();
84 /* Note: the initial ref_count of 1 represents the caller's
85 * ref; the queue's own ref is indicated by the absence of the
90 g_mutex_lock (queue->mutex);
92 queue->tail->next = item;
93 item->prev = queue->tail;
96 queue->head = queue->tail = item;
98 g_mutex_unlock (queue->mutex);
103 * soup_message_queue_item_ref:
104 * @item: a #SoupMessageQueueItem
109 soup_message_queue_item_ref (SoupMessageQueueItem *item)
115 * soup_message_queue_item_unref:
116 * @item: a #SoupMessageQueueItem
118 * Unrefs @item; use this on a #SoupMessageQueueItem that you are done
119 * with (but that you aren't passing to
120 * soup_message_queue_item_next()).
123 soup_message_queue_item_unref (SoupMessageQueueItem *item)
125 g_mutex_lock (item->queue->mutex);
127 /* Decrement the ref_count; if it's still non-zero OR if the
128 * item is still in the queue, then return.
130 if (--item->ref_count || !item->removed) {
131 g_mutex_unlock (item->queue->mutex);
135 /* OK, @item is dead. Rewrite @queue around it */
137 item->prev->next = item->next;
139 item->queue->head = item->next;
141 item->next->prev = item->prev;
143 item->queue->tail = item->prev;
145 g_mutex_unlock (item->queue->mutex);
148 g_object_unref (item->msg);
149 g_object_unref (item->cancellable);
151 g_object_unref (item->msg_addr);
152 g_slice_free (SoupMessageQueueItem, item);
156 * soup_message_queue_lookup:
157 * @queue: a #SoupMessageQueue
158 * @msg: a #SoupMessage
160 * Finds the #SoupMessageQueueItem for @msg in @queue. You must unref
161 * the item with soup_message_queue_unref_item() when you are done
164 * Return value: the queue item for @msg, or %NULL
166 SoupMessageQueueItem *
167 soup_message_queue_lookup (SoupMessageQueue *queue, SoupMessage *msg)
169 SoupMessageQueueItem *item;
171 g_mutex_lock (queue->mutex);
174 while (item && (item->removed || item->msg != msg))
180 g_mutex_unlock (queue->mutex);
185 * soup_message_queue_first:
186 * @queue: a #SoupMessageQueue
188 * Gets the first item in @queue. You must unref the item by calling
189 * soup_message_queue_unref_item() on it when you are done.
190 * (soup_message_queue_next() does this for you automatically, so you
191 * only need to unref the item yourself if you are not going to
192 * finishing walking the queue.)
194 * Return value: the first item in @queue.
196 SoupMessageQueueItem *
197 soup_message_queue_first (SoupMessageQueue *queue)
199 SoupMessageQueueItem *item;
201 g_mutex_lock (queue->mutex);
204 while (item && item->removed)
210 g_mutex_unlock (queue->mutex);
215 * soup_message_queue_next:
216 * @queue: a #SoupMessageQueue
217 * @item: a #SoupMessageQueueItem
219 * Unrefs @item and gets the next item after it in @queue. As with
220 * soup_message_queue_first(), you must unref the returned item
221 * yourself with soup_message_queue_unref_item() if you do not finish
224 * Return value: the next item in @queue.
226 SoupMessageQueueItem *
227 soup_message_queue_next (SoupMessageQueue *queue, SoupMessageQueueItem *item)
229 SoupMessageQueueItem *next;
231 g_mutex_lock (queue->mutex);
234 while (next && next->removed)
239 g_mutex_unlock (queue->mutex);
240 soup_message_queue_item_unref (item);
245 * soup_message_queue_remove:
246 * @queue: a #SoupMessageQueue
247 * @item: a #SoupMessageQueueItem
249 * Removes @item from @queue. Note that you probably also need to call
250 * soup_message_queue_unref_item() after this.
253 soup_message_queue_remove (SoupMessageQueue *queue, SoupMessageQueueItem *item)
255 g_mutex_lock (queue->mutex);
256 item->removed = TRUE;
257 g_mutex_unlock (queue->mutex);