diff --git a/VERSION b/VERSION index 5eef5933..06cfe81a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -B1-40-g491ffc3576+1 \ No newline at end of file +B1-41-g0c6ff6822d+1 \ No newline at end of file diff --git a/c-host/platform/Linux/capture/XCB/src/xcb.c b/c-host/platform/Linux/capture/XCB/src/xcb.c index 8e5166b0..3914de3d 100644 --- a/c-host/platform/Linux/capture/XCB/src/xcb.c +++ b/c-host/platform/Linux/capture/XCB/src/xcb.c @@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "interface/capture.h" #include "interface/platform.h" #include "common/debug.h" +#include "common/event.h" #include #include #include @@ -37,7 +38,7 @@ struct xcb uint32_t seg; int shmID; void * data; - osEventHandle * frameEvent; + LGEvent * frameEvent; unsigned int width; unsigned int height; @@ -67,7 +68,7 @@ static bool xcb_create() this = (struct xcb *)calloc(sizeof(struct xcb), 1); this->shmID = -1; this->data = (void *)-1; - this->frameEvent = os_createEvent(true); + this->frameEvent = lgCreateEvent(true, 20); if (!this->frameEvent) { @@ -84,7 +85,7 @@ static bool xcb_init() assert(this); assert(!this->initialized); - os_resetEvent(this->frameEvent); + lgResetEvent(this->frameEvent); this->xcb = xcb_connect(NULL, NULL); if (!this->xcb || xcb_connection_has_error(this->xcb)) @@ -158,7 +159,7 @@ static bool xcb_deinit() static void xcb_free() { - os_freeEvent(this->frameEvent); + lgFreeEvent(this->frameEvent); free(this); this = NULL; } @@ -187,20 +188,29 @@ static CaptureResult xcb_capture() 0); this->hasFrame = true; - os_signalEvent(this->frameEvent); + lgSignalEvent(this->frameEvent); } return CAPTURE_RESULT_OK; } -static CaptureResult xcb_getFrame(CaptureFrame * frame) +static CaptureResult xcb_waitFrame(CaptureFrame * frame) +{ + lgWaitEvent(this->frameEvent, TIMEOUT_INFINITE); + + frame->width = this->width; + frame->height = this->height; + frame->pitch = this->width * 4; + frame->stride = this->width; + frame->format = CAPTURE_FMT_BGRA; + + return CAPTURE_RESULT_OK; +} + +static CaptureResult xcb_getFrame(FrameBuffer frame) { assert(this); assert(this->initialized); - assert(frame); - assert(frame->data); - - os_waitEvent(this->frameEvent, TIMEOUT_INFINITE); xcb_shm_get_image_reply_t * img; img = xcb_shm_get_image_reply(this->xcb, this->imgC, NULL); @@ -210,12 +220,7 @@ static CaptureResult xcb_getFrame(CaptureFrame * frame) return CAPTURE_RESULT_ERROR; } - frame->width = this->width; - frame->height = this->height; - frame->pitch = this->width * 4; - frame->stride = this->width; - frame->format = CAPTURE_FMT_BGRA; - memcpy(frame->data, this->data, this->width * this->height * 4); + framebuffer_write(frame, this->data, this->width * this->height * 4); free(img); this->hasFrame = false; @@ -237,6 +242,7 @@ struct CaptureInterface Capture_XCB = .free = xcb_free, .getMaxFrameSize = xcb_getMaxFrameSize, .capture = xcb_capture, + .waitFrame = xcb_waitFrame, .getFrame = xcb_getFrame, .getPointer = xcb_getPointer }; \ No newline at end of file diff --git a/c-host/platform/Linux/src/platform.c b/c-host/platform/Linux/src/platform.c index 5c79dcae..5a6ea044 100644 --- a/c-host/platform/Linux/src/platform.c +++ b/c-host/platform/Linux/src/platform.c @@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "interface/platform.h" #include "common/debug.h" #include "common/option.h" +#include "common/thread.h" #include #include @@ -44,15 +45,6 @@ struct app static struct app app; -struct osThreadHandle -{ - const char * name; - osThreadFunction function; - void * opaque; - pthread_t handle; - int resultCode; -}; - void sigHandler(int signo) { DEBUG_INFO("SIGINT"); @@ -268,186 +260,4 @@ void os_shmemUnmap() munmap(app.shmMap, app.shmSize); app.shmMap = MAP_FAILED; -} - -static void * threadWrapper(void * opaque) -{ - osThreadHandle * handle = (osThreadHandle *)opaque; - handle->resultCode = handle->function(handle->opaque); - return NULL; -} - -bool os_createThread(const char * name, osThreadFunction function, void * opaque, osThreadHandle ** handle) -{ - *handle = (osThreadHandle*)malloc(sizeof(osThreadHandle)); - (*handle)->name = name; - (*handle)->function = function; - (*handle)->opaque = opaque; - - if (pthread_create(&(*handle)->handle, NULL, threadWrapper, *handle) != 0) - { - DEBUG_ERROR("pthread_create failed for thread: %s", name); - free(*handle); - *handle = NULL; - return false; - } - return true; -} - -bool os_joinThread(osThreadHandle * handle, int * resultCode) -{ - if (pthread_join(handle->handle, NULL) != 0) - { - DEBUG_ERROR("pthread_join failed for thread: %s", handle->name); - free(handle); - return false; - } - - if (resultCode) - *resultCode = handle->resultCode; - - free(handle); - return true; -} - -struct osEventHandle -{ - pthread_mutex_t mutex; - pthread_cond_t cond; - bool flag; - bool autoReset; -}; - -osEventHandle * os_createEvent(bool autoReset) -{ - osEventHandle * handle = (osEventHandle *)calloc(sizeof(osEventHandle), 1); - if (!handle) - { - DEBUG_ERROR("Failed to allocate memory"); - return NULL; - } - - if (pthread_mutex_init(&handle->mutex, NULL) != 0) - { - DEBUG_ERROR("Failed to create the mutex"); - free(handle); - return NULL; - } - - if (pthread_cond_init(&handle->cond, NULL) != 0) - { - pthread_mutex_destroy(&handle->mutex); - free(handle); - return NULL; - } - - handle->autoReset = autoReset; - - return handle; -} - -void os_freeEvent(osEventHandle * handle) -{ - assert(handle); - - pthread_cond_destroy (&handle->cond ); - pthread_mutex_destroy(&handle->mutex); - free(handle); -} - -bool os_waitEvent(osEventHandle * handle, unsigned int timeout) -{ - assert(handle); - - if (pthread_mutex_lock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to lock the mutex"); - return false; - } - - while(!handle->flag) - { - if (timeout == TIMEOUT_INFINITE) - { - if (pthread_cond_wait(&handle->cond, &handle->mutex) != 0) - { - DEBUG_ERROR("Wait to wait on the condition"); - return false; - } - } - else - { - struct timespec ts; - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - switch(pthread_cond_timedwait(&handle->cond, &handle->mutex, &ts)) - { - case ETIMEDOUT: - return false; - - default: - DEBUG_ERROR("Timed wait failed"); - return false; - } - } - } - - if (handle->autoReset) - handle->flag = false; - - if (pthread_mutex_unlock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to unlock the mutex"); - return false; - } - - return true; -} - -bool os_signalEvent(osEventHandle * handle) -{ - assert(handle); - - if (pthread_mutex_lock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to lock the mutex"); - return false; - } - - handle->flag = true; - - if (pthread_mutex_unlock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to unlock the mutex"); - return false; - } - - if (pthread_cond_signal(&handle->cond) != 0) - { - DEBUG_ERROR("Failed to signal the condition"); - return false; - } - - return true; -} - -bool os_resetEvent(osEventHandle * handle) -{ - assert(handle); - - if (pthread_mutex_lock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to lock the mutex"); - return false; - } - - handle->flag = false; - - if (pthread_mutex_unlock(&handle->mutex) != 0) - { - DEBUG_ERROR("Failed to unlock the mutex"); - return false; - } - - return true; } \ No newline at end of file diff --git a/common/src/platform/linux/CMakeLists.txt b/common/src/platform/linux/CMakeLists.txt index 695c8c91..51128e44 100644 --- a/common/src/platform/linux/CMakeLists.txt +++ b/common/src/platform/linux/CMakeLists.txt @@ -8,4 +8,10 @@ include_directories( add_library(lg_common_platform_code STATIC crash.c sysinfo.c + thread.c + event.c ) + +if(ENABLE_BACKTRACE) + target_link_libraries(lg_common_platform_code bfd) +endif() diff --git a/common/src/platform/linux/event.c b/common/src/platform/linux/event.c new file mode 100644 index 00000000..dc0d1a2c --- /dev/null +++ b/common/src/platform/linux/event.c @@ -0,0 +1,169 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2019 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common/event.h" + +#include "common/debug.h" + +#include +#include +#include +#include + +struct LGEvent +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + bool flag; + bool autoReset; +}; + +LGEvent * lgCreateEvent(bool autoReset, unsigned int msSpinTime) +{ + LGEvent * handle = (LGEvent *)calloc(sizeof(LGEvent), 1); + if (!handle) + { + DEBUG_ERROR("Failed to allocate memory"); + return NULL; + } + + if (pthread_mutex_init(&handle->mutex, NULL) != 0) + { + DEBUG_ERROR("Failed to create the mutex"); + free(handle); + return NULL; + } + + if (pthread_cond_init(&handle->cond, NULL) != 0) + { + pthread_mutex_destroy(&handle->mutex); + free(handle); + return NULL; + } + + handle->autoReset = autoReset; + + return handle; +} + +void lgFreeEvent(LGEvent * handle) +{ + assert(handle); + + pthread_cond_destroy (&handle->cond ); + pthread_mutex_destroy(&handle->mutex); + free(handle); +} + +bool lgWaitEvent(LGEvent * handle, unsigned int timeout) +{ + assert(handle); + + if (pthread_mutex_lock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to lock the mutex"); + return false; + } + + while(!handle->flag) + { + if (timeout == TIMEOUT_INFINITE) + { + if (pthread_cond_wait(&handle->cond, &handle->mutex) != 0) + { + DEBUG_ERROR("Wait to wait on the condition"); + return false; + } + } + else + { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + switch(pthread_cond_timedwait(&handle->cond, &handle->mutex, &ts)) + { + case ETIMEDOUT: + return false; + + default: + DEBUG_ERROR("Timed wait failed"); + return false; + } + } + } + + if (handle->autoReset) + handle->flag = false; + + if (pthread_mutex_unlock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to unlock the mutex"); + return false; + } + + return true; +} + +bool lgSignalEvent(LGEvent * handle) +{ + assert(handle); + + if (pthread_mutex_lock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to lock the mutex"); + return false; + } + + handle->flag = true; + + if (pthread_mutex_unlock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to unlock the mutex"); + return false; + } + + if (pthread_cond_signal(&handle->cond) != 0) + { + DEBUG_ERROR("Failed to signal the condition"); + return false; + } + + return true; +} + +bool lgResetEvent(LGEvent * handle) +{ + assert(handle); + + if (pthread_mutex_lock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to lock the mutex"); + return false; + } + + handle->flag = false; + + if (pthread_mutex_unlock(&handle->mutex) != 0) + { + DEBUG_ERROR("Failed to unlock the mutex"); + return false; + } + + return true; +} \ No newline at end of file diff --git a/common/src/platform/linux/thread.c b/common/src/platform/linux/thread.c new file mode 100644 index 00000000..1d42c574 --- /dev/null +++ b/common/src/platform/linux/thread.c @@ -0,0 +1,74 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017-2020 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common/thread.h" + +#include +#include + +#include "common/debug.h" + +struct LGThread +{ + const char * name; + LGThreadFunction function; + void * opaque; + pthread_t handle; + int resultCode; +}; + +static void * threadWrapper(void * opaque) +{ + LGThread * handle = (LGThread *)opaque; + handle->resultCode = handle->function(handle->opaque); + return NULL; +} + +bool lgCreateThread(const char * name, LGThreadFunction function, void * opaque, LGThread ** handle) +{ + *handle = (LGThread*)malloc(sizeof(LGThread)); + (*handle)->name = name; + (*handle)->function = function; + (*handle)->opaque = opaque; + + if (pthread_create(&(*handle)->handle, NULL, threadWrapper, *handle) != 0) + { + DEBUG_ERROR("pthread_create failed for thread: %s", name); + free(*handle); + *handle = NULL; + return false; + } + return true; +} + +bool lgJoinThread(LGThread * handle, int * resultCode) +{ + if (pthread_join(handle->handle, NULL) != 0) + { + DEBUG_ERROR("pthread_join failed for thread: %s", handle->name); + free(handle); + return false; + } + + if (resultCode) + *resultCode = handle->resultCode; + + free(handle); + return true; +} \ No newline at end of file