summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergio Villar Senin <svillar@igalia.com>2013-04-17 10:15:59 +0200
committerSergio Villar Senin <svillar@igalia.com>2013-04-17 10:15:59 +0200
commitc146806dc176f81be0c7554d67f9e981ee07a3b9 (patch)
tree5bf04d9031d62004739b2082f3d85c51b880f665
parentd61e68e5187224f5b6e0ad4a0060b22d07ba0b64 (diff)
downloadlibsoup-c146806dc176f81be0c7554d67f9e981ee07a3b9.tar.gz
libsoup-c146806dc176f81be0c7554d67f9e981ee07a3b9.tar.bz2
libsoup-c146806dc176f81be0c7554d67f9e981ee07a3b9.zip
soup-message-queue: add a priority system to the message queue
Clients can specify a priority for each message added to the SoupSession, which will determine the order in which it is processed by the session's message processing queue. https://bugzilla.gnome.org/show_bug.cgi?id=696277
-rw-r--r--docs/reference/libsoup-2.4-sections.txt5
-rw-r--r--libsoup/libsoup-2.4.sym3
-rw-r--r--libsoup/soup-message-private.h2
-rw-r--r--libsoup/soup-message-queue.c25
-rw-r--r--libsoup/soup-message-queue.h3
-rw-r--r--libsoup/soup-message.c91
-rw-r--r--libsoup/soup-message.h18
-rw-r--r--tests/session-test.c57
8 files changed, 200 insertions, 4 deletions
diff --git a/docs/reference/libsoup-2.4-sections.txt b/docs/reference/libsoup-2.4-sections.txt
index 9a856429..4b6ebfd9 100644
--- a/docs/reference/libsoup-2.4-sections.txt
+++ b/docs/reference/libsoup-2.4-sections.txt
@@ -37,6 +37,10 @@ soup_message_set_chunk_allocator
soup_message_disable_feature
soup_message_get_soup_request
<SUBSECTION>
+SoupMessagePriority
+soup_message_get_priority
+soup_message_set_priority
+<SUBSECTION>
SOUP_MESSAGE_METHOD
SOUP_MESSAGE_URI
SOUP_MESSAGE_HTTP_VERSION
@@ -45,6 +49,7 @@ SOUP_MESSAGE_STATUS_CODE
SOUP_MESSAGE_REASON_PHRASE
SOUP_MESSAGE_SERVER_SIDE
SOUP_MESSAGE_FIRST_PARTY
+SOUP_MESSAGE_PRIORITY
SOUP_MESSAGE_REQUEST_BODY
SOUP_MESSAGE_REQUEST_HEADERS
SOUP_MESSAGE_RESPONSE_BODY
diff --git a/libsoup/libsoup-2.4.sym b/libsoup/libsoup-2.4.sym
index 22af1601..d0f22f6e 100644
--- a/libsoup/libsoup-2.4.sym
+++ b/libsoup/libsoup-2.4.sym
@@ -231,6 +231,7 @@ soup_message_get_first_party
soup_message_get_flags
soup_message_get_https_status
soup_message_get_http_version
+soup_message_get_priority
soup_message_get_soup_request
soup_message_get_type
soup_message_get_uri
@@ -273,11 +274,13 @@ soup_message_io_cleanup
soup_message_is_keepalive
soup_message_new
soup_message_new_from_uri
+soup_message_priority_get_type
soup_message_restarted
soup_message_set_chunk_allocator
soup_message_set_first_party
soup_message_set_flags
soup_message_set_http_version
+soup_message_set_priority
soup_message_set_redirect
soup_message_set_request
soup_message_set_response
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index de7cb7d0..356b96db 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -41,6 +41,8 @@ typedef struct {
GTlsCertificateFlags tls_errors;
SoupRequest *request;
+
+ SoupMessagePriority priority;
} SoupMessagePrivate;
#define SOUP_MESSAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_MESSAGE, SoupMessagePrivate))
diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 8b1ebaf9..3dced0e4 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -89,6 +89,7 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg,
item->callback = callback;
item->callback_data = user_data;
item->cancellable = g_cancellable_new ();
+ item->priority = soup_message_get_priority (msg);
g_signal_connect (msg, "restarted",
G_CALLBACK (queue_message_restarted), item);
@@ -101,9 +102,27 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg,
g_mutex_lock (&queue->mutex);
if (queue->head) {
- queue->tail->next = item;
- item->prev = queue->tail;
- queue->tail = item;
+ SoupMessageQueueItem *it = queue->head;
+
+ while (it && it->priority >= item->priority)
+ it = it->next;
+
+ if (!it) {
+ if (queue->tail) {
+ queue->tail->next = item;
+ item->prev = queue->tail;
+ } else
+ queue->head = item;
+ queue->tail = item;
+ } else {
+ if (it != queue->head)
+ it->prev->next = item;
+ else
+ queue->head = item;
+ item->prev = it->prev;
+ it->prev = item;
+ item->next = it;
+ }
} else
queue->head = queue->tail = item;
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index 135a6aac..d965e513 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -52,7 +52,8 @@ struct _SoupMessageQueueItem {
/*< private >*/
guint removed : 1;
- guint ref_count : 31;
+ guint priority : 3;
+ guint ref_count : 28;
SoupMessageQueueItem *prev, *next;
SoupMessageQueueItem *related;
};
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index d30fd372..b65dd76b 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -135,6 +135,7 @@ enum {
PROP_RESPONSE_HEADERS,
PROP_TLS_CERTIFICATE,
PROP_TLS_ERRORS,
+ PROP_PRIORITY,
LAST_PROP
};
@@ -145,6 +146,7 @@ soup_message_init (SoupMessage *msg)
SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
priv->http_version = priv->orig_http_version = SOUP_HTTP_1_1;
+ priv->priority = SOUP_MESSAGE_PRIORITY_NORMAL;
msg->request_body = soup_message_body_new ();
msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
@@ -236,6 +238,9 @@ soup_message_set_property (GObject *object, guint prop_id,
else if (priv->tls_certificate)
priv->msg_flags |= SOUP_MESSAGE_CERTIFICATE_TRUSTED;
break;
+ case PROP_PRIORITY:
+ priv->priority = g_value_get_enum (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -292,6 +297,9 @@ soup_message_get_property (GObject *object, guint prop_id,
case PROP_TLS_ERRORS:
g_value_set_flags (value, priv->tls_errors);
break;
+ case PROP_PRIORITY:
+ g_value_set_enum (value, priv->priority);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -857,6 +865,22 @@ soup_message_class_init (SoupMessageClass *message_class)
"The verification errors on the message's TLS certificate",
G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
G_PARAM_READWRITE));
+ /**
+ * SOUP_MESSAGE_PRIORITY:
+ *
+ * Sets the priority of the #SoupMessage. See
+ * soup_message_set_priority() for further details.
+ *
+ * Since: 2.44
+ **/
+ g_object_class_install_property (
+ object_class, PROP_PRIORITY,
+ g_param_spec_enum (SOUP_MESSAGE_PRIORITY,
+ "Priority",
+ "The priority of the message",
+ SOUP_TYPE_MESSAGE_PRIORITY,
+ SOUP_MESSAGE_PRIORITY_NORMAL,
+ G_PARAM_READWRITE));
}
@@ -1917,3 +1941,70 @@ soup_message_get_soup_request (SoupMessage *msg)
return priv->request;
}
+/**
+ * SoupMessagePriority:
+ * @SOUP_MESSAGE_PRIORITY_VERY_LOW: The lowest priority, the messages
+ * with this priority will be the last ones to be attended.
+ * @SOUP_MESSAGE_PRIORITY_LOW: Use this for low priority messages, a
+ * #SoupMessage with the default priority will be processed first.
+ * @SOUP_MESSAGE_PRIORITY_NORMAL: The default priotity, this is the
+ * priority assigned to the #SoupMessage by default.
+ * @SOUP_MESSAGE_PRIORITY_HIGH: High priority, a #SoupMessage with
+ * this priority will be processed before the ones with the default
+ * priority.
+ * @SOUP_MESSAGE_PRIORITY_VERY_HIGH: The highest priority, use this
+ * for very urgent #SoupMessage as they will be the first ones to be
+ * attended.
+ *
+ * Priorities that can be set on a #SoupMessage to instruct the
+ * message queue to process it before any other message with lower
+ * priority.
+ **/
+
+/**
+ * soup_message_set_priority:
+ * @msg: a #SoupMessage
+ * @priority: the #SoupMessagePriority
+ *
+ * Sets the priority of a message. Note that this won't have any
+ * effect unless used before the message is added to the session's
+ * message processing queue.
+ *
+ * The message will be placed just before any other previously added
+ * message with lower priority (messages with the same priority are
+ * processed on a FIFO basis).
+ *
+ * Setting priorities does not currently work with #SoupSessionSync
+ * (or with synchronous messages on a plain #SoupSession) because in
+ * the synchronous/blocking case, priority ends up being determined
+ * semi-randomly by thread scheduling.
+ *
+ * Since: 2.44
+ */
+void
+soup_message_set_priority (SoupMessage *msg,
+ SoupMessagePriority priority)
+{
+ g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+ g_object_set (msg, SOUP_MESSAGE_PRIORITY, priority, NULL);
+}
+
+/**
+ * soup_message_get_priority:
+ * @msg: a #SoupMessage
+ *
+ * Retrieves the #SoupMessagePriority. If not set this value defaults
+ * to #SOUP_MESSAGE_PRIORITY_NORMAL.
+ *
+ * Return value: the priority of the message.
+ *
+ * Since: 2.44
+ */
+SoupMessagePriority
+soup_message_get_priority (SoupMessage *msg)
+{
+ g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_MESSAGE_PRIORITY_NORMAL);
+
+ return SOUP_MESSAGE_GET_PRIVATE (msg)->priority;
+}
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index 23ec024a..22c2b1ed 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -74,6 +74,7 @@ GType soup_message_get_type (void);
#define SOUP_MESSAGE_RESPONSE_HEADERS "response-headers"
#define SOUP_MESSAGE_TLS_CERTIFICATE "tls-certificate"
#define SOUP_MESSAGE_TLS_ERRORS "tls-errors"
+#define SOUP_MESSAGE_PRIORITY "priority"
SoupMessage *soup_message_new (const char *method,
const char *uri_string);
@@ -186,6 +187,23 @@ void soup_message_disable_feature (SoupMessage *msg,
SOUP_AVAILABLE_IN_2_42
SoupRequest *soup_message_get_soup_request (SoupMessage *msg);
+
+typedef enum {
+ SOUP_MESSAGE_PRIORITY_VERY_LOW = 0,
+ SOUP_MESSAGE_PRIORITY_LOW,
+ SOUP_MESSAGE_PRIORITY_NORMAL,
+ SOUP_MESSAGE_PRIORITY_HIGH,
+ SOUP_MESSAGE_PRIORITY_VERY_HIGH
+} SoupMessagePriority;
+
+SOUP_AVAILABLE_IN_2_44
+void soup_message_set_priority (SoupMessage *msg,
+ SoupMessagePriority priority);
+
+
+SOUP_AVAILABLE_IN_2_44
+SoupMessagePriority soup_message_get_priority (SoupMessage *msg);
+
void soup_message_wrote_informational (SoupMessage *msg);
void soup_message_wrote_headers (SoupMessage *msg);
void soup_message_wrote_chunk (SoupMessage *msg);
diff --git a/tests/session-test.c b/tests/session-test.c
index 3207797e..b8e224ea 100644
--- a/tests/session-test.c
+++ b/tests/session-test.c
@@ -5,6 +5,7 @@
static gboolean server_processed_message;
static gboolean timeout;
static GMainLoop *loop;
+static SoupMessagePriority expected_priorities[3];
static gboolean
timeout_cb (gpointer user_data)
@@ -207,6 +208,61 @@ do_sync_tests (char *uri, char *timeout_uri)
soup_test_session_abort_unref (session);
}
+static void
+priority_test_finished_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ guint *finished_count = user_data;
+ SoupMessagePriority priority = soup_message_get_priority (msg);
+
+ if (priority != expected_priorities[*finished_count]) {
+ debug_printf (1, " message %d should have priority %d (%d found)\n",
+ *finished_count, expected_priorities[*finished_count], priority);
+ errors++;
+ } else
+ debug_printf (1, " received message %d with priority %d\n",
+ *finished_count, priority);
+
+ (*finished_count)++;
+}
+
+static void
+do_priority_tests (char *uri)
+{
+ SoupSession *session;
+ int i, finished_count = 0;
+ SoupMessagePriority priorities[] =
+ { SOUP_MESSAGE_PRIORITY_LOW,
+ SOUP_MESSAGE_PRIORITY_HIGH,
+ SOUP_MESSAGE_PRIORITY_NORMAL };
+
+ debug_printf (1, "\nSoupSessionAsync\n");
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+ g_object_set (session, "max-conns", 1, NULL);
+
+ expected_priorities[0] = SOUP_MESSAGE_PRIORITY_HIGH;
+ expected_priorities[1] = SOUP_MESSAGE_PRIORITY_NORMAL;
+ expected_priorities[2] = SOUP_MESSAGE_PRIORITY_LOW;
+
+ for (i = 0; i < 3; i++) {
+ char *msg_uri;
+ SoupMessage *msg;
+
+ msg_uri = g_strdup_printf ("%s/%d", uri, i);
+ msg = soup_message_new ("GET", uri);
+ g_free (msg_uri);
+
+ soup_message_set_priority (msg, priorities[i]);
+ soup_session_queue_message (session, msg, priority_test_finished_cb, &finished_count);
+ }
+
+ debug_printf (2, " waiting for finished\n");
+ while (finished_count != 3)
+ g_main_context_iteration (NULL, TRUE);
+
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
@@ -224,6 +280,7 @@ main (int argc, char **argv)
do_plain_tests (uri, timeout_uri);
do_async_tests (uri, timeout_uri);
do_sync_tests (uri, timeout_uri);
+ do_priority_tests (uri);
g_free (uri);
g_free (timeout_uri);