queue: re-implement

This commit is contained in:
Bert Belder 2017-09-11 01:29:45 +02:00
parent 4568ce69d8
commit 4d9a24a708
5 changed files with 59 additions and 102 deletions

View File

@ -30,12 +30,6 @@ typedef struct _ep_sock_private {
uint32_t flags;
} _ep_sock_private_t;
#define ATTN_LIST_ADD(p, sock_info) \
do { \
QUEUE_INSERT_TAIL(&(p)->update_queue, &(sock_info)->queue_entry); \
(_ep_sock_private(sock_info))->flags |= _EP_SOCK_LISTED; \
} while (0)
static inline _ep_sock_private_t* _ep_sock_private(ep_sock_t* sock_info) {
return container_of(sock_info, _ep_sock_private_t, pub);
}
@ -64,7 +58,7 @@ ep_sock_t* ep_sock_new(ep_port_t* port_info) {
memset(sock_private, 0, sizeof *sock_private);
handle_tree_entry_init(&sock_private->pub.tree_entry);
QUEUE_INIT(&sock_private->pub.queue_entry);
queue_elem_init(&sock_private->pub.queue_entry);
return &sock_private->pub;
}

View File

@ -16,7 +16,7 @@ typedef struct poll_req poll_req_t;
typedef struct ep_sock {
handle_tree_entry_t tree_entry;
QUEUE queue_entry;
queue_elem_t queue_entry;
} ep_sock_t;
EPOLL_INTERNAL ep_sock_t* ep_sock_new(ep_port_t* port_info);

View File

@ -99,13 +99,13 @@ int epoll_ctl(epoll_t port_handle,
}
static int _ep_port_update_events(ep_port_t* port_info) {
QUEUE* update_queue = &port_info->update_queue;
queue_t* update_queue = &port_info->update_queue;
/* Walk the queue, submitting new poll requests for every socket that needs
* it. */
while (!QUEUE_EMPTY(update_queue)) {
QUEUE* queue_entry = QUEUE_HEAD(update_queue);
ep_sock_t* sock_info = QUEUE_DATA(queue_entry, ep_sock_t, queue_entry);
while (!queue_empty(update_queue)) {
queue_elem_t* queue_entry = queue_first(update_queue);
ep_sock_t* sock_info = container_of(queue_entry, ep_sock_t, queue_entry);
if (ep_sock_update(port_info, sock_info) < 0)
return -1;
@ -229,7 +229,7 @@ epoll_t epoll_create(void) {
port_info->iocp = iocp;
port_info->poll_req_count = 0;
QUEUE_INIT(&port_info->update_queue);
queue_init(&port_info->update_queue);
memset(&port_info->driver_sockets, 0, sizeof port_info->driver_sockets);
handle_tree_init(&port_info->sock_tree);
@ -393,19 +393,19 @@ error:;
bool ep_port_is_socket_update_pending(ep_port_t* port_info,
ep_sock_t* sock_info) {
unused(port_info);
return QUEUE_ENQUEUED(&sock_info->queue_entry);
return queue_enqueued(&sock_info->queue_entry);
}
void ep_port_request_socket_update(ep_port_t* port_info,
ep_sock_t* sock_info) {
if (ep_port_is_socket_update_pending(port_info, sock_info))
return;
QUEUE_INSERT_TAIL(&port_info->update_queue, &sock_info->queue_entry);
queue_append(&port_info->update_queue, &sock_info->queue_entry);
assert(ep_port_is_socket_update_pending(port_info, sock_info));
}
void ep_port_clear_socket_update(ep_port_t* port_info, ep_sock_t* sock_info) {
if (!ep_port_is_socket_update_pending(port_info, sock_info))
return;
QUEUE_REMOVE(&sock_info->queue_entry);
queue_remove(&sock_info->queue_entry);
}

View File

@ -17,7 +17,7 @@ typedef struct ep_port {
HANDLE iocp;
SOCKET driver_sockets[array_count(AFD_PROVIDER_GUID_LIST)];
handle_tree_t sock_tree;
QUEUE update_queue;
queue_t update_queue;
size_t poll_req_count;
} ep_port_t;

View File

@ -1,101 +1,64 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef QUEUE_H_
#define QUEUE_H_
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
typedef void* QUEUE[2];
#include "internal.h"
/* Private macros. */
#define _QUEUE_NEXT(q) (*(QUEUE**) &((*(q))[0]))
#define _QUEUE_PREV(q) (*(QUEUE**) &((*(q))[1]))
#define _QUEUE_PREV_NEXT(q) (_QUEUE_NEXT(_QUEUE_PREV(q)))
#define _QUEUE_NEXT_PREV(q) (_QUEUE_PREV(_QUEUE_NEXT(q)))
typedef struct queue_elem queue_elem_t;
typedef struct queue_elem {
queue_elem_t* prev;
queue_elem_t* next;
} queue_elem_t;
typedef struct queue {
queue_elem_t head;
} queue_t;
/* Public macros. */
#define QUEUE_DATA(ptr, type, field) \
((type*) ((char*) (ptr) -offsetof(type, field)))
EPOLL_INTERNAL inline void queue_elem_init(queue_elem_t* elem) {
elem->prev = elem;
elem->next = elem;
}
/* Important note: mutating the list while QUEUE_FOREACH is
* iterating over its elements results in undefined behavior.
*/
#define QUEUE_FOREACH(q, h) \
for ((q) = _QUEUE_NEXT(h); (q) != (h); (q) = _QUEUE_NEXT(q))
EPOLL_INTERNAL inline void queue_init(queue_t* queue) {
queue_elem_init(&queue->head);
}
#define QUEUE_EMPTY(q) ((const QUEUE*) (q) == (const QUEUE*) _QUEUE_NEXT(q))
#define QUEUE_ENQUEUED(q) (!QUEUE_EMPTY(q))
EPOLL_INTERNAL inline bool queue_enqueued(const queue_elem_t* elem) {
return elem->prev != elem;
}
#define QUEUE_HEAD(q) (_QUEUE_NEXT(q))
EPOLL_INTERNAL inline bool queue_empty(const queue_t* queue) {
return !queue_enqueued(&queue->head);
}
#define QUEUE_INIT(q) \
do { \
_QUEUE_NEXT(q) = (q); \
_QUEUE_PREV(q) = (q); \
} while (0)
EPOLL_INTERNAL inline queue_elem_t* queue_first(const queue_t* queue) {
return !queue_empty(queue) ? queue->head.next : NULL;
}
#define QUEUE_MERGE(h, n) \
do { \
_QUEUE_PREV_NEXT(h) = _QUEUE_NEXT(n); \
_QUEUE_NEXT_PREV(n) = _QUEUE_PREV(h); \
_QUEUE_PREV(h) = _QUEUE_PREV(n); \
_QUEUE_PREV_NEXT(h) = (h); \
} while (0)
EPOLL_INTERNAL inline queue_elem_t* queue_last(const queue_t* queue) {
return !queue_empty(queue) ? queue->head.prev : NULL;
}
#define QUEUE_SPLIT(h, q, n) \
do { \
_QUEUE_PREV(n) = _QUEUE_PREV(h); \
_QUEUE_PREV_NEXT(n) = (n); \
_QUEUE_NEXT(n) = (q); \
_QUEUE_PREV(h) = _QUEUE_PREV(q); \
_QUEUE_PREV_NEXT(h) = (h); \
_QUEUE_PREV(q) = (n); \
} while (0)
EPOLL_INTERNAL inline void queue_prepend(queue_t* queue, queue_elem_t* elem) {
elem->next = queue->head.next;
elem->prev = &queue->head;
elem->next->prev = elem;
queue->head.next = elem;
}
#define QUEUE_MOVE(h, n) \
do { \
if (QUEUE_EMPTY(h)) \
QUEUE_INIT(n); \
else { \
QUEUE* q = QUEUE_HEAD(h); \
QUEUE_SPLIT(h, q, n); \
} \
} while (0)
EPOLL_INTERNAL inline void queue_append(queue_t* queue, queue_elem_t* elem) {
elem->next = &queue->head;
elem->prev = queue->head.prev;
elem->prev->next = elem;
queue->head.prev = elem;
}
#define QUEUE_INSERT_HEAD(h, q) \
do { \
_QUEUE_NEXT(q) = _QUEUE_NEXT(h); \
_QUEUE_PREV(q) = (h); \
_QUEUE_NEXT_PREV(q) = (q); \
_QUEUE_NEXT(h) = (q); \
} while (0)
#define QUEUE_INSERT_TAIL(h, q) \
do { \
_QUEUE_NEXT(q) = (h); \
_QUEUE_PREV(q) = _QUEUE_PREV(h); \
_QUEUE_PREV_NEXT(q) = (q); \
_QUEUE_PREV(h) = (q); \
} while (0)
#define QUEUE_REMOVE(q) \
do { \
_QUEUE_PREV_NEXT(q) = _QUEUE_NEXT(q); \
_QUEUE_NEXT_PREV(q) = _QUEUE_PREV(q); \
QUEUE_INIT(q); \
} while (0)
EPOLL_INTERNAL inline void queue_remove(queue_elem_t* elem) {
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
elem->prev = elem;
elem->next = elem;
}
#endif /* QUEUE_H_ */