From b68bb9eb4e710cc55c1ada175a4f28b8412d8cc5 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 16 Jan 2014 10:35:43 +0100 Subject: [PATCH] update RECV ioctl and implement priority queues (ABI break) --- .gitignore | 1 + connection.c | 237 ++++++++++++++++++++++-------------- connection.h | 9 +- handle.c | 10 +- kdbus.h | 52 ++++++-- test/Makefile | 3 +- test/kdbus-util.c | 21 ++-- test/kdbus-util.h | 2 +- test/test-kdbus-activator.c | 4 +- test/test-kdbus-benchmark.c | 8 +- test/test-kdbus-chat.c | 6 +- test/test-kdbus-monitor.c | 9 +- test/test-kdbus-prio.c | 160 ++++++++++++++++++++++++ test/test-kdbus-timeout.c | 10 +- test/test-kdbus.c | 47 +++---- 15 files changed, 416 insertions(+), 163 deletions(-) create mode 100644 test/test-kdbus-prio.c diff --git a/.gitignore b/.gitignore index 0d2e6b5..18413ea 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ test/test-kdbus-monitor test/test-kdbus-activator test/test-kdbus-chat test/test-kdbus-timeout +test/test-kdbus-prio diff --git a/connection.c b/connection.c index c9f6f00..9a2998a 100644 --- a/connection.c +++ b/connection.c @@ -42,6 +42,8 @@ /** * struct kdbus_conn_queue - messages waiting to be read * @entry: Entry in the connection's list + * @prio_node: Entry in the priority queue tree + * @prio_entry: Queue tree node entry in the list of one priority * @off: Offset into the shmem file in the receiver's pool * @size: The number of bytes used in the pool * @memfds: Arrays of offsets where to update the installed @@ -58,6 +60,9 @@ */ struct kdbus_conn_queue { struct list_head entry; + struct rb_node prio_node; + struct list_head prio_entry; + s64 priority; size_t off; size_t size; @@ -319,6 +324,86 @@ static int kdbus_conn_payload_add(struct kdbus_conn *conn, return 0; } +/* add queue entry to connection, maintain priority queue */ +static void kdbus_conn_queue_add(struct kdbus_conn *conn, + struct kdbus_conn_queue *queue) +{ + struct rb_node **n; + struct rb_node *pn = NULL; + bool highest = true; + + /* sort into priority queue tree */ + n = &conn->msg_prio_queue.rb_node; + while (*n) { + struct kdbus_conn_queue *q; + + pn = *n; + q = rb_entry(pn, struct kdbus_conn_queue, prio_node); + + /* existing node for this priority, add to its list */ + if (likely(queue->priority == q->priority)) { + list_add_tail(&queue->prio_entry, &q->prio_entry); + goto prio_done; + } + + if (queue->priority < q->priority) { + n = &pn->rb_left; + } else { + n = &pn->rb_right; + highest = false; + } + } + + /* cache highest-priority entry */ + if (highest) + conn->msg_prio_highest = &queue->prio_node; + + /* new node for this priority */ + rb_link_node(&queue->prio_node, pn, n); + rb_insert_color(&queue->prio_node, &conn->msg_prio_queue); + INIT_LIST_HEAD(&queue->prio_entry); + +prio_done: + /* add to unsorted fifo list */ + list_add_tail(&queue->entry, &conn->msg_list); + conn->msg_count++; +} + +/* remove queue entry from connection, maintain priority queue */ +static void kdbus_conn_queue_remove(struct kdbus_conn *conn, + struct kdbus_conn_queue *queue) +{ + conn->msg_count--; + list_del(&queue->entry); + + if (list_empty(&queue->prio_entry)) { + /* + * Single entry for this priority, update cached + * highest-priority entry, remove the tree node. + */ + if (conn->msg_prio_highest == &queue->prio_node) + conn->msg_prio_highest = rb_next(&queue->prio_node); + + rb_erase(&queue->prio_node, &conn->msg_prio_queue); + } else { + struct kdbus_conn_queue *q; + + /* + * Multiple entries for this priority entry, get next one in + * the list. Update cached highest-priority entry, store the + * new one as the tree node. + */ + q = list_first_entry(&queue->prio_entry, + struct kdbus_conn_queue, prio_entry); + list_del(&queue->prio_entry); + + if (conn->msg_prio_highest == &queue->prio_node) + conn->msg_prio_highest = &q->prio_node; + + rb_replace_node(&queue->prio_node, &q->prio_node, &conn->msg_prio_queue); + } +} + static void kdbus_conn_queue_cleanup(struct kdbus_conn_queue *queue) { kdbus_conn_memfds_unref(queue); @@ -479,13 +564,13 @@ static int kdbus_conn_queue_insert(struct kdbus_conn *conn, goto exit_pool_free; } - /* remember the offset to the message */ + /* copy some properties of the message to the queue entry */ queue->off = off; queue->size = want; + queue->priority = kmsg->msg.priority; /* link the message into the receiver's queue */ - list_add_tail(&queue->entry, &conn->msg_list); - conn->msg_count++; + kdbus_conn_queue_add(conn, queue); mutex_unlock(&conn->lock); @@ -774,7 +859,6 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep, goto exit_unref; } - INIT_LIST_HEAD(&reply->entry); reply->conn = kdbus_conn_ref(conn_dst); reply->cookie = msg->cookie; @@ -966,12 +1050,14 @@ remove_unused: * * Returns: 0 on success, negative errno on failure. */ -int kdbus_conn_recv_msg(struct kdbus_conn *conn, __u64 __user *buf) +int kdbus_conn_recv_msg(struct kdbus_conn *conn, + struct kdbus_cmd_recv __user *recv_user) { - struct kdbus_conn_queue *queue; + struct kdbus_cmd_recv recv; + struct kdbus_conn_queue *queue = NULL; int *memfds = NULL; unsigned int i; - int ret; + int ret = 0; mutex_lock(&conn->lock); if (unlikely(conn->ep->disconnected)) { @@ -984,15 +1070,58 @@ int kdbus_conn_recv_msg(struct kdbus_conn *conn, __u64 __user *buf) goto exit_unlock; } - /* return the address of the next message in the pool */ - queue = list_first_entry(&conn->msg_list, - struct kdbus_conn_queue, entry); + if (copy_from_user(&recv, recv_user, + sizeof(struct kdbus_cmd_recv))) { + ret = -EFAULT; + goto exit_unlock; + } + + if (recv.offset > 0) { + ret = -EINVAL; + goto exit_unlock; + } + + if (recv.flags & KDBUS_RECV_USE_PRIORITY) { + /* get next message with highest priority */ + queue = rb_entry(conn->msg_prio_highest, + struct kdbus_conn_queue, prio_node); + + /* no entry with the requested priority */ + if (queue->priority > recv.priority) { + ret = -ENOMSG; + goto exit_unlock; + } + + } else { + /* ignore the priority, return the next entry in the queue */ + queue = list_first_entry(&conn->msg_list, + struct kdbus_conn_queue, entry); + } + + BUG_ON(!queue); - if (copy_to_user(buf, &queue->off, sizeof(__u64))) { + /* just drop the message */ + if (recv.flags & KDBUS_RECV_DROP) { + kdbus_conn_queue_remove(conn, queue); + kdbus_pool_free_range(conn->pool, queue->off); + kdbus_conn_queue_cleanup(queue); + goto exit_unlock; + } + + /* return the address of the next message in the pool */ + if (copy_to_user(&recv_user->offset, &queue->off, sizeof(__u64))) { ret = -EFAULT; goto exit_unlock; } + /* + * Just return the location of the next message. Do not install + * file descriptors or anything else. This is usually used to + * determine the sender of the next queued message. + */ + if (recv.flags & KDBUS_RECV_PEEK) + goto exit_unlock; + /* * Install KDBUS_MSG_PAYLOAD_MEMFDs file descriptors, we return * the list of file descriptors to be able to cleanup on error. @@ -1012,8 +1141,7 @@ int kdbus_conn_recv_msg(struct kdbus_conn *conn, __u64 __user *buf) kfree(memfds); - list_del(&queue->entry); - conn->msg_count--; + kdbus_conn_queue_remove(conn, queue); mutex_unlock(&conn->lock); kdbus_pool_flush_dcache(conn->pool, queue->off, queue->size); @@ -1030,82 +1158,6 @@ exit_unlock: return ret; } -/** - * kdbus_conn_drop_msg - receive a message from the queue - * @conn: Connection to work on - * - * Returns: 0 on success, negative errno on failure. - */ -int kdbus_conn_drop_msg(struct kdbus_conn *conn) -{ - struct kdbus_conn_queue *queue; - int ret; - - mutex_lock(&conn->lock); - if (unlikely(conn->ep->disconnected)) { - ret = -ECONNRESET; - goto exit_unlock; - } - - if (conn->msg_count == 0) { - ret = -EAGAIN; - goto exit_unlock; - } - - queue = list_first_entry(&conn->msg_list, - struct kdbus_conn_queue, entry); - list_del(&queue->entry); - conn->msg_count--; - - kdbus_pool_free_range(conn->pool, queue->off); - mutex_unlock(&conn->lock); - - kdbus_conn_queue_cleanup(queue); - return 0; - -exit_unlock: - mutex_unlock(&conn->lock); - return ret; -} - -/** - * kdbus_conn_src_msg - return the sender of a message in the queue - * @conn: Connection to work on - * @buf: The ID of the sender of the next message in the queue - * - * Returns: 0 on success, negative errno on failure. - */ -int kdbus_conn_src_msg(struct kdbus_conn *conn, __u64 __user *buf) -{ - struct kdbus_conn_queue *queue; - int ret; - - mutex_lock(&conn->lock); - if (unlikely(conn->ep->disconnected)) { - ret = -ECONNRESET; - goto exit_unlock; - } - - if (conn->msg_count == 0) { - ret = -EAGAIN; - goto exit_unlock; - } - - queue = list_first_entry(&conn->msg_list, - struct kdbus_conn_queue, entry); - if (copy_to_user(buf, &queue->src_id, sizeof(__u64))) { - ret = -EFAULT; - goto exit_unlock; - } - - mutex_unlock(&conn->lock); - return 0; - -exit_unlock: - mutex_unlock(&conn->lock); - return ret; -} - /** * kdbus_conn_disconnect() - disconnect a connection * @conn: The connection to disconnect @@ -1269,11 +1321,14 @@ int kdbus_conn_move_messages(struct kdbus_conn *conn_dst, BUG_ON(conn_src == conn_dst); + /* remove all messages from the source */ mutex_lock(&conn_src->lock); list_splice_init(&conn_src->msg_list, &msg_list); + conn_src->msg_prio_queue = RB_ROOT; conn_src->msg_count = 0; mutex_unlock(&conn_src->lock); + /* insert messages into destination */ mutex_lock(&conn_dst->lock); list_for_each_entry_safe(q, tmp, &msg_list, entry) { @@ -1286,8 +1341,7 @@ int kdbus_conn_move_messages(struct kdbus_conn *conn_dst, if (ret < 0) goto exit_unlock_dst; - list_add_tail(&q->entry, &conn_dst->msg_list); - conn_dst->msg_count++; + kdbus_conn_queue_add(conn_dst, q); } exit_unlock_dst: @@ -1575,6 +1629,7 @@ int kdbus_conn_new(struct kdbus_ep *ep, kref_init(&conn->kref); mutex_init(&conn->lock); INIT_LIST_HEAD(&conn->msg_list); + conn->msg_prio_queue = RB_ROOT; INIT_LIST_HEAD(&conn->names_list); INIT_LIST_HEAD(&conn->names_queue_list); INIT_LIST_HEAD(&conn->reply_list); diff --git a/connection.h b/connection.h index 0a7aaa9..7016212 100644 --- a/connection.h +++ b/connection.h @@ -29,6 +29,8 @@ * @attach_flags: KDBUS_ATTACH_* flags * @lock: Connection data lock * @msg_list: Queue of messages + * @msg_prio_queue: Tree of messages, sorted by priority + * @prio_highest: Cached entry for highest priority (lowest value) node * @hentry: Entry in ID <-> connection map * @monitor_entry: The connection is a monitor * @names_list: List of well-known names @@ -58,6 +60,8 @@ struct kdbus_conn { u64 attach_flags; struct mutex lock; struct list_head msg_list; + struct rb_root msg_prio_queue; + struct rb_node *msg_prio_highest; struct hlist_node hentry; struct list_head monitor_entry; struct list_head names_list; @@ -86,9 +90,8 @@ struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn); int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_msg_list_empty); -int kdbus_conn_recv_msg(struct kdbus_conn *conn, __u64 __user *buf); -int kdbus_conn_drop_msg(struct kdbus_conn *conn); -int kdbus_conn_src_msg(struct kdbus_conn *conn, __u64 __user *buf); +int kdbus_conn_recv_msg(struct kdbus_conn *conn, + struct kdbus_cmd_recv __user *recv); int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *buf); int kdbus_conn_kmsg_send(struct kdbus_ep *ep, diff --git a/handle.c b/handle.c index cbc5628..68a153d 100644 --- a/handle.c +++ b/handle.c @@ -614,7 +614,7 @@ static long kdbus_handle_ioctl_ep_connected(struct file *file, unsigned int cmd, } case KDBUS_CMD_MSG_RECV: - /* receive a pointer to a queued message */ + /* handle a queued message */ if (!KDBUS_IS_ALIGNED8((uintptr_t)buf)) { ret = -EFAULT; break; @@ -641,14 +641,6 @@ static long kdbus_handle_ioctl_ep_connected(struct file *file, unsigned int cmd, break; } - case KDBUS_CMD_MSG_DROP: - ret = kdbus_conn_drop_msg(conn); - break; - - case KDBUS_CMD_MSG_SRC: - ret = kdbus_conn_src_msg(conn, buf); - break; - case KDBUS_CMD_MEMFD_NEW: ret = kdbus_handle_memfd(buf); break; diff --git a/kdbus.h b/kdbus.h index d2e4fd3..a758547 100644 --- a/kdbus.h +++ b/kdbus.h @@ -349,6 +349,7 @@ enum kdbus_payload_type { * struct kdbus_msg - the representation of a kdbus message * @size: Total size of the message * @flags: Message flags (KDBUS_MSG_FLAGS_*) + * @priority: Message queue priority value * @dst_id: 64-bit ID of the destination connection * @src_id: 64-bit ID of the source connection * @payload_type: Payload type (KDBUS_PAYLOAD_*) @@ -366,6 +367,7 @@ enum kdbus_payload_type { struct kdbus_msg { __u64 size; __u64 flags; + __s64 priority; __u64 dst_id; __u64 src_id; __u64 payload_type; @@ -377,6 +379,42 @@ struct kdbus_msg { struct kdbus_item items[0]; } __attribute__((aligned(8))); +/** + * enum kdbus_recv_flags - flags for de-queuing messages + * @KDBUS_RECV_PEEK: Return the next queued message without + * actually de-queuing it, and without installing + * any file descriptors or other resources. It is + * usually used to determine the activating + * connection of a bus name. + * @KDBUS_RECV_DROP: Drop and free the next queued message and all + * its ressources without actually receiveing it. + * @KDBUS_RECV_USE_PRIORITY: Only de-queue messages with the specified or + * higher priority; if not set, the priority field + * is ignored. + */ +enum kdbus_recv_flags { + KDBUS_RECV_PEEK = 1 << 0, + KDBUS_RECV_DROP = 1 << 1, + KDBUS_RECV_USE_PRIORITY = 1 << 2, +}; + +/** + * kdbus_cmd_recv - struct to de-queue a buffered message + * @flags: KDBUS_RECV_* flags + * @priority: Minimum priority of the messages to de-queue. Lowest + * values have the highest priority. + * @offset: Returned offset in the pool where the message is + * stored. The user must use KDBUS_CMD_FREE to free + * the allocated memory. + * + * This struct is used with the KDBUS_CMD_MSG_RECV ioctl. + */ +struct kdbus_cmd_recv { + __u64 flags; + __s64 priority; + __u64 offset; +} __attribute__((aligned(8))); + /** * enum kdbus_policy_access_type - permissions of a policy record * @_KDBUS_POLICY_ACCESS_NULL: Uninitialized/invalid @@ -480,8 +518,7 @@ enum kdbus_attach_flags { * @id128: Unique 128-bit ID of the bus (kernel → userspace) * @items: A list of items * - * This struct is used with the KDBUS_CMD_HELLO ioctl. See the ioctl - * documentation for more information. + * This struct is used with the KDBUS_CMD_HELLO ioctl. */ struct kdbus_cmd_hello { __u64 size; @@ -700,11 +737,6 @@ struct kdbus_cmd_memfd_make { * placed in the receiver's pool. * @KDBUS_CMD_FREE: Release the allocated memory in the receiver's * pool. - * @KDBUS_CMD_DROP: Drop and free the next queued message and all - * its ressources without actually receiveing it. - * @KDBUS_CMD_SRC: Query the sender's connection ID of the next - * queued message, used to determine the activating - * connection of a bus name. * @KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with * the connection. Well-known names are used to * address a peer on the bus. @@ -759,10 +791,8 @@ enum kdbus_ioctl_type { KDBUS_CMD_BYEBYE = _IO (KDBUS_IOC_MAGIC, 0x31), KDBUS_CMD_MSG_SEND = _IOW (KDBUS_IOC_MAGIC, 0x40, struct kdbus_msg), - KDBUS_CMD_MSG_RECV = _IOR (KDBUS_IOC_MAGIC, 0x41, __u64 *), + KDBUS_CMD_MSG_RECV = _IOWR(KDBUS_IOC_MAGIC, 0x41, struct kdbus_cmd_recv), KDBUS_CMD_FREE = _IOW (KDBUS_IOC_MAGIC, 0x42, __u64 *), - KDBUS_CMD_MSG_DROP = _IO (KDBUS_IOC_MAGIC, 0x43), - KDBUS_CMD_MSG_SRC = _IOR (KDBUS_IOC_MAGIC, 0x44, __u64 *), KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOC_MAGIC, 0x50, struct kdbus_cmd_name), KDBUS_CMD_NAME_RELEASE = _IOW (KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name), @@ -827,6 +857,8 @@ enum kdbus_ioctl_type { * @ENOENT: The name to query information about is currently not on * the bus. * @ENOMEM: Out of memory. + * @ENOMSG: The queue is not empty, but no message with a matching + * priority is currently queued. * @ENOSYS: The requested functionality is not available. * @ENOTSUPP: The feature negotiation failed, a not supported feature * was requested, or an unknown item type was received. diff --git a/test/Makefile b/test/Makefile index 893dfc6..d668b5c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -17,7 +17,8 @@ TESTS= \ test-kdbus-activator \ test-kdbus-monitor \ test-kdbus-chat \ - test-kdbus-timeout + test-kdbus-timeout \ + test-kdbus-prio all: $(TESTS) diff --git a/test/kdbus-util.c b/test/kdbus-util.c index c375bb9..8979635 100644 --- a/test/kdbus-util.c +++ b/test/kdbus-util.c @@ -103,6 +103,7 @@ int msg_send(const struct conn *conn, uint64_t cookie, uint64_t flags, uint64_t timeout, + int64_t priority, uint64_t dst_id) { struct kdbus_msg *msg; @@ -166,6 +167,7 @@ int msg_send(const struct conn *conn, memset(msg, 0, size); msg->flags = flags; msg->timeout_ns = timeout; + msg->priority = priority; msg->size = size; msg->src_id = conn->id; msg->dst_id = name ? 0 : dst_id; @@ -247,11 +249,12 @@ void msg_dump(const struct conn *conn, const struct kdbus_msg *msg) else cookie_reply = msg->cookie_reply; - printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, cookie=%llu, timeout=%llu cookie_reply=%llu\n", + printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n", enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size, (unsigned long long)msg->flags, msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst), - (unsigned long long)msg->cookie, (unsigned long long)timeout, (unsigned long long)cookie_reply); + (unsigned long long)msg->cookie, (unsigned long long)timeout, (unsigned long long)cookie_reply, + (long long)msg->priority); KDBUS_ITEM_FOREACH(item, msg, items) { if (item->size < KDBUS_ITEM_HEADER_SIZE) { @@ -422,23 +425,25 @@ void msg_dump(const struct conn *conn, const struct kdbus_msg *msg) int msg_recv(struct conn *conn) { - uint64_t off; + struct kdbus_cmd_recv recv = {}; struct kdbus_msg *msg; int ret; - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); if (ret < 0) { + ret = -errno; fprintf(stderr, "error receiving message: %d (%m)\n", ret); - return EXIT_FAILURE; + return ret; } - msg = (struct kdbus_msg *)(conn->buf + off); + msg = (struct kdbus_msg *)(conn->buf + recv.offset); msg_dump(conn, msg); - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); if (ret < 0) { + ret = -errno; fprintf(stderr, "error free message: %d (%m)\n", ret); - return EXIT_FAILURE; + return ret; } return 0; diff --git a/test/kdbus-util.h b/test/kdbus-util.h index 6765d65..205d368 100644 --- a/test/kdbus-util.h +++ b/test/kdbus-util.h @@ -43,7 +43,7 @@ int msg_recv(struct conn *conn); void msg_dump(const struct conn *conn, const struct kdbus_msg *msg); char *msg_id(uint64_t id, char *buf); int msg_send(const struct conn *conn, const char *name, uint64_t cookie, - uint64_t flags, uint64_t timeout, uint64_t dst_id); + uint64_t flags, uint64_t timeout, int64_t priority, uint64_t dst_id); struct conn *connect_to_bus(const char *path, uint64_t hello_flags); void append_policy(struct kdbus_cmd_policy *cmd_policy, struct kdbus_item *policy, __u64 max_size); struct kdbus_item *make_policy_name(const char *name); diff --git a/test/test-kdbus-activator.c b/test/test-kdbus-activator.c index 4b06e24..4754a92 100644 --- a/test/test-kdbus-activator.c +++ b/test/test-kdbus-activator.c @@ -42,7 +42,7 @@ static struct conn *make_activator(const char *path, const char *name) hello->conn_flags = KDBUS_HELLO_ACTIVATOR; item = hello->items; - item->size = KDBUS_ITEM_SIZE(slen); + item->size = KDBUS_ITEM_HEADER_SIZE + slen; item->type = KDBUS_ITEM_NAME; strcpy(item->str, name); @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) KDBUS_NAME_LIST_ACTIVATORS | KDBUS_NAME_LIST_QUEUED); - msg_send(conn_a, "foo.test.activator", 0xdeafbeef, 0, 0, KDBUS_DST_ID_NAME); + msg_send(conn_a, "foo.test.activator", 0xdeafbeef, 0, 0, 0, KDBUS_DST_ID_NAME); fds[0].fd = activator->fd; fds[1].fd = conn_a->fd; diff --git a/test/test-kdbus-benchmark.c b/test/test-kdbus-benchmark.c index a7014ad..1d19fa7 100644 --- a/test/test-kdbus-benchmark.c +++ b/test/test-kdbus-benchmark.c @@ -159,17 +159,17 @@ static int handle_echo_reply(struct conn *conn) { int ret; - uint64_t off; + struct kdbus_cmd_recv recv = {}; struct kdbus_msg *msg; const struct kdbus_item *item; - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); if (ret < 0) { fprintf(stderr, "error receiving message: %d (%m)\n", ret); return EXIT_FAILURE; } - msg = (struct kdbus_msg *)(conn->buf + off); + msg = (struct kdbus_msg *)(conn->buf + recv.offset); item = msg->items; KDBUS_ITEM_FOREACH(item, msg, items) { @@ -196,7 +196,7 @@ handle_echo_reply(struct conn *conn) } } - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); if (ret < 0) { fprintf(stderr, "error free message: %d (%m)\n", ret); return EXIT_FAILURE; diff --git a/test/test-kdbus-chat.c b/test/test-kdbus-chat.c index 99fbbb3..df62e2b 100644 --- a/test/test-kdbus-chat.c +++ b/test/test-kdbus-chat.c @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) add_match_empty(conn_b->fd); cookie = 0; - msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, KDBUS_DST_ID_BROADCAST); + msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, 0, KDBUS_DST_ID_BROADCAST); fds[0].fd = conn_a->fd; fds[1].fd = conn_b->fd; @@ -140,12 +140,12 @@ int main(int argc, char *argv[]) name_release(conn_a, "foo.bar.baz"); msg_recv(conn_a); - msg_send(conn_a, NULL, 0xc0000000 | cookie++, 0, 0, conn_b->id); + msg_send(conn_a, NULL, 0xc0000000 | cookie++, 0, 0, 0, conn_b->id); } if (fds[1].revents & POLLIN) { msg_recv(conn_b); - msg_send(conn_b, NULL, 0xc0000000 | cookie++, 0, 0, conn_a->id); + msg_send(conn_b, NULL, 0xc0000000 | cookie++, 0, 0, 0, conn_a->id); } name_list(conn_b, KDBUS_NAME_LIST_UNIQUE| diff --git a/test/test-kdbus-monitor.c b/test/test-kdbus-monitor.c index 754fba7..b06b898 100644 --- a/test/test-kdbus-monitor.c +++ b/test/test-kdbus-monitor.c @@ -46,7 +46,8 @@ static void usage(const char *argv0) static int dump_packet(struct conn *conn, int fd) { int ret; - uint64_t off, size; + struct kdbus_cmd_recv recv = {}; + uint64_t size; struct kdbus_msg *msg; const struct kdbus_item *item; struct timeval now; @@ -58,13 +59,13 @@ static int dump_packet(struct conn *conn, int fd) entry.tv_sec = now.tv_sec; entry.tv_usec = now.tv_usec; - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); if (ret < 0) { fprintf(stderr, "error receiving message: %d (%m)\n", ret); return EXIT_FAILURE; } - msg = (struct kdbus_msg *)(conn->buf + off); + msg = (struct kdbus_msg *)(conn->buf + recv.offset); item = msg->items; size = msg->size; @@ -113,7 +114,7 @@ static int dump_packet(struct conn *conn, int fd) } } - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); if (ret < 0) { fprintf(stderr, "error free message: %d (%m)\n", ret); return EXIT_FAILURE; diff --git a/test/test-kdbus-prio.c b/test/test-kdbus-prio.c new file mode 100644 index 0000000..ef3b6dc --- /dev/null +++ b/test/test-kdbus-prio.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdbus-util.h" +#include "kdbus-enum.h" + +static int msg_recv_prio(struct conn *conn, int64_t priority) +{ + struct kdbus_cmd_recv recv = { + .flags = KDBUS_RECV_USE_PRIORITY, + .priority = priority, + }; + struct kdbus_msg *msg; + int ret; + + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "error receiving message: %d (%m)\n", ret); + return ret; + } + + msg = (struct kdbus_msg *)(conn->buf + recv.offset); + msg_dump(conn, msg); + + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); + if (ret < 0) { + ret = -errno; + fprintf(stderr, "error free message: %d (%m)\n", ret); + return ret; + } + + return 0; +} + +static int run_test(void) +{ + struct { + struct kdbus_cmd_make head; + + /* bloom size item */ + struct { + uint64_t size; + uint64_t type; + uint64_t bloom_size; + } bs; + + /* name item */ + uint64_t n_size; + uint64_t n_type; + char name[64]; + } bus_make; + char *bus; + struct conn *conn_a, *conn_b; + uint64_t cookie; + int fdc; + int ret; + + printf("-- opening /dev/" KBUILD_MODNAME "/control\n"); + fdc = open("/dev/" KBUILD_MODNAME "/control", O_RDWR|O_CLOEXEC); + if (fdc < 0) { + fprintf(stderr, "--- error %d (%m)\n", fdc); + return EXIT_FAILURE; + } + + memset(&bus_make, 0, sizeof(bus_make)); + bus_make.head.flags = KDBUS_MAKE_POLICY_OPEN; + bus_make.bs.size = sizeof(bus_make.bs); + bus_make.bs.type = KDBUS_ITEM_BLOOM_SIZE; + bus_make.bs.bloom_size = 64; + + snprintf(bus_make.name, sizeof(bus_make.name), "%u-testbus", getuid()); + bus_make.n_type = KDBUS_ITEM_MAKE_NAME; + bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; + + bus_make.head.size = sizeof(struct kdbus_cmd_make) + + sizeof(bus_make.bs) + + bus_make.n_size; + + printf("-- creating bus '%s'\n", bus_make.name); + ret = ioctl(fdc, KDBUS_CMD_BUS_MAKE, &bus_make); + if (ret) { + fprintf(stderr, "--- error %d (%m)\n", ret); + return EXIT_FAILURE; + } + + if (asprintf(&bus, "/dev/" KBUILD_MODNAME "/%s/bus", bus_make.name) < 0) + return EXIT_FAILURE; + + conn_a = connect_to_bus(bus, 0); + conn_b = connect_to_bus(bus, 0); + if (!conn_a || !conn_b) + return EXIT_FAILURE; + + cookie = 0; + msg_send(conn_b, NULL, ++cookie, 0, 0, 25, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -600, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, 10, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -35, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -100, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, 20, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -15, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -800, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -150, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -150, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, 10, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -800, conn_a->id); + msg_send(conn_b, NULL, ++cookie, 0, 0, -10, conn_a->id); + + printf("--- get priority -200\n"); + for (;;) { + if (msg_recv_prio(conn_a, -200) < 0) + break; + } + + printf("--- get priority -100\n"); + for (;;) { + if (msg_recv_prio(conn_a, -100) < 0) + break; + } + + printf("--- get priority 10\n"); + for (;;) { + if (msg_recv_prio(conn_a, 10) < 0) + break; + } + + printf("--- get priority (all)\n"); + for (;;) { + if (msg_recv(conn_a) < 0) + break; + } + + close(conn_a->fd); + close(conn_b->fd); + free(conn_a); + free(conn_b); + close(fdc); + free(bus); + + return EXIT_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + if (argc > 1) + while (run_test() == 0); + + return run_test(); +} diff --git a/test/test-kdbus-timeout.c b/test/test-kdbus-timeout.c index f25e3e5..527b5a9 100644 --- a/test/test-kdbus-timeout.c +++ b/test/test-kdbus-timeout.c @@ -18,21 +18,21 @@ static uint64_t expected = 0; int timeout_msg_recv(struct conn *conn) { - uint64_t off; + struct kdbus_cmd_recv recv = {}; struct kdbus_msg *msg; int ret; - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); if (ret < 0) { fprintf(stderr, "error receiving message: %d (%m)\n", ret); return EXIT_FAILURE; } - msg = (struct kdbus_msg *)(conn->buf + off); + msg = (struct kdbus_msg *)(conn->buf + recv.offset); expected &= ~(1ULL << msg->cookie_reply); printf("Got message timeout for cookie %llu\n", msg->cookie_reply); - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); if (ret < 0) { fprintf(stderr, "error free message: %d (%m)\n", ret); return EXIT_FAILURE; @@ -104,7 +104,7 @@ static int run_test(void) /* send messages that expect a reply (within 1 sec), but never answer it */ for (i = 0; i < n_msgs; i++) { printf("Sending message with cookie %u ...\n", i); - msg_send(conn_b, NULL, i, KDBUS_MSG_FLAGS_EXPECT_REPLY, (i + 1) * 100ULL * 1000ULL, conn_a->id); + msg_send(conn_b, NULL, i, KDBUS_MSG_FLAGS_EXPECT_REPLY, (i + 1) * 100ULL * 1000ULL, 0, conn_a->id); expected |= 1ULL << i; } diff --git a/test/test-kdbus.c b/test/test-kdbus.c index 9b8a073..0104701 100644 --- a/test/test-kdbus.c +++ b/test/test-kdbus.c @@ -445,7 +445,7 @@ static int check_hello(struct kdbus_check_env *env) static int check_byebye(struct kdbus_check_env *env) { struct kdbus_conn *conn; - uint64_t off; + struct kdbus_cmd_recv recv = {}; int ret; /* create a 2nd connection */ @@ -464,10 +464,10 @@ static int check_byebye(struct kdbus_check_env *env) ASSERT_RETURN(ret == -1 && errno == EBUSY); /* receive the message */ - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); ASSERT_RETURN(ret == 0); /* and try again */ @@ -703,7 +703,7 @@ static int check_match_id_add(struct kdbus_check_env *env) struct kdbus_conn *conn; struct kdbus_item *item; struct kdbus_msg *msg; - uint64_t off; + struct kdbus_cmd_recv recv = {}; int ret; memset(&buf, 0, sizeof(buf)); @@ -723,10 +723,10 @@ static int check_match_id_add(struct kdbus_check_env *env) ASSERT_RETURN(conn != NULL); /* 1st connection should have received a notification */ - ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(env->conn->buf + off); + msg = (struct kdbus_msg *)(env->conn->buf + recv.offset); item = &msg->items[0]; ASSERT_RETURN(item->type == KDBUS_ITEM_ID_ADD); ASSERT_RETURN(item->id_change.id == conn->hello.id); @@ -749,7 +749,7 @@ static int check_match_id_remove(struct kdbus_check_env *env) struct kdbus_conn *conn; struct kdbus_item *item; struct kdbus_msg *msg; - uint64_t off; + struct kdbus_cmd_recv recv = {}; size_t id; int ret; @@ -773,10 +773,10 @@ static int check_match_id_remove(struct kdbus_check_env *env) free_conn(conn); /* 1st connection should have received a notification */ - ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(env->conn->buf + off); + msg = (struct kdbus_msg *)(env->conn->buf + recv.offset); item = &msg->items[0]; ASSERT_RETURN(item->type == KDBUS_ITEM_ID_REMOVE); ASSERT_RETURN(item->id_change.id == id); @@ -798,7 +798,8 @@ static int check_match_name_add(struct kdbus_check_env *env) struct kdbus_cmd_name *cmd_name; struct kdbus_item *item; struct kdbus_msg *msg; - uint64_t size, off; + uint64_t size; + struct kdbus_cmd_recv recv = {}; char *name; int ret; @@ -830,10 +831,10 @@ static int check_match_name_add(struct kdbus_check_env *env) ASSERT_RETURN(ret == 0); /* we should have received a notification */ - ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(env->conn->buf + off); + msg = (struct kdbus_msg *)(env->conn->buf + recv.offset); item = &msg->items[0]; ASSERT_RETURN(item->type == KDBUS_ITEM_NAME_ADD); ASSERT_RETURN(item->name_change.old.id == 0); @@ -857,7 +858,8 @@ static int check_match_name_remove(struct kdbus_check_env *env) struct kdbus_cmd_name *cmd_name; struct kdbus_item *item; struct kdbus_msg *msg; - uint64_t size, off; + uint64_t size; + struct kdbus_cmd_recv recv = {}; char *name; int ret; @@ -893,10 +895,10 @@ static int check_match_name_remove(struct kdbus_check_env *env) ASSERT_RETURN(ret == 0); /* we should have received a notification */ - ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(env->conn->buf + off); + msg = (struct kdbus_msg *)(env->conn->buf + recv.offset); item = &msg->items[0]; ASSERT_RETURN(item->type == KDBUS_ITEM_NAME_REMOVE); ASSERT_RETURN(item->name_change.old.id == env->conn->hello.id); @@ -921,7 +923,8 @@ static int check_match_name_change(struct kdbus_check_env *env) struct kdbus_item *item; struct kdbus_conn *conn; struct kdbus_msg *msg; - uint64_t size, off; + uint64_t size; + struct kdbus_cmd_recv recv = {}; char *name; int ret; @@ -972,10 +975,10 @@ static int check_match_name_change(struct kdbus_check_env *env) ASSERT_RETURN(ret == 0); /* we should have received a notification */ - ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(env->conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(env->conn->buf + off); + msg = (struct kdbus_msg *)(env->conn->buf + recv.offset); item = &msg->items[0]; ASSERT_RETURN(item->type == KDBUS_ITEM_NAME_CHANGE); ASSERT_RETURN(item->name_change.old.id == env->conn->hello.id); @@ -993,7 +996,7 @@ static int check_msg_basic(struct kdbus_check_env *env) struct kdbus_msg *msg; uint64_t cookie = 0x1234abcd5678eeff; struct pollfd fd; - uint64_t off; + struct kdbus_cmd_recv recv = {}; int ret; /* create a 2nd connection */ @@ -1015,13 +1018,13 @@ static int check_msg_basic(struct kdbus_check_env *env) ret = poll(&fd, 1, 100); ASSERT_RETURN(ret > 0 && (fd.revents & POLLIN)); - ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &off); + ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv); ASSERT_RETURN(ret == 0); - msg = (struct kdbus_msg *)(conn->buf + off); + msg = (struct kdbus_msg *)(conn->buf + recv.offset); ASSERT_RETURN(msg->cookie == cookie); - ret = ioctl(conn->fd, KDBUS_CMD_FREE, &off); + ret = ioctl(conn->fd, KDBUS_CMD_FREE, &recv.offset); ASSERT_RETURN(ret == 0); free_conn(conn); -- 2.34.1