[client] implemented the new ivshmem interrupt sync system

This commit is contained in:
Geoffrey McRae 2017-10-20 01:03:39 +11:00
parent 3a7bff77f2
commit b871d6d8d0
4 changed files with 119 additions and 11 deletions

View File

@ -23,6 +23,8 @@ struct KVMGFXHeader
{ {
char magic[sizeof(KVMGFX_HEADER_MAGIC)]; char magic[sizeof(KVMGFX_HEADER_MAGIC)];
uint32_t version; // version of this structure 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 FrameType frameType; // the frame type
FrameComp compType; // frame compression mode FrameComp compType; // frame compression mode
uint32_t width; // the width uint32_t width; // the width

View File

@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -270,6 +271,7 @@ bool ivshmem_read_msg(int64_t * index, int * fd)
if (!fd) if (!fd)
return true; return true;
*fd = -1;
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, 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; continue;
} }
memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd)); *fd = *(int*)CMSG_DATA(cmsg);
} }
return true; return true;
} }
// ============================================================================
uint16_t ivshmem_get_id() uint16_t ivshmem_get_id()
{ {
if (!ivshmem.connected) if (!ivshmem.connected)
@ -456,3 +460,71 @@ bool ivshmem_process()
client->irqs[client->irqCount++] = fd; client->irqs[client->irqCount++] = fd;
return true; 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;
}

View File

@ -9,3 +9,13 @@ bool ivshmem_process();
uint16_t ivshmem_get_id(); uint16_t ivshmem_get_id();
void * ivshmem_get_map(); void * ivshmem_get_map();
size_t ivshmem_get_map_size(); 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);

View File

@ -211,7 +211,6 @@ void drawFunc_YUV420P(CompFunc compFunc, SDL_Texture * texture, uint8_t * dst, c
int renderThread(void * unused) int renderThread(void * unused)
{ {
bool startup = true;
struct KVMGFXHeader format; struct KVMGFXHeader format;
SDL_Texture *texture = NULL; SDL_Texture *texture = NULL;
uint8_t *pixels = (uint8_t*)(state.shm + 1); 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) if (memcmp(state.shm->magic, KVMGFX_HEADER_MAGIC, sizeof(KVMGFX_HEADER_MAGIC)) != 0)
continue; continue;
// if the frame count hasn't changed, we don't do anything if (state.shm->version != 2)
if (!startup && format.frames == state.shm->frames) continue;
bool ready = false;
bool error = false;
while(state.running && !ready && !error)
{ {
if (!state.running) // 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; break;
usleep(100); case IVSHMEM_WAIT_RESULT_TIMEOUT:
continue; 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 the format is invalid or it has changed
if (format.frameType == FRAME_TYPE_INVALID || !areFormatsSame(format, *state.shm)) 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"); DEBUG_ERROR("Failed to map memory");
break; break;
} }
state.shm->hostID = ivshmem_get_id();
if (!spice_connect("127.0.0.1", 5900, "")) if (!spice_connect("127.0.0.1", 5900, ""))
{ {