Pull request
No user-visible changes. -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJcPLmTAAoJEJykq7OBq3PIxOEH/jQItQRDlB2PCSyojNkvMpXJ LVnSc4a5edUUt9e+YvI3+DYX7WJ43VtxfurgOSwS2gFds92ckD9+U5CrFbxsLCoL 7no+cC8fgNSqp+lmIX0c7nexgTLRU99Qmov3ixTKVzE6WrBjHN5fHRZlMIY8wXlE NCXnAzM8uoxDXRyK/a2dQ7ckGaYtXn9O8x7N+B+HyVI+0yyGArjZTZUcC2ok+Smf wzGfxl/iQDxLWw0kfl6adhTC2riVFUzsSshqKnDEqgpBerwT6WSiWvmxLhpetf5E 2C4wEmGDgdt5kLC+OU3XxDfLaNAN/W0kpcszkZODstkcSrQQ2B0tcbJigzruua4= =rosm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging Pull request No user-visible changes. # gpg: Signature made Mon 14 Jan 2019 16:32:19 GMT # gpg: using RSA key 9CA4ABB381AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" # Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35 775A 9CA4 ABB3 81AB 73C8 * remotes/stefanha/tags/block-pull-request: aio-posix: Fix concurrent aio_poll/set_fd_handler. aio-posix: Unregister fd from ctx epoll when removing fd_handler. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4b9f0b0f7c
@ -200,6 +200,31 @@ static AioHandler *find_aio_handler(AioContext *ctx, int fd)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
|
||||||
|
{
|
||||||
|
/* If the GSource is in the process of being destroyed then
|
||||||
|
* g_source_remove_poll() causes an assertion failure. Skip
|
||||||
|
* removal in that case, because glib cleans up its state during
|
||||||
|
* destruction anyway.
|
||||||
|
*/
|
||||||
|
if (!g_source_is_destroyed(&ctx->source)) {
|
||||||
|
g_source_remove_poll(&ctx->source, &node->pfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a read is in progress, just mark the node as deleted */
|
||||||
|
if (qemu_lockcnt_count(&ctx->list_lock)) {
|
||||||
|
node->deleted = 1;
|
||||||
|
node->pfd.revents = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Otherwise, delete it for real. We can't just mark it as
|
||||||
|
* deleted because deleted nodes are only cleaned up while
|
||||||
|
* no one is walking the handlers list.
|
||||||
|
*/
|
||||||
|
QLIST_REMOVE(node, node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void aio_set_fd_handler(AioContext *ctx,
|
void aio_set_fd_handler(AioContext *ctx,
|
||||||
int fd,
|
int fd,
|
||||||
bool is_external,
|
bool is_external,
|
||||||
@ -209,6 +234,7 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
AioHandler *node;
|
AioHandler *node;
|
||||||
|
AioHandler *new_node = NULL;
|
||||||
bool is_new = false;
|
bool is_new = false;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
int poll_disable_change;
|
int poll_disable_change;
|
||||||
@ -223,50 +249,39 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
qemu_lockcnt_unlock(&ctx->list_lock);
|
qemu_lockcnt_unlock(&ctx->list_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* Clean events in order to unregister fd from the ctx epoll. */
|
||||||
|
node->pfd.events = 0;
|
||||||
|
|
||||||
/* If the GSource is in the process of being destroyed then
|
|
||||||
* g_source_remove_poll() causes an assertion failure. Skip
|
|
||||||
* removal in that case, because glib cleans up its state during
|
|
||||||
* destruction anyway.
|
|
||||||
*/
|
|
||||||
if (!g_source_is_destroyed(&ctx->source)) {
|
|
||||||
g_source_remove_poll(&ctx->source, &node->pfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If a read is in progress, just mark the node as deleted */
|
|
||||||
if (qemu_lockcnt_count(&ctx->list_lock)) {
|
|
||||||
node->deleted = 1;
|
|
||||||
node->pfd.revents = 0;
|
|
||||||
} else {
|
|
||||||
/* Otherwise, delete it for real. We can't just mark it as
|
|
||||||
* deleted because deleted nodes are only cleaned up while
|
|
||||||
* no one is walking the handlers list.
|
|
||||||
*/
|
|
||||||
QLIST_REMOVE(node, node);
|
|
||||||
deleted = true;
|
|
||||||
}
|
|
||||||
poll_disable_change = -!node->io_poll;
|
poll_disable_change = -!node->io_poll;
|
||||||
} else {
|
} else {
|
||||||
poll_disable_change = !io_poll - (node && !node->io_poll);
|
poll_disable_change = !io_poll - (node && !node->io_poll);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
/* Alloc and insert if it's not already there */
|
|
||||||
node = g_new0(AioHandler, 1);
|
|
||||||
node->pfd.fd = fd;
|
|
||||||
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
|
|
||||||
|
|
||||||
g_source_add_poll(&ctx->source, &node->pfd);
|
|
||||||
is_new = true;
|
is_new = true;
|
||||||
}
|
}
|
||||||
|
/* Alloc and insert if it's not already there */
|
||||||
|
new_node = g_new0(AioHandler, 1);
|
||||||
|
|
||||||
/* Update handler with latest information */
|
/* Update handler with latest information */
|
||||||
node->io_read = io_read;
|
new_node->io_read = io_read;
|
||||||
node->io_write = io_write;
|
new_node->io_write = io_write;
|
||||||
node->io_poll = io_poll;
|
new_node->io_poll = io_poll;
|
||||||
node->opaque = opaque;
|
new_node->opaque = opaque;
|
||||||
node->is_external = is_external;
|
new_node->is_external = is_external;
|
||||||
|
|
||||||
node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
|
if (is_new) {
|
||||||
node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
|
new_node->pfd.fd = fd;
|
||||||
|
} else {
|
||||||
|
new_node->pfd = node->pfd;
|
||||||
|
}
|
||||||
|
g_source_add_poll(&ctx->source, &new_node->pfd);
|
||||||
|
|
||||||
|
new_node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
|
||||||
|
new_node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, new_node, node);
|
||||||
|
}
|
||||||
|
if (node) {
|
||||||
|
deleted = aio_remove_fd_handler(ctx, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No need to order poll_disable_cnt writes against other updates;
|
/* No need to order poll_disable_cnt writes against other updates;
|
||||||
@ -278,7 +293,12 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
atomic_set(&ctx->poll_disable_cnt,
|
atomic_set(&ctx->poll_disable_cnt,
|
||||||
atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
|
atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
|
||||||
|
|
||||||
aio_epoll_update(ctx, node, is_new);
|
if (new_node) {
|
||||||
|
aio_epoll_update(ctx, new_node, is_new);
|
||||||
|
} else if (node) {
|
||||||
|
/* Unregister deleted fd_handler */
|
||||||
|
aio_epoll_update(ctx, node, false);
|
||||||
|
}
|
||||||
qemu_lockcnt_unlock(&ctx->list_lock);
|
qemu_lockcnt_unlock(&ctx->list_lock);
|
||||||
aio_notify(ctx);
|
aio_notify(ctx);
|
||||||
|
|
||||||
|
@ -35,6 +35,22 @@ struct AioHandler {
|
|||||||
QLIST_ENTRY(AioHandler) node;
|
QLIST_ENTRY(AioHandler) node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
|
||||||
|
{
|
||||||
|
/* If aio_poll is in progress, just mark the node as deleted */
|
||||||
|
if (qemu_lockcnt_count(&ctx->list_lock)) {
|
||||||
|
node->deleted = 1;
|
||||||
|
node->pfd.revents = 0;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, delete it for real. We can't just mark it as
|
||||||
|
* deleted because deleted nodes are only cleaned up after
|
||||||
|
* releasing the list_lock.
|
||||||
|
*/
|
||||||
|
QLIST_REMOVE(node, node);
|
||||||
|
g_free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void aio_set_fd_handler(AioContext *ctx,
|
void aio_set_fd_handler(AioContext *ctx,
|
||||||
int fd,
|
int fd,
|
||||||
bool is_external,
|
bool is_external,
|
||||||
@ -44,41 +60,23 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
/* fd is a SOCKET in our case */
|
/* fd is a SOCKET in our case */
|
||||||
AioHandler *node;
|
AioHandler *old_node;
|
||||||
|
AioHandler *node = NULL;
|
||||||
|
|
||||||
qemu_lockcnt_lock(&ctx->list_lock);
|
qemu_lockcnt_lock(&ctx->list_lock);
|
||||||
QLIST_FOREACH(node, &ctx->aio_handlers, node) {
|
QLIST_FOREACH(old_node, &ctx->aio_handlers, node) {
|
||||||
if (node->pfd.fd == fd && !node->deleted) {
|
if (old_node->pfd.fd == fd && !old_node->deleted) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Are we deleting the fd handler? */
|
if (io_read || io_write) {
|
||||||
if (!io_read && !io_write) {
|
|
||||||
if (node) {
|
|
||||||
/* If aio_poll is in progress, just mark the node as deleted */
|
|
||||||
if (qemu_lockcnt_count(&ctx->list_lock)) {
|
|
||||||
node->deleted = 1;
|
|
||||||
node->pfd.revents = 0;
|
|
||||||
} else {
|
|
||||||
/* Otherwise, delete it for real. We can't just mark it as
|
|
||||||
* deleted because deleted nodes are only cleaned up after
|
|
||||||
* releasing the list_lock.
|
|
||||||
*/
|
|
||||||
QLIST_REMOVE(node, node);
|
|
||||||
g_free(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
long bitmask = 0;
|
long bitmask = 0;
|
||||||
|
|
||||||
if (node == NULL) {
|
/* Alloc and insert if it's not already there */
|
||||||
/* Alloc and insert if it's not already there */
|
node = g_new0(AioHandler, 1);
|
||||||
node = g_new0(AioHandler, 1);
|
node->pfd.fd = fd;
|
||||||
node->pfd.fd = fd;
|
|
||||||
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
node->pfd.events = 0;
|
node->pfd.events = 0;
|
||||||
if (node->io_read) {
|
if (node->io_read) {
|
||||||
@ -104,9 +102,13 @@ void aio_set_fd_handler(AioContext *ctx,
|
|||||||
bitmask |= FD_WRITE | FD_CONNECT;
|
bitmask |= FD_WRITE | FD_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
|
||||||
event = event_notifier_get_handle(&ctx->notifier);
|
event = event_notifier_get_handle(&ctx->notifier);
|
||||||
WSAEventSelect(node->pfd.fd, event, bitmask);
|
WSAEventSelect(node->pfd.fd, event, bitmask);
|
||||||
}
|
}
|
||||||
|
if (old_node) {
|
||||||
|
aio_remove_fd_handler(ctx, old_node);
|
||||||
|
}
|
||||||
|
|
||||||
qemu_lockcnt_unlock(&ctx->list_lock);
|
qemu_lockcnt_unlock(&ctx->list_lock);
|
||||||
aio_notify(ctx);
|
aio_notify(ctx);
|
||||||
@ -139,18 +141,7 @@ void aio_set_event_notifier(AioContext *ctx,
|
|||||||
if (node) {
|
if (node) {
|
||||||
g_source_remove_poll(&ctx->source, &node->pfd);
|
g_source_remove_poll(&ctx->source, &node->pfd);
|
||||||
|
|
||||||
/* aio_poll is in progress, just mark the node as deleted */
|
aio_remove_fd_handler(ctx, node);
|
||||||
if (qemu_lockcnt_count(&ctx->list_lock)) {
|
|
||||||
node->deleted = 1;
|
|
||||||
node->pfd.revents = 0;
|
|
||||||
} else {
|
|
||||||
/* Otherwise, delete it for real. We can't just mark it as
|
|
||||||
* deleted because deleted nodes are only cleaned up after
|
|
||||||
* releasing the list_lock.
|
|
||||||
*/
|
|
||||||
QLIST_REMOVE(node, node);
|
|
||||||
g_free(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user