310 lines
9.0 KiB
C
310 lines
9.0 KiB
C
/***************************************************************************//**
|
||
@file osspec.c
|
||
Файл содержит некоторые внутренние функции, которые скрывают вызовы ОС:
|
||
функции работы с объектами синхронизации, потоками и т.д.
|
||
|
||
@author Borisov Alexey <borisov@lcard.ru>
|
||
@date 28.05.2012
|
||
***************************************************************************/
|
||
#include "osspec.h"
|
||
#include <stdlib.h>
|
||
|
||
|
||
#ifndef _WIN32
|
||
#include <sys/time.h>
|
||
#include <errno.h>
|
||
|
||
|
||
|
||
static void f_get_abs_time(uint32_t timeout, struct timespec *timeToWait) {
|
||
#ifdef NO_CLOCKGETTIME
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
timeToWait->tv_sec = tv.tv_sec;
|
||
timeToWait->tv_nsec = tv.tv_usec * 1000;
|
||
#else
|
||
clock_gettime(CLOCK_REALTIME, timeToWait);
|
||
#endif
|
||
timeToWait->tv_sec += timeout/1000;
|
||
timeToWait->tv_nsec += 1000000*(timeout%1000) + 1;
|
||
while (timeToWait->tv_nsec >= 1000000000) {
|
||
timeToWait->tv_sec++;
|
||
timeToWait->tv_nsec -=1000000000;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifdef OSSPEC_USE_MUTEX
|
||
/***************************************************************************
|
||
Вспомогательная функции для работы с мьютексами....
|
||
**************************************************************************/
|
||
//создание мьютекса
|
||
t_mutex osspec_mutex_create(void) {
|
||
t_mutex hnd;
|
||
#ifdef _WIN32
|
||
hnd = CreateMutex(NULL, FALSE, NULL);
|
||
#else
|
||
hnd = (t_mutex)malloc(sizeof(pthread_mutex_t));
|
||
if (hnd!=NULL) {
|
||
int err = pthread_mutex_init(hnd, NULL);
|
||
if (err) {
|
||
free(hnd);
|
||
hnd = OSSPEC_INVALID_MUTEX;
|
||
}
|
||
} else {
|
||
hnd = OSSPEC_INVALID_MUTEX;
|
||
}
|
||
#endif
|
||
return hnd;
|
||
}
|
||
|
||
|
||
|
||
//захват мьютекса
|
||
int32_t osspec_mutex_lock(t_mutex handle, uint32_t timeout) {
|
||
int32_t err = 0;
|
||
if (handle == OSSPEC_INVALID_MUTEX)
|
||
err = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
|
||
#ifdef _WIN32
|
||
if (!err) {
|
||
err = WaitForSingleObject(handle, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_MUTEX_LOCK_TOUT;
|
||
}
|
||
#else
|
||
if (!err) {
|
||
int wt_res;
|
||
#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||
if (timeout == OSSPEC_TIMEOUT_INFINITY) {
|
||
wt_res = pthread_mutex_lock(handle);
|
||
} else {
|
||
struct timespec timeToWait;
|
||
f_get_abs_time(timeout, &timeToWait);
|
||
wt_res = pthread_mutex_timedlock(handle, &timeToWait);
|
||
}
|
||
#else // HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||
(void)timeout;
|
||
wt_res = pthread_mutex_lock(handle);
|
||
#endif // HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||
if (wt_res == ETIMEDOUT) {
|
||
err = OSSPEC_ERR_MUTEX_LOCK_TOUT;
|
||
} else if (wt_res != 0) {
|
||
err = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
|
||
}
|
||
}
|
||
#endif
|
||
return err;
|
||
}
|
||
|
||
//освобождение мьютекса
|
||
int32_t osspec_mutex_release(t_mutex handle) {
|
||
int32_t res = 0;
|
||
if (handle == OSSPEC_INVALID_MUTEX)
|
||
res = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
|
||
#ifdef _WIN32
|
||
if (!res)
|
||
res = ReleaseMutex(handle) ? 0 : OSSPEC_ERR_MUTEX_RELEASE;
|
||
#else
|
||
if (!res && pthread_mutex_unlock(handle))
|
||
res = OSSPEC_ERR_MUTEX_RELEASE;
|
||
#endif
|
||
return res;
|
||
}
|
||
|
||
int32_t osspec_mutex_destroy(t_mutex handle) {
|
||
int32_t res = (handle != OSSPEC_INVALID_MUTEX) ?
|
||
0 : OSSPEC_ERR_MUTEX_INVALID_HANDLE;
|
||
#ifdef _WIN32
|
||
if (!res)
|
||
CloseHandle(handle);
|
||
#else
|
||
if (!res) {
|
||
pthread_mutex_destroy(handle);
|
||
free(handle);
|
||
}
|
||
#endif
|
||
return res;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
#ifdef OSSPEC_USE_EVENTS
|
||
#ifdef _WIN32
|
||
|
||
#else
|
||
struct st_osspec_event {
|
||
pthread_cond_t cond;
|
||
pthread_mutex_t mutex;
|
||
int flags;
|
||
int val;
|
||
};
|
||
#endif
|
||
|
||
|
||
t_event osspec_event_create(int32_t flags) {
|
||
t_event evt;
|
||
#ifdef _WIN32
|
||
evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
#else
|
||
evt = malloc(sizeof(struct st_osspec_event));
|
||
if (evt!=NULL) {
|
||
if (pthread_mutex_init(&evt->mutex, NULL) != 0) {
|
||
free(evt);
|
||
evt = NULL;
|
||
} else {
|
||
if (pthread_cond_init(&evt->cond, NULL)!= 0) {
|
||
pthread_mutex_destroy(&evt->mutex);
|
||
free(evt);
|
||
evt = NULL;
|
||
} else {
|
||
evt->flags = flags;
|
||
evt->val = 0;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
return evt;
|
||
}
|
||
|
||
int32_t osspec_event_destroy(t_event event) {
|
||
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
|
||
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
#ifdef _WIN32
|
||
if (!res)
|
||
CloseHandle(event);
|
||
#else
|
||
if (!res) {
|
||
pthread_mutex_destroy(&event->mutex);
|
||
pthread_cond_destroy(&event->cond);
|
||
free(event);
|
||
}
|
||
#endif
|
||
return res;
|
||
}
|
||
|
||
int32_t osspec_event_set(t_event event) {
|
||
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
|
||
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
if (res == 0) {
|
||
#ifdef _WIN32
|
||
if (!SetEvent(event))
|
||
res = OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
#else
|
||
pthread_mutex_lock(&event->mutex);
|
||
if (!event->val) {
|
||
event->val = 1;
|
||
pthread_cond_signal(&event->cond);
|
||
}
|
||
pthread_mutex_unlock(&event->mutex);
|
||
#endif
|
||
}
|
||
return res;
|
||
|
||
}
|
||
|
||
int32_t osspec_event_clear(t_event event) {
|
||
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
|
||
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
if (res == 0) {
|
||
#ifdef _WIN32
|
||
if (!ResetEvent(event))
|
||
res = OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
#else
|
||
pthread_mutex_lock(&event->mutex);
|
||
event->val = 0;
|
||
pthread_mutex_unlock(&event->mutex);
|
||
#endif
|
||
}
|
||
return res;
|
||
}
|
||
|
||
int32_t osspec_event_wait(t_event event, uint32_t timeout) {
|
||
int32_t err = (event != OSSPEC_INVALID_EVENT) ?
|
||
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
if (err == 0) {
|
||
#ifdef _WIN32
|
||
err = WaitForSingleObject(event, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_EVENT_WAIT_TOUT;
|
||
#else
|
||
struct timespec timeToWait;
|
||
int out = 0;
|
||
if (timeout != OSSPEC_TIMEOUT_INFINITY)
|
||
f_get_abs_time(timeout, &timeToWait);
|
||
|
||
while (!out && !err) {
|
||
pthread_mutex_lock(&event->mutex);
|
||
if (!event->val) {
|
||
int wait_res = timeout == OSSPEC_TIMEOUT_INFINITY ?
|
||
pthread_cond_wait(&event->cond,&event->mutex) :
|
||
pthread_cond_timedwait(&event->cond,&event->mutex, &timeToWait);
|
||
if (event->val) {
|
||
out = 1;
|
||
} else if (wait_res == ETIMEDOUT) {
|
||
err = OSSPEC_ERR_EVENT_WAIT_TOUT;
|
||
} else if (wait_res == EINVAL) {
|
||
err = OSSPEC_ERR_EVENT_INVALID_HANDLE;
|
||
}
|
||
} else {
|
||
out = 1;
|
||
}
|
||
pthread_mutex_unlock(&event->mutex);
|
||
}
|
||
#endif
|
||
}
|
||
return err;
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
#ifdef OSSPEC_USE_THREADS
|
||
t_thread osspec_thread_create(t_osspec_thread_func func, void *arg, uint32_t flags) {
|
||
t_thread thread;
|
||
#ifdef _WIN32
|
||
thread = CreateThread(NULL, 0, func, arg, 0, NULL);
|
||
#else
|
||
if (pthread_create(&thread, NULL, func, arg) != 0) {
|
||
thread = OSSPEC_INVALID_THREAD;
|
||
}
|
||
#endif
|
||
return thread;
|
||
}
|
||
|
||
int32_t osspec_thread_wait(t_thread thread, uint32_t timeout) {
|
||
int32_t err = (thread != OSSPEC_INVALID_THREAD) ?
|
||
0 : OSSPEC_ERR_THREAD_INVALID_HANDLE;
|
||
if (!err) {
|
||
#ifdef _WIN32
|
||
err = WaitForSingleObject(thread, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_THREAD_WAIT_TOUT;
|
||
#else
|
||
int wt_res;
|
||
|
||
#ifndef OSSPEC_THREAD_NO_TIMEOUT
|
||
if (timeout != OSSPEC_TIMEOUT_INFINITY) {
|
||
struct timespec timeToWait;
|
||
f_get_abs_time(timeout, &timeToWait);
|
||
wt_res = pthread_timedjoin_np(thread, NULL, &timeToWait);
|
||
} else {
|
||
#endif
|
||
wt_res = pthread_join(thread, NULL);
|
||
#ifndef OSSPEC_THREAD_NO_TIMEOUT
|
||
}
|
||
#endif
|
||
if (wt_res == ETIMEDOUT) {
|
||
err = OSSPEC_ERR_THREAD_WAIT_TOUT;
|
||
} else if (wt_res != 0) {
|
||
err = OSSPEC_ERR_THREAD_INVALID_HANDLE;
|
||
}
|
||
#endif
|
||
}
|
||
return err;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
|