mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 13:37:22 +00:00
[common] moved linux agnostic code into the common library
This commit is contained in:
parent
0c6ff6822d
commit
1c1d2a0568
@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "interface/capture.h"
|
#include "interface/capture.h"
|
||||||
#include "interface/platform.h"
|
#include "interface/platform.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
|
#include "common/event.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -37,7 +38,7 @@ struct xcb
|
|||||||
uint32_t seg;
|
uint32_t seg;
|
||||||
int shmID;
|
int shmID;
|
||||||
void * data;
|
void * data;
|
||||||
osEventHandle * frameEvent;
|
LGEvent * frameEvent;
|
||||||
|
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
@ -67,7 +68,7 @@ static bool xcb_create()
|
|||||||
this = (struct xcb *)calloc(sizeof(struct xcb), 1);
|
this = (struct xcb *)calloc(sizeof(struct xcb), 1);
|
||||||
this->shmID = -1;
|
this->shmID = -1;
|
||||||
this->data = (void *)-1;
|
this->data = (void *)-1;
|
||||||
this->frameEvent = os_createEvent(true);
|
this->frameEvent = lgCreateEvent(true, 20);
|
||||||
|
|
||||||
if (!this->frameEvent)
|
if (!this->frameEvent)
|
||||||
{
|
{
|
||||||
@ -84,7 +85,7 @@ static bool xcb_init()
|
|||||||
assert(this);
|
assert(this);
|
||||||
assert(!this->initialized);
|
assert(!this->initialized);
|
||||||
|
|
||||||
os_resetEvent(this->frameEvent);
|
lgResetEvent(this->frameEvent);
|
||||||
|
|
||||||
this->xcb = xcb_connect(NULL, NULL);
|
this->xcb = xcb_connect(NULL, NULL);
|
||||||
if (!this->xcb || xcb_connection_has_error(this->xcb))
|
if (!this->xcb || xcb_connection_has_error(this->xcb))
|
||||||
@ -158,7 +159,7 @@ static bool xcb_deinit()
|
|||||||
|
|
||||||
static void xcb_free()
|
static void xcb_free()
|
||||||
{
|
{
|
||||||
os_freeEvent(this->frameEvent);
|
lgFreeEvent(this->frameEvent);
|
||||||
free(this);
|
free(this);
|
||||||
this = NULL;
|
this = NULL;
|
||||||
}
|
}
|
||||||
@ -187,20 +188,29 @@ static CaptureResult xcb_capture()
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
this->hasFrame = true;
|
this->hasFrame = true;
|
||||||
os_signalEvent(this->frameEvent);
|
lgSignalEvent(this->frameEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CAPTURE_RESULT_OK;
|
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);
|
||||||
assert(this->initialized);
|
assert(this->initialized);
|
||||||
assert(frame);
|
|
||||||
assert(frame->data);
|
|
||||||
|
|
||||||
os_waitEvent(this->frameEvent, TIMEOUT_INFINITE);
|
|
||||||
|
|
||||||
xcb_shm_get_image_reply_t * img;
|
xcb_shm_get_image_reply_t * img;
|
||||||
img = xcb_shm_get_image_reply(this->xcb, this->imgC, NULL);
|
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;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->width = this->width;
|
framebuffer_write(frame, this->data, this->width * this->height * 4);
|
||||||
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);
|
|
||||||
free(img);
|
free(img);
|
||||||
|
|
||||||
this->hasFrame = false;
|
this->hasFrame = false;
|
||||||
@ -237,6 +242,7 @@ struct CaptureInterface Capture_XCB =
|
|||||||
.free = xcb_free,
|
.free = xcb_free,
|
||||||
.getMaxFrameSize = xcb_getMaxFrameSize,
|
.getMaxFrameSize = xcb_getMaxFrameSize,
|
||||||
.capture = xcb_capture,
|
.capture = xcb_capture,
|
||||||
|
.waitFrame = xcb_waitFrame,
|
||||||
.getFrame = xcb_getFrame,
|
.getFrame = xcb_getFrame,
|
||||||
.getPointer = xcb_getPointer
|
.getPointer = xcb_getPointer
|
||||||
};
|
};
|
@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "interface/platform.h"
|
#include "interface/platform.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/option.h"
|
#include "common/option.h"
|
||||||
|
#include "common/thread.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -44,15 +45,6 @@ struct app
|
|||||||
|
|
||||||
static struct app app;
|
static struct app app;
|
||||||
|
|
||||||
struct osThreadHandle
|
|
||||||
{
|
|
||||||
const char * name;
|
|
||||||
osThreadFunction function;
|
|
||||||
void * opaque;
|
|
||||||
pthread_t handle;
|
|
||||||
int resultCode;
|
|
||||||
};
|
|
||||||
|
|
||||||
void sigHandler(int signo)
|
void sigHandler(int signo)
|
||||||
{
|
{
|
||||||
DEBUG_INFO("SIGINT");
|
DEBUG_INFO("SIGINT");
|
||||||
@ -269,185 +261,3 @@ void os_shmemUnmap()
|
|||||||
munmap(app.shmMap, app.shmSize);
|
munmap(app.shmMap, app.shmSize);
|
||||||
app.shmMap = MAP_FAILED;
|
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;
|
|
||||||
}
|
|
@ -8,4 +8,10 @@ include_directories(
|
|||||||
add_library(lg_common_platform_code STATIC
|
add_library(lg_common_platform_code STATIC
|
||||||
crash.c
|
crash.c
|
||||||
sysinfo.c
|
sysinfo.c
|
||||||
|
thread.c
|
||||||
|
event.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ENABLE_BACKTRACE)
|
||||||
|
target_link_libraries(lg_common_platform_code bfd)
|
||||||
|
endif()
|
||||||
|
169
common/src/platform/linux/event.c
Normal file
169
common/src/platform/linux/event.c
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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 <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
74
common/src/platform/linux/thread.c
Normal file
74
common/src/platform/linux/thread.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||||
|
Copyright (C) 2017-2020 Geoffrey McRae <geoff@hostfission.com>
|
||||||
|
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 <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user