|
Packit Service |
ca3877 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
Packit Service |
ca3877 |
/*
|
|
Packit Service |
ca3877 |
* soup-message-queue.c: Message queue
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Copyright (C) 2003 Novell, Inc.
|
|
Packit Service |
ca3877 |
* Copyright (C) 2008 Red Hat, Inc.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
ca3877 |
#include <config.h>
|
|
Packit Service |
ca3877 |
#endif
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include "soup-message-queue.h"
|
|
Packit Service |
ca3877 |
#include "soup.h"
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* This is an internal structure used by #SoupSession and its
|
|
Packit Service |
ca3877 |
* subclasses to keep track of the status of messages currently being
|
|
Packit Service |
ca3877 |
* processed.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* The #SoupMessageQueue itself is mostly just a linked list of
|
|
Packit Service |
ca3877 |
* #SoupMessageQueueItem, with some added cleverness to allow the list
|
|
Packit Service |
ca3877 |
* to be walked safely while other threads / re-entrant loops are
|
|
Packit Service |
ca3877 |
* adding items to and removing items from it. In particular, this is
|
|
Packit Service |
ca3877 |
* handled by refcounting items and then keeping "removed" items in
|
|
Packit Service |
ca3877 |
* the list until their ref_count drops to 0, but skipping over the
|
|
Packit Service |
ca3877 |
* "removed" ones when walking the queue.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
struct _SoupMessageQueue {
|
|
Packit Service |
ca3877 |
SoupSession *session;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GMutex mutex;
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *head, *tail;
|
|
Packit Service |
ca3877 |
};
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
SoupMessageQueue *
|
|
Packit Service |
ca3877 |
soup_message_queue_new (SoupSession *session)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueue *queue;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
queue = g_slice_new0 (SoupMessageQueue);
|
|
Packit Service |
ca3877 |
queue->session = session;
|
|
Packit Service |
ca3877 |
g_mutex_init (&queue->mutex);
|
|
Packit Service |
ca3877 |
return queue;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_message_queue_destroy (SoupMessageQueue *queue)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_if_fail (queue->head == NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_clear (&queue->mutex);
|
|
Packit Service |
ca3877 |
g_slice_free (SoupMessageQueue, queue);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
queue_message_restarted (SoupMessage *msg, gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *item = user_data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_cancellable_reset (item->cancellable);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_append:
|
|
Packit Service |
ca3877 |
* @queue: a #SoupMessageQueue
|
|
Packit Service |
ca3877 |
* @msg: a #SoupMessage
|
|
Packit Service |
ca3877 |
* @callback: the callback for @msg
|
|
Packit Service |
ca3877 |
* @user_data: the data to pass to @callback
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Creates a new #SoupMessageQueueItem and appends it to @queue.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Return value: the new item, which you must unref with
|
|
Packit Service |
ca3877 |
* soup_message_queue_unref_item() when you are done with.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *
|
|
Packit Service |
ca3877 |
soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg,
|
|
Packit Service |
ca3877 |
SoupSessionCallback callback, gpointer user_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *item;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
item = g_slice_new0 (SoupMessageQueueItem);
|
|
Packit Service |
ca3877 |
item->session = g_object_ref (queue->session);
|
|
Packit Service |
ca3877 |
item->async_context = soup_session_get_async_context (item->session);
|
|
Packit Service |
ca3877 |
if (item->async_context)
|
|
Packit Service |
ca3877 |
g_main_context_ref (item->async_context);
|
|
Packit Service |
ca3877 |
item->queue = queue;
|
|
Packit Service |
ca3877 |
item->msg = g_object_ref (msg);
|
|
Packit Service |
ca3877 |
item->callback = callback;
|
|
Packit Service |
ca3877 |
item->callback_data = user_data;
|
|
Packit Service |
ca3877 |
item->cancellable = g_cancellable_new ();
|
|
Packit Service |
ca3877 |
item->priority = soup_message_get_priority (msg);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_signal_connect (msg, "restarted",
|
|
Packit Service |
ca3877 |
G_CALLBACK (queue_message_restarted), item);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Note: the initial ref_count of 1 represents the caller's
|
|
Packit Service |
ca3877 |
* ref; the queue's own ref is indicated by the absence of the
|
|
Packit Service |
ca3877 |
* "removed" flag.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
item->ref_count = 1;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_lock (&queue->mutex);
|
|
Packit Service |
ca3877 |
if (queue->head) {
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *it = queue->head;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
while (it && it->priority >= item->priority)
|
|
Packit Service |
ca3877 |
it = it->next;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!it) {
|
|
Packit Service |
ca3877 |
if (queue->tail) {
|
|
Packit Service |
ca3877 |
queue->tail->next = item;
|
|
Packit Service |
ca3877 |
item->prev = queue->tail;
|
|
Packit Service |
ca3877 |
} else
|
|
Packit Service |
ca3877 |
queue->head = item;
|
|
Packit Service |
ca3877 |
queue->tail = item;
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
if (it != queue->head)
|
|
Packit Service |
ca3877 |
it->prev->next = item;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
queue->head = item;
|
|
Packit Service |
ca3877 |
item->prev = it->prev;
|
|
Packit Service |
ca3877 |
it->prev = item;
|
|
Packit Service |
ca3877 |
item->next = it;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
} else
|
|
Packit Service |
ca3877 |
queue->head = queue->tail = item;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&queue->mutex);
|
|
Packit Service |
ca3877 |
return item;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_item_ref:
|
|
Packit Service |
ca3877 |
* @item: a #SoupMessageQueueItem
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Refs @item.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_message_queue_item_ref (SoupMessageQueueItem *item)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_mutex_lock (&item->queue->mutex);
|
|
Packit Service |
ca3877 |
item->ref_count++;
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&item->queue->mutex);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_item_unref:
|
|
Packit Service |
ca3877 |
* @item: a #SoupMessageQueueItem
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Unrefs @item; use this on a #SoupMessageQueueItem that you are done
|
|
Packit Service |
ca3877 |
* with (but that you aren't passing to
|
|
Packit Service |
ca3877 |
* soup_message_queue_item_next()).
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_message_queue_item_unref (SoupMessageQueueItem *item)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_mutex_lock (&item->queue->mutex);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Decrement the ref_count; if it's still non-zero OR if the
|
|
Packit Service |
ca3877 |
* item is still in the queue, then return.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
if (--item->ref_count || !item->removed) {
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&item->queue->mutex);
|
|
Packit Service |
ca3877 |
return;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_warn_if_fail (item->conn == NULL);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* OK, @item is dead. Rewrite @queue around it */
|
|
Packit Service |
ca3877 |
if (item->prev)
|
|
Packit Service |
ca3877 |
item->prev->next = item->next;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
item->queue->head = item->next;
|
|
Packit Service |
ca3877 |
if (item->next)
|
|
Packit Service |
ca3877 |
item->next->prev = item->prev;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
item->queue->tail = item->prev;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&item->queue->mutex);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* And free it */
|
|
Packit Service |
ca3877 |
g_signal_handlers_disconnect_by_func (item->msg,
|
|
Packit Service |
ca3877 |
queue_message_restarted, item);
|
|
Packit Service |
ca3877 |
g_object_unref (item->session);
|
|
Packit Service |
ca3877 |
g_object_unref (item->msg);
|
|
Packit Service |
ca3877 |
g_object_unref (item->cancellable);
|
|
Packit Service |
ca3877 |
g_clear_error (&item->error);
|
|
Packit Service |
ca3877 |
g_clear_object (&item->task);
|
|
Packit Service |
ca3877 |
g_clear_pointer (&item->async_context, g_main_context_unref);
|
|
Packit Service |
ca3877 |
if (item->io_source) {
|
|
Packit Service |
ca3877 |
g_source_destroy (item->io_source);
|
|
Packit Service |
ca3877 |
g_source_unref (item->io_source);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
g_slice_free (SoupMessageQueueItem, item);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_lookup:
|
|
Packit Service |
ca3877 |
* @queue: a #SoupMessageQueue
|
|
Packit Service |
ca3877 |
* @msg: a #SoupMessage
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Finds the #SoupMessageQueueItem for @msg in @queue. You must unref
|
|
Packit Service |
ca3877 |
* the item with soup_message_queue_unref_item() when you are done
|
|
Packit Service |
ca3877 |
* with it.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Return value: (nullable): the queue item for @msg, or %NULL
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *
|
|
Packit Service |
ca3877 |
soup_message_queue_lookup (SoupMessageQueue *queue, SoupMessage *msg)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *item;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_lock (&queue->mutex);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
item = queue->tail;
|
|
Packit Service |
ca3877 |
while (item && (item->removed || item->msg != msg))
|
|
Packit Service |
ca3877 |
item = item->prev;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (item)
|
|
Packit Service |
ca3877 |
item->ref_count++;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&queue->mutex);
|
|
Packit Service |
ca3877 |
return item;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_first:
|
|
Packit Service |
ca3877 |
* @queue: a #SoupMessageQueue
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Gets the first item in @queue. You must unref the item by calling
|
|
Packit Service |
ca3877 |
* soup_message_queue_unref_item() on it when you are done.
|
|
Packit Service |
ca3877 |
* (soup_message_queue_next() does this for you automatically, so you
|
|
Packit Service |
ca3877 |
* only need to unref the item yourself if you are not going to
|
|
Packit Service |
ca3877 |
* finishing walking the queue.)
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Return value: the first item in @queue.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *
|
|
Packit Service |
ca3877 |
soup_message_queue_first (SoupMessageQueue *queue)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *item;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_lock (&queue->mutex);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
item = queue->head;
|
|
Packit Service |
ca3877 |
while (item && item->removed)
|
|
Packit Service |
ca3877 |
item = item->next;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (item)
|
|
Packit Service |
ca3877 |
item->ref_count++;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&queue->mutex);
|
|
Packit Service |
ca3877 |
return item;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_next:
|
|
Packit Service |
ca3877 |
* @queue: a #SoupMessageQueue
|
|
Packit Service |
ca3877 |
* @item: a #SoupMessageQueueItem
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Unrefs @item and gets the next item after it in @queue. As with
|
|
Packit Service |
ca3877 |
* soup_message_queue_first(), you must unref the returned item
|
|
Packit Service |
ca3877 |
* yourself with soup_message_queue_unref_item() if you do not finish
|
|
Packit Service |
ca3877 |
* walking the queue.
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Return value: the next item in @queue.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *
|
|
Packit Service |
ca3877 |
soup_message_queue_next (SoupMessageQueue *queue, SoupMessageQueueItem *item)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupMessageQueueItem *next;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_lock (&queue->mutex);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
next = item->next;
|
|
Packit Service |
ca3877 |
while (next && next->removed)
|
|
Packit Service |
ca3877 |
next = next->next;
|
|
Packit Service |
ca3877 |
if (next)
|
|
Packit Service |
ca3877 |
next->ref_count++;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&queue->mutex);
|
|
Packit Service |
ca3877 |
soup_message_queue_item_unref (item);
|
|
Packit Service |
ca3877 |
return next;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/**
|
|
Packit Service |
ca3877 |
* soup_message_queue_remove:
|
|
Packit Service |
ca3877 |
* @queue: a #SoupMessageQueue
|
|
Packit Service |
ca3877 |
* @item: a #SoupMessageQueueItem
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Removes @item from @queue. Note that you probably also need to call
|
|
Packit Service |
ca3877 |
* soup_message_queue_unref_item() after this.
|
|
Packit Service |
ca3877 |
**/
|
|
Packit Service |
ca3877 |
void
|
|
Packit Service |
ca3877 |
soup_message_queue_remove (SoupMessageQueue *queue, SoupMessageQueueItem *item)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
g_return_if_fail (!item->removed);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_mutex_lock (&queue->mutex);
|
|
Packit Service |
ca3877 |
item->removed = TRUE;
|
|
Packit Service |
ca3877 |
g_mutex_unlock (&queue->mutex);
|
|
Packit Service |
ca3877 |
}
|