mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +00:00
[client] added support for LGMP
This commit is contained in:
parent
7a98a886b6
commit
2d755a45e0
@ -85,6 +85,8 @@ set(SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common")
|
add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common")
|
||||||
|
add_subdirectory("${PROJECT_TOP}/LGMP/lgmp" "${CMAKE_BINARY_DIR}/lgmp" )
|
||||||
|
|
||||||
add_subdirectory(spice)
|
add_subdirectory(spice)
|
||||||
add_subdirectory(renderers)
|
add_subdirectory(renderers)
|
||||||
add_subdirectory(clipboards)
|
add_subdirectory(clipboards)
|
||||||
@ -96,6 +98,7 @@ target_compile_options(looking-glass-client PUBLIC ${PKGCONFIG_CFLAGS_OTHER})
|
|||||||
target_link_libraries(looking-glass-client
|
target_link_libraries(looking-glass-client
|
||||||
${EXE_FLAGS}
|
${EXE_FLAGS}
|
||||||
lg_common
|
lg_common
|
||||||
|
lgmp
|
||||||
spice
|
spice
|
||||||
renderers
|
renderers
|
||||||
clipboards
|
clipboards
|
||||||
|
@ -236,41 +236,54 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
static int cursorThread(void * unused)
|
static int cursorThread(void * unused)
|
||||||
{
|
{
|
||||||
KVMFRCursor header;
|
LGMP_STATUS status;
|
||||||
|
PLGMPCQueue queue;
|
||||||
LG_RendererCursor cursorType = LG_CURSOR_COLOR;
|
LG_RendererCursor cursorType = LG_CURSOR_COLOR;
|
||||||
uint32_t version = 0;
|
|
||||||
|
|
||||||
memset(&header, 0, sizeof(KVMFRCursor));
|
|
||||||
|
|
||||||
lgWaitEvent(e_startup, TIMEOUT_INFINITE);
|
lgWaitEvent(e_startup, TIMEOUT_INFINITE);
|
||||||
|
|
||||||
|
// subscribe to the pointer queue
|
||||||
while(state.running)
|
while(state.running)
|
||||||
{
|
{
|
||||||
// poll until we have cursor data
|
status = lgmpClientSubscribe(state.lgmp, LGMP_Q_POINTER, &queue);
|
||||||
if(!(state.kvmfr->cursor.flags & KVMFR_CURSOR_FLAG_UPDATE) &&
|
if (status == LGMP_OK)
|
||||||
!(state.kvmfr->cursor.flags & KVMFR_CURSOR_FLAG_POS))
|
break;
|
||||||
|
|
||||||
|
if (status == LGMP_ERR_NO_SUCH_QUEUE)
|
||||||
{
|
{
|
||||||
if (!state.running)
|
usleep(1000);
|
||||||
return 0;
|
|
||||||
usleep(params.cursorPollInterval);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the cursor was moved
|
DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status));
|
||||||
bool moved = false;
|
state.running = false;
|
||||||
if (state.kvmfr->cursor.flags & KVMFR_CURSOR_FLAG_POS)
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(state.running)
|
||||||
|
{
|
||||||
|
LGMPMessage msg;
|
||||||
|
if ((status = lgmpClientProcess(queue, &msg)) != LGMP_OK)
|
||||||
{
|
{
|
||||||
state.cursor.x = state.kvmfr->cursor.x;
|
if (status == LGMP_ERR_QUEUE_EMPTY)
|
||||||
state.cursor.y = state.kvmfr->cursor.y;
|
{
|
||||||
state.haveCursorPos = true;
|
usleep(params.cursorPollInterval);
|
||||||
moved = true;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status));
|
||||||
|
state.running = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this was only a move event
|
KVMFRCursor * cursor = (KVMFRCursor *)msg.mem;
|
||||||
if (!(state.kvmfr->cursor.flags & KVMFR_CURSOR_FLAG_UPDATE))
|
state.cursor.x = cursor->x;
|
||||||
{
|
state.cursor.y = cursor->y;
|
||||||
// turn off the pos flag, trigger the event and continue
|
state.haveCursorPos = true;
|
||||||
__sync_and_and_fetch(&state.kvmfr->cursor.flags, ~KVMFR_CURSOR_FLAG_POS);
|
|
||||||
|
|
||||||
|
// if this was only a move event
|
||||||
|
if (msg.udata == 0)
|
||||||
|
{
|
||||||
state.lgr->on_mouse_event
|
state.lgr->on_mouse_event
|
||||||
(
|
(
|
||||||
state.lgrData,
|
state.lgrData,
|
||||||
@ -278,61 +291,40 @@ static int cursorThread(void * unused)
|
|||||||
state.cursor.x,
|
state.cursor.x,
|
||||||
state.cursor.y
|
state.cursor.y
|
||||||
);
|
);
|
||||||
|
lgmpClientMessageDone(queue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we must take a copy of the header to prevent the contained arguments
|
switch(cursor->type)
|
||||||
// from being abused to overflow buffers.
|
|
||||||
memcpy(&header, &state.kvmfr->cursor, sizeof(struct KVMFRCursor));
|
|
||||||
|
|
||||||
if (header.flags & KVMFR_CURSOR_FLAG_SHAPE &&
|
|
||||||
header.version != version)
|
|
||||||
{
|
{
|
||||||
version = header.version;
|
case CURSOR_TYPE_COLOR : cursorType = LG_CURSOR_COLOR ; break;
|
||||||
|
case CURSOR_TYPE_MONOCHROME : cursorType = LG_CURSOR_MONOCHROME ; break;
|
||||||
bool bad = false;
|
case CURSOR_TYPE_MASKED_COLOR: cursorType = LG_CURSOR_MASKED_COLOR; break;
|
||||||
switch(header.type)
|
default:
|
||||||
{
|
DEBUG_ERROR("Invalid cursor type");
|
||||||
case CURSOR_TYPE_COLOR : cursorType = LG_CURSOR_COLOR ; break;
|
lgmpClientMessageDone(queue);
|
||||||
case CURSOR_TYPE_MONOCHROME : cursorType = LG_CURSOR_MONOCHROME ; break;
|
continue;
|
||||||
case CURSOR_TYPE_MASKED_COLOR: cursorType = LG_CURSOR_MASKED_COLOR; break;
|
|
||||||
default:
|
|
||||||
DEBUG_ERROR("Invalid cursor type");
|
|
||||||
bad = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bad)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// check the data position is sane
|
|
||||||
const uint64_t dataSize = header.height * header.pitch;
|
|
||||||
if (header.dataPos + dataSize > state.shm.size)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("The guest sent an invalid mouse dataPos");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * data = (const uint8_t *)state.kvmfr + header.dataPos;
|
|
||||||
if (!state.lgr->on_mouse_shape(
|
|
||||||
state.lgrData,
|
|
||||||
cursorType,
|
|
||||||
header.width,
|
|
||||||
header.height,
|
|
||||||
header.pitch,
|
|
||||||
data)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Failed to update mouse shape");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we have taken the mouse data, we can flag to the host we are ready
|
const uint8_t * data = (const uint8_t *)(cursor + 1);
|
||||||
state.kvmfr->cursor.flags = 0;
|
if (!state.lgr->on_mouse_shape(
|
||||||
|
state.lgrData,
|
||||||
|
cursorType,
|
||||||
|
cursor->width,
|
||||||
|
cursor->height,
|
||||||
|
cursor->pitch,
|
||||||
|
data)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to update mouse shape");
|
||||||
|
lgmpClientMessageDone(queue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool showCursor = header.flags & KVMFR_CURSOR_FLAG_VISIBLE;
|
bool showCursor = cursor->visible;
|
||||||
if (showCursor != state.cursorVisible || moved)
|
lgmpClientMessageDone(queue);
|
||||||
|
|
||||||
|
if (showCursor != state.cursorVisible)
|
||||||
{
|
{
|
||||||
state.cursorVisible = showCursor;
|
state.cursorVisible = showCursor;
|
||||||
state.lgr->on_mouse_event
|
state.lgr->on_mouse_event
|
||||||
@ -345,67 +337,65 @@ static int cursorThread(void * unused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lgmpClientUnsubscribe(&queue);
|
||||||
|
state.running = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int frameThread(void * unused)
|
static int frameThread(void * unused)
|
||||||
{
|
{
|
||||||
bool error = false;
|
LGMP_STATUS status;
|
||||||
KVMFRFrame header;
|
PLGMPCQueue queue;
|
||||||
|
|
||||||
memset(&header, 0, sizeof(struct KVMFRFrame));
|
|
||||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||||
|
|
||||||
lgWaitEvent(e_startup, TIMEOUT_INFINITE);
|
lgWaitEvent(e_startup, TIMEOUT_INFINITE);
|
||||||
|
|
||||||
|
// subscribe to the frame queue
|
||||||
while(state.running)
|
while(state.running)
|
||||||
{
|
{
|
||||||
// poll until we have a new frame
|
status = lgmpClientSubscribe(state.lgmp, LGMP_Q_FRAME, &queue);
|
||||||
while(!(state.kvmfr->frame.flags & KVMFR_FRAME_FLAG_UPDATE))
|
if (status == LGMP_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status == LGMP_ERR_NO_SUCH_QUEUE)
|
||||||
{
|
{
|
||||||
if (!state.running)
|
|
||||||
break;
|
|
||||||
|
|
||||||
usleep(params.framePollInterval);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we must take a copy of the header to prevent the contained
|
|
||||||
// arguments from being abused to overflow buffers.
|
|
||||||
memcpy(&header, &state.kvmfr->frame, sizeof(struct KVMFRFrame));
|
|
||||||
|
|
||||||
// tell the host to continue as the host buffers up to one frame
|
|
||||||
// we can be sure the data for this frame wont be touched
|
|
||||||
__sync_and_and_fetch(&state.kvmfr->frame.flags, ~KVMFR_FRAME_FLAG_UPDATE);
|
|
||||||
|
|
||||||
// sainty check of the frame format
|
|
||||||
if (
|
|
||||||
header.type >= FRAME_TYPE_MAX ||
|
|
||||||
header.width == 0 ||
|
|
||||||
header.height == 0 ||
|
|
||||||
header.pitch == 0 ||
|
|
||||||
header.dataPos == 0 ||
|
|
||||||
header.dataPos > state.shm.size ||
|
|
||||||
header.pitch < header.width
|
|
||||||
){
|
|
||||||
DEBUG_WARN("Bad header");
|
|
||||||
DEBUG_WARN(" width : %u" , header.width );
|
|
||||||
DEBUG_WARN(" height : %u" , header.height );
|
|
||||||
DEBUG_WARN(" pitch : %u" , header.pitch );
|
|
||||||
DEBUG_WARN(" dataPos: 0x%08lx", header.dataPos);
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_ERROR("lgmpClientSubscribe Failed: %s", lgmpStatusString(status));
|
||||||
|
state.running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(state.running)
|
||||||
|
{
|
||||||
|
LGMPMessage msg;
|
||||||
|
if ((status = lgmpClientProcess(queue, &msg)) != LGMP_OK)
|
||||||
|
{
|
||||||
|
if (status == LGMP_ERR_QUEUE_EMPTY)
|
||||||
|
{
|
||||||
|
usleep(params.framePollInterval);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ERROR("lgmpClientProcess Failed: %s", lgmpStatusString(status));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
KVMFRFrame * frame = (KVMFRFrame *)msg.mem;
|
||||||
|
|
||||||
// setup the renderer format with the frame format details
|
// setup the renderer format with the frame format details
|
||||||
LG_RendererFormat lgrFormat;
|
LG_RendererFormat lgrFormat;
|
||||||
lgrFormat.type = header.type;
|
lgrFormat.type = frame->type;
|
||||||
lgrFormat.width = header.width;
|
lgrFormat.width = frame->width;
|
||||||
lgrFormat.height = header.height;
|
lgrFormat.height = frame->height;
|
||||||
lgrFormat.stride = header.stride;
|
lgrFormat.stride = frame->stride;
|
||||||
lgrFormat.pitch = header.pitch;
|
lgrFormat.pitch = frame->pitch;
|
||||||
|
|
||||||
size_t dataSize;
|
size_t dataSize;
|
||||||
switch(header.type)
|
bool error = false;
|
||||||
|
switch(frame->type)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_RGBA:
|
case FRAME_TYPE_RGBA:
|
||||||
case FRAME_TYPE_BGRA:
|
case FRAME_TYPE_BGRA:
|
||||||
@ -427,35 +417,32 @@ static int frameThread(void * unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
|
||||||
|
|
||||||
// check the header's dataPos is sane
|
|
||||||
if (header.dataPos + dataSize > state.shm.size)
|
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("The guest sent an invalid dataPos");
|
lgmpClientMessageDone(queue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.width != state.srcSize.x || header.height != state.srcSize.y)
|
if (frame->width != state.srcSize.x || frame->height != state.srcSize.y)
|
||||||
{
|
{
|
||||||
state.srcSize.x = header.width;
|
state.srcSize.x = frame->width;
|
||||||
state.srcSize.y = header.height;
|
state.srcSize.y = frame->height;
|
||||||
state.haveSrcSize = true;
|
state.haveSrcSize = true;
|
||||||
if (params.autoResize)
|
if (params.autoResize)
|
||||||
SDL_SetWindowSize(state.window, header.width, header.height);
|
SDL_SetWindowSize(state.window, frame->width, frame->height);
|
||||||
updatePositionInfo();
|
updatePositionInfo();
|
||||||
}
|
}
|
||||||
FrameBuffer frame = (FrameBuffer)((uint8_t *)state.kvmfr + header.dataPos);
|
|
||||||
|
|
||||||
if (!state.lgr->on_frame_event(state.lgrData, lgrFormat, frame))
|
FrameBuffer fb = (FrameBuffer)(frame + 1);
|
||||||
|
if (!state.lgr->on_frame_event(state.lgrData, lgrFormat, fb))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("renderer on frame event returned failure");
|
DEBUG_ERROR("renderer on frame event returned failure");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
lgmpClientMessageDone(queue);
|
||||||
++state.frameCount;
|
++state.frameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lgmpClientUnsubscribe(&queue);
|
||||||
state.running = false;
|
state.running = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1122,8 +1109,6 @@ static int lg_run()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.kvmfr = (struct KVMFRHeader*)state.shm.mem;
|
|
||||||
|
|
||||||
// try to connect to the spice server
|
// try to connect to the spice server
|
||||||
if (params.useSpiceInput || params.useSpiceClipboard)
|
if (params.useSpiceInput || params.useSpiceClipboard)
|
||||||
{
|
{
|
||||||
@ -1322,34 +1307,27 @@ static int lg_run()
|
|||||||
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);
|
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);
|
||||||
SDL_SetEventFilter(eventFilter, NULL);
|
SDL_SetEventFilter(eventFilter, NULL);
|
||||||
|
|
||||||
// flag the host that we are starting up this is important so that
|
LGMP_STATUS status;
|
||||||
// the host wakes up if it is waiting on an interrupt, the host will
|
while(true)
|
||||||
// also send us the current mouse shape since we won't know it yet
|
{
|
||||||
DEBUG_INFO("Waiting for host to signal it's ready...");
|
if ((status = lgmpClientInit(state.shm.mem, state.shm.size, &state.lgmp)) == LGMP_OK)
|
||||||
__sync_or_and_fetch(&state.kvmfr->flags, KVMFR_HEADER_FLAG_RESTART);
|
break;
|
||||||
|
|
||||||
while(state.running && (state.kvmfr->flags & KVMFR_HEADER_FLAG_RESTART))
|
if (status == LGMP_ERR_INVALID_SESSION)
|
||||||
SDL_WaitEventTimeout(NULL, 1000);
|
{
|
||||||
|
SDL_WaitEventTimeout(NULL, 1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ERROR("lgmpClientInit Failed: %s", lgmpStatusString(status));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!state.running)
|
if (!state.running)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
DEBUG_INFO("Host ready, starting session");
|
DEBUG_INFO("Host ready, starting session");
|
||||||
|
|
||||||
// check the header's magic and version are valid
|
|
||||||
if (memcmp(state.kvmfr->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC)) != 0)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("Invalid header magic, is the host running?");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.kvmfr->version != KVMFR_HEADER_VERSION)
|
|
||||||
{
|
|
||||||
DEBUG_ERROR("KVMFR version missmatch, expected %u but got %u", KVMFR_HEADER_VERSION, state.kvmfr->version);
|
|
||||||
DEBUG_ERROR("This is not a bug, ensure you have the right version of looking-glass-host.exe on the guest");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lgCreateThread("cursorThread", cursorThread, NULL, &t_cursor))
|
if (!lgCreateThread("cursorThread", cursorThread, NULL, &t_cursor))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("cursor create thread failed");
|
DEBUG_ERROR("cursor create thread failed");
|
||||||
@ -1367,6 +1345,14 @@ static int lg_run()
|
|||||||
{
|
{
|
||||||
SDL_WaitEventTimeout(NULL, 1000);
|
SDL_WaitEventTimeout(NULL, 1000);
|
||||||
|
|
||||||
|
if (!lgmpClientSessionValid(state.lgmp))
|
||||||
|
{
|
||||||
|
DEBUG_WARN("Session is invalid, has the host shutdown?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)closeAlert;
|
||||||
|
/*
|
||||||
if (closeAlert == NULL)
|
if (closeAlert == NULL)
|
||||||
{
|
{
|
||||||
if (state.kvmfr->flags & KVMFR_HEADER_FLAG_PAUSED)
|
if (state.kvmfr->flags & KVMFR_HEADER_FLAG_PAUSED)
|
||||||
@ -1388,6 +1374,7 @@ static int lg_run()
|
|||||||
closeAlert = NULL;
|
closeAlert = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1400,6 +1387,8 @@ static void lg_shutdown()
|
|||||||
if (t_render)
|
if (t_render)
|
||||||
lgJoinThread(t_render, NULL);
|
lgJoinThread(t_render, NULL);
|
||||||
|
|
||||||
|
lgmpClientFree(&state.lgmp);
|
||||||
|
|
||||||
if (e_startup)
|
if (e_startup)
|
||||||
{
|
{
|
||||||
lgFreeEvent(e_startup);
|
lgFreeEvent(e_startup);
|
||||||
|
@ -26,6 +26,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "common/ivshmem.h"
|
#include "common/ivshmem.h"
|
||||||
|
|
||||||
#include "spice/spice.h"
|
#include "spice/spice.h"
|
||||||
|
#include <lgmp/client.h>
|
||||||
|
|
||||||
struct AppState
|
struct AppState
|
||||||
{
|
{
|
||||||
@ -58,7 +59,9 @@ struct AppState
|
|||||||
SDL_Window * window;
|
SDL_Window * window;
|
||||||
|
|
||||||
struct IVSHMEM shm;
|
struct IVSHMEM shm;
|
||||||
struct KVMFRHeader * kvmfr;
|
PLGMPClient lgmp;
|
||||||
|
PLGMPCQueue frameQueue;
|
||||||
|
PLGMPCQueue pointerQueue;
|
||||||
|
|
||||||
uint64_t frameTime;
|
uint64_t frameTime;
|
||||||
uint64_t lastFrameTime;
|
uint64_t lastFrameTime;
|
||||||
|
@ -25,12 +25,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
struct LGEvent
|
struct LGEvent
|
||||||
{
|
{
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_cond_t cond;
|
pthread_cond_t cond;
|
||||||
bool flag;
|
uint32_t flag;
|
||||||
bool autoReset;
|
bool autoReset;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,7 +60,6 @@ LGEvent * lgCreateEvent(bool autoReset, unsigned int msSpinTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle->autoReset = autoReset;
|
handle->autoReset = autoReset;
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(!handle->flag)
|
while(!atomic_load(&handle->flag))
|
||||||
{
|
{
|
||||||
if (timeout == TIMEOUT_INFINITE)
|
if (timeout == TIMEOUT_INFINITE)
|
||||||
{
|
{
|
||||||
@ -109,7 +110,7 @@ bool lgWaitEvent(LGEvent * handle, unsigned int timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (handle->autoReset)
|
if (handle->autoReset)
|
||||||
handle->flag = false;
|
atomic_store(&handle->flag, 0);
|
||||||
|
|
||||||
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
||||||
{
|
{
|
||||||
@ -130,7 +131,7 @@ bool lgSignalEvent(LGEvent * handle)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->flag = true;
|
atomic_store(&handle->flag, 1);
|
||||||
|
|
||||||
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
||||||
{
|
{
|
||||||
@ -157,7 +158,7 @@ bool lgResetEvent(LGEvent * handle)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->flag = false;
|
atomic_store(&handle->flag, 0);
|
||||||
|
|
||||||
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
if (pthread_mutex_unlock(&handle->mutex) != 0)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user