mirror of
https://github.com/tezc/sc.git
synced 2025-01-14 06:43:04 +08:00
234 lines
4.2 KiB
C
234 lines
4.2 KiB
C
#include "sc_cond.h"
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
|
|
#include <windows.h>
|
|
|
|
struct sc_thread
|
|
{
|
|
HANDLE id;
|
|
void* (*fn)(void*);
|
|
void* arg;
|
|
void* ret;
|
|
};
|
|
|
|
#else
|
|
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
struct sc_thread
|
|
{
|
|
pthread_t id;
|
|
};
|
|
|
|
#endif
|
|
|
|
void sc_thread_init(struct sc_thread* thread);
|
|
int sc_thread_term(struct sc_thread* thread);
|
|
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg);
|
|
int sc_thread_stop(struct sc_thread* thread, void** ret);
|
|
|
|
void sc_thread_init(struct sc_thread* thread)
|
|
{
|
|
thread->id = 0;
|
|
}
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#include <process.h>
|
|
|
|
unsigned int __stdcall sc_thread_fn(void* arg)
|
|
{
|
|
struct sc_thread* thread = arg;
|
|
|
|
thread->ret = thread->fn(thread->arg);
|
|
return 0;
|
|
}
|
|
|
|
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg)
|
|
{
|
|
int rc;
|
|
|
|
thread->fn = fn;
|
|
thread->arg = arg;
|
|
|
|
thread->id = (HANDLE)_beginthreadex(NULL, 0, sc_thread_fn, thread, 0, NULL);
|
|
rc = thread->id == 0 ? -1 : 0;
|
|
|
|
return rc;
|
|
}
|
|
|
|
int sc_thread_stop(struct sc_thread* thread, void** ret)
|
|
{
|
|
int rc = 0;
|
|
DWORD rv;
|
|
BOOL brc;
|
|
|
|
if (thread->id == 0) {
|
|
return -1;
|
|
}
|
|
|
|
rv = WaitForSingleObject(thread->id, INFINITE);
|
|
if (rv == WAIT_FAILED) {
|
|
rc = -1;
|
|
}
|
|
|
|
brc = CloseHandle(thread->id);
|
|
if (!brc) {
|
|
rc = -1;
|
|
}
|
|
|
|
thread->id = 0;
|
|
if (ret != NULL) {
|
|
*ret = thread->ret;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
#else
|
|
|
|
int sc_thread_start(struct sc_thread* thread, void* (*fn)(void*), void* arg)
|
|
{
|
|
int rc;
|
|
pthread_attr_t hndl;
|
|
|
|
rc = pthread_attr_init(&hndl);
|
|
if (rc != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// This may only fail with EINVAL.
|
|
pthread_attr_setdetachstate(&hndl, PTHREAD_CREATE_JOINABLE);
|
|
|
|
rc = pthread_create(&thread->id, &hndl, fn, arg);
|
|
|
|
// This may only fail with EINVAL.
|
|
pthread_attr_destroy(&hndl);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int sc_thread_stop(struct sc_thread* thread, void** ret)
|
|
{
|
|
int rc;
|
|
void* val;
|
|
|
|
if (thread->id == 0) {
|
|
return -1;
|
|
}
|
|
|
|
rc = pthread_join(thread->id, &val);
|
|
thread->id = 0;
|
|
|
|
if (ret != NULL) {
|
|
*ret = val;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#endif
|
|
|
|
int sc_thread_term(struct sc_thread* thread)
|
|
{
|
|
return sc_thread_stop(thread, NULL);
|
|
}
|
|
|
|
void* thread1_fn(void* arg)
|
|
{
|
|
char* data;
|
|
struct sc_cond* cond = arg;
|
|
|
|
data = sc_cond_wait(cond);
|
|
assert(strcmp(data, "finish") == 0);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void* thread2_fn(void* arg)
|
|
{
|
|
struct sc_cond* cond = arg;
|
|
sc_cond_signal(cond, "finish");
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef SC_HAVE_WRAP
|
|
bool mock_attrinit = false;
|
|
extern int __real_pthread_mutexattr_init(pthread_mutexattr_t *attr);
|
|
int __wrap_pthread_mutexattr_init(pthread_mutexattr_t *attr)
|
|
{
|
|
if (!mock_attrinit) {
|
|
return __real_pthread_mutexattr_init(attr);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool mock_mutexinit = false;
|
|
extern int __real_pthread_mutex_init(pthread_mutex_t *__mutex,
|
|
const pthread_mutexattr_t *__mutexattr);
|
|
int __wrap_pthread_mutex_init(pthread_mutex_t *__mutex,
|
|
const pthread_mutexattr_t *__mutexattr)
|
|
{
|
|
if (!mock_mutexinit) {
|
|
return __real_pthread_mutex_init(__mutex, __mutexattr);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void fail_test()
|
|
{
|
|
struct sc_cond cond;
|
|
|
|
mock_attrinit = true;
|
|
assert(sc_cond_init(&cond) == -1);
|
|
assert(*sc_cond_err(&cond) != '\0');
|
|
mock_attrinit = false;
|
|
assert(sc_cond_init(&cond) == 0);
|
|
assert(sc_cond_term(&cond) == 0);
|
|
mock_mutexinit = true;
|
|
assert(sc_cond_init(&cond) == -1);
|
|
mock_mutexinit = false;
|
|
assert(sc_cond_init(&cond) == 0);
|
|
assert(sc_cond_term(&cond) == 0);
|
|
}
|
|
|
|
#else
|
|
void fail_test()
|
|
{
|
|
|
|
}
|
|
#endif
|
|
|
|
void test1()
|
|
{
|
|
struct sc_cond cond;
|
|
struct sc_thread thread1;
|
|
struct sc_thread thread2;
|
|
|
|
assert(sc_cond_init(&cond) == 0);
|
|
|
|
sc_thread_init(&thread1);
|
|
sc_thread_init(&thread2);
|
|
|
|
assert(sc_thread_start(&thread1, thread1_fn, &cond) == 0);
|
|
assert(sc_thread_start(&thread2, thread2_fn, &cond) == 0);
|
|
|
|
assert(sc_thread_term(&thread1) == 0);
|
|
assert(sc_thread_term(&thread2) == 0);
|
|
|
|
assert(sc_cond_term(&cond) == 0);
|
|
}
|
|
|
|
|
|
int main()
|
|
{
|
|
test1();
|
|
fail_test();
|
|
|
|
return 0;
|
|
}
|