From b871d6d8d0587e44fa89e07dcc9a424ff187ba5c Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 20 Oct 2017 01:03:39 +1100 Subject: [PATCH] [client] implemented the new ivshmem interrupt sync system --- client/KVMGFXHeader.h | 2 ++ client/ivshmem/ivshmem.c | 74 +++++++++++++++++++++++++++++++++++++++- client/ivshmem/ivshmem.h | 12 ++++++- client/main.c | 42 ++++++++++++++++++----- 4 files changed, 119 insertions(+), 11 deletions(-) diff --git a/client/KVMGFXHeader.h b/client/KVMGFXHeader.h index ce536fd8..d0e01b14 100644 --- a/client/KVMGFXHeader.h +++ b/client/KVMGFXHeader.h @@ -23,6 +23,8 @@ struct KVMGFXHeader { char magic[sizeof(KVMGFX_HEADER_MAGIC)]; uint32_t version; // version of this structure + uint16_t hostID; // the host ivshmem client id + uint16_t guestID; // the guest ivshmem client id FrameType frameType; // the frame type FrameComp compType; // frame compression mode uint32_t width; // the width diff --git a/client/ivshmem/ivshmem.c b/client/ivshmem/ivshmem.c index 23f94a79..b48cdfec 100644 --- a/client/ivshmem/ivshmem.c +++ b/client/ivshmem/ivshmem.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -270,6 +271,7 @@ bool ivshmem_read_msg(int64_t * index, int * fd) if (!fd) return true; + *fd = -1; struct cmsghdr *cmsg; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { @@ -280,12 +282,14 @@ bool ivshmem_read_msg(int64_t * index, int * fd) continue; } - memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd)); + *fd = *(int*)CMSG_DATA(cmsg); } return true; } +// ============================================================================ + uint16_t ivshmem_get_id() { if (!ivshmem.connected) @@ -455,4 +459,72 @@ bool ivshmem_process() client->irqs[client->irqCount++] = fd; return true; +} + +// ============================================================================ + +enum IVSHMEMWaitResult ivshmem_wait_irq(uint16_t vector) +{ + if (vector > ivshmem.server.irqCount - 1) + return false; + + int fd = ivshmem.server.irqs[vector]; + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + while(true) + { + int ret = select(fd+1, &fds, NULL, NULL, &timeout); + if (ret < 0) + { + if (errno == EINTR) + continue; + + DEBUG_ERROR("select error"); + break; + } + + if (ret == 0) + return IVSHMEM_WAIT_RESULT_TIMEOUT; + + if (FD_ISSET(fd, &fds)) + { + uint64_t kick; + read(fd, &kick, sizeof(kick)); + return IVSHMEM_WAIT_RESULT_OK; + } + } + + return IVSHMEM_WAIT_RESULT_ERROR; +} + +// ============================================================================ + +bool ivshmem_kick_irq(uint16_t clientID, uint16_t vector) +{ + struct IVSHMEMClient * client = ivshmem_get_client(clientID); + if (!client) + { + DEBUG_ERROR("invalid client"); + return false; + } + + if (vector > client->irqCount - 1) + { + DEBUG_ERROR("invalid vector for client"); + return false; + } + + int fd = client->irqs[vector]; + uint64_t kick = ivshmem.server.clientID; + if (write(fd, &kick, sizeof(kick)) == sizeof(kick)) + return true; + + DEBUG_ERROR("failed to send kick"); + return false; } \ No newline at end of file diff --git a/client/ivshmem/ivshmem.h b/client/ivshmem/ivshmem.h index ff7e92de..e43c6778 100644 --- a/client/ivshmem/ivshmem.h +++ b/client/ivshmem/ivshmem.h @@ -8,4 +8,14 @@ bool ivshmem_process(); uint16_t ivshmem_get_id(); void * ivshmem_get_map(); -size_t ivshmem_get_map_size(); \ No newline at end of file +size_t ivshmem_get_map_size(); + +enum IVSHMEMWaitResult +{ + IVSHMEM_WAIT_RESULT_OK, + IVSHMEM_WAIT_RESULT_TIMEOUT, + IVSHMEM_WAIT_RESULT_ERROR +}; + +enum IVSHMEMWaitResult ivshmem_wait_irq(uint16_t vector); +bool ivshmem_kick_irq(uint16_t clientID, uint16_t vector); \ No newline at end of file diff --git a/client/main.c b/client/main.c index df0db640..a2dc65db 100644 --- a/client/main.c +++ b/client/main.c @@ -211,7 +211,6 @@ void drawFunc_YUV420P(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, c int renderThread(void * unused) { - bool startup = true; struct KVMGFXHeader format; SDL_Texture *texture = NULL; uint8_t *pixels = (uint8_t*)(state.shm + 1); @@ -254,16 +253,40 @@ int renderThread(void * unused) if (memcmp(state.shm->magic, KVMGFX_HEADER_MAGIC, sizeof(KVMGFX_HEADER_MAGIC)) != 0) continue; - // if the frame count hasn't changed, we don't do anything - if (!startup && format.frames == state.shm->frames) - { - if (!state.running) - break; - - usleep(100); + if (state.shm->version != 2) continue; + + bool ready = false; + bool error = false; + while(state.running && !ready && !error) + { + // kick the guest and wait for a frame + ivshmem_kick_irq(state.shm->guestID, 0); + switch(ivshmem_wait_irq(0)) + { + case IVSHMEM_WAIT_RESULT_OK: + ready = true; + break; + + case IVSHMEM_WAIT_RESULT_TIMEOUT: + ready = false; + break; + + case IVSHMEM_WAIT_RESULT_ERROR: + error = true; + break; + } } - startup = false; + + if (error) + { + DEBUG_ERROR("error during wait for host"); + break; + } + +// continue; +// } +// startup = false; // if the format is invalid or it has changed if (format.frameType == FRAME_TYPE_INVALID || !areFormatsSame(format, *state.shm)) @@ -507,6 +530,7 @@ int main(int argc, char * argv[]) DEBUG_ERROR("Failed to map memory"); break; } + state.shm->hostID = ivshmem_get_id(); if (!spice_connect("127.0.0.1", 5900, "")) {