diff options
author | Sergio Villar Senin <svillar@igalia.com> | 2013-04-17 10:15:59 +0200 |
---|---|---|
committer | Sergio Villar Senin <svillar@igalia.com> | 2013-04-17 10:15:59 +0200 |
commit | c146806dc176f81be0c7554d67f9e981ee07a3b9 (patch) | |
tree | 5bf04d9031d62004739b2082f3d85c51b880f665 | |
parent | d61e68e5187224f5b6e0ad4a0060b22d07ba0b64 (diff) | |
download | libsoup-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.txt | 5 | ||||
-rw-r--r-- | libsoup/libsoup-2.4.sym | 3 | ||||
-rw-r--r-- | libsoup/soup-message-private.h | 2 | ||||
-rw-r--r-- | libsoup/soup-message-queue.c | 25 | ||||
-rw-r--r-- | libsoup/soup-message-queue.h | 3 | ||||
-rw-r--r-- | libsoup/soup-message.c | 91 | ||||
-rw-r--r-- | libsoup/soup-message.h | 18 | ||||
-rw-r--r-- | tests/session-test.c | 57 |
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); |