2024-06-12 13:51:27 +08:00

253 lines
6.6 KiB
C

/************************************************************************
Copyright (c) 2021 OceanBase.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02111-1301, USA
Part of this code includes code from PHP's mysqlnd extension
(written by Andrey Hristov, Georg Richter and Ulf Wendel), freely
*************************************************************************/
#include "ob_thread.h"
#ifdef _WIN32
#include <process.h>
#include <signal.h>
unsigned int __stdcall ob_win_thread_start(void *win_start_param)
{
struct ob_thread_start_param *ob_start_param= (struct ob_thread_start_param *)win_start_param;
ob_start_routine ob_start_func= ob_start_param->func;
void *ob_start_arg= ob_start_param->arg;
free(win_start_param);
(*ob_start_func)(ob_start_arg);
return 0;
}
ob_thread_t ob_thread_self()
{
return GetCurrentThreadId();
}
int ob_thread_equal(ob_thread_t ob_thread1, ob_thread_t ob_thread2)
{
return (ob_thread1 == ob_thread2);
}
int ob_thread_attr_init(ob_thread_attr_t *ob_thread_attr)
{
ob_thread_attr->ob_thead_state= OB_THREAD_CREATE_JOINABLE;
ob_thread_attr->ob_thread_stack_size= 0;
return 0;
}
int ob_thread_attr_destroy(ob_thread_attr_t *ob_thread_attr)
{
ob_thread_attr->ob_thead_state= OB_THREAD_CREATE_JOINABLE;
ob_thread_attr->ob_thread_stack_size= 0;
return 0;
}
int ob_thread_attr_setstacksize(ob_thread_attr_t *ob_thread_attr, size_t ob_stacksize)
{
ob_thread_attr->ob_thread_stack_size= (DWORD)ob_stacksize;
return 0;
}
int ob_thread_attr_setdetachstate(ob_thread_attr_t *ob_thread_attr, int ob_ob_thead_state)
{
ob_thread_attr->ob_thead_state= ob_ob_thead_state;
return 0;
}
int ob_thread_attr_getstacksize(ob_thread_attr_t *ob_thread_attr, size_t *ob_stacksize)
{
*ob_stacksize= (size_t)ob_thread_attr->ob_thread_stack_size;
return 0;
}
void ob_thread_yield()
{
SwitchToThread();
}
int ob_thread_once(ob_thread_once_t *ob_once_control, void (*ob_routine)(void))
{
int ret = 0;
LONG ob_thread_state;
if (OB_THREAD_ONCE_DONE == *ob_once_control) {
ret = 0;
} else {
ob_thread_state = InterlockedCompareExchange(ob_once_control, OB_THREAD_ONCE_INPROGRESS, OB_THREAD_ONCE_INIT);
switch(ob_thread_state)
{
case OB_THREAD_ONCE_DONE:
{
// do nothing
break;
}
case OB_THREAD_ONCE_INPROGRESS:
{
while(OB_THREAD_ONCE_INPROGRESS == *ob_once_control) {
Sleep(1); // sleep
}
break;
}
case OB_THREAD_ONCE_INIT:
{
(*ob_routine)();
*ob_once_control = OB_THREAD_ONCE_DONE;
break;
}
}
}
return ret;
}
int ob_thread_create(ob_thread_handle *ob_thread, const ob_thread_attr_t *ob_thread_attr,
ob_start_routine ob_thread_func, void *ob_thread_arg)
{
int ret = 0;
unsigned int ob_thread_stack_size;
struct ob_thread_start_param *ob_thread_param;
if (NULL == (ob_thread_param = (struct ob_thread_start_param *)malloc(sizeof(*ob_thread_param)))) {
ret = 1; // error
} else {
ob_thread_param->arg = ob_thread_arg;
ob_thread_param->func = ob_thread_func;
ob_thread_stack_size = ob_thread_attr ? ob_thread_attr->ob_thread_stack_size : 0;
ob_thread->handle= (HANDLE)_beginthreadex(NULL, ob_thread_stack_size, ob_win_thread_start, ob_thread_param, 0, &ob_thread->thread);
if (NULL == ob_thread->handle) {
// error, free param
free(ob_thread_param);
ret = 1;
} else if (ob_thread_attr && OB_THREAD_CREATE_DETACHED == ob_thread_attr->ob_thead_state) {
CloseHandle(ob_thread->handle);
ob_thread->handle= NULL;
}
}
if (0 != ret) {
ob_thread->handle= NULL;
ob_thread->thread= 0;
}
return ret;
}
int ob_thread_join(ob_thread_handle *ob_thread, void **ob_join_ptr)
{
int ret = 0;
if (WAIT_OBJECT_0 != WaitForSingleObject(ob_thread->handle, INFINITE)) {
ret = 1;
} else if (ob_thread->handle) {
CloseHandle(ob_thread->handle);
}
if (0 != ret) {
ob_thread->thread= 0;
ob_thread->handle= NULL;
}
return ret;
}
int ob_thread_cancel(ob_thread_handle *ob_thread)
{
int ret = 0;
BOOL terminate_ret = FALSE;
if (ob_thread->handle) {
if (FALSE == (terminate_ret = TerminateThread(ob_thread->handle, 0))) {
errno= EINVAL;
ret = -1;
} else {
CloseHandle(ob_thread->handle);
}
}
return ret;
}
void ob_thread_exit(void *ob_thread_exit_ptr)
{
_endthreadex(0);
}
#else
// for unix
ob_thread_t ob_thread_self()
{
return pthread_self();
}
int ob_thread_equal(ob_thread_t ob_thread1, ob_thread_t ob_thread2)
{
return pthread_equal(ob_thread1, ob_thread2);
}
int ob_thread_attr_init(ob_thread_attr_t *ob_thread_attr)
{
return pthread_attr_init(ob_thread_attr);
}
int ob_thread_attr_destroy(ob_thread_attr_t *ob_thread_attr)
{
return pthread_attr_destroy(ob_thread_attr);
}
int ob_thread_attr_setstacksize(ob_thread_attr_t *ob_thread_attr, size_t ob_stacksize)
{
return pthread_attr_setstacksize(ob_thread_attr, ob_stacksize);
}
int ob_thread_attr_setdetachstate(ob_thread_attr_t *ob_thread_attr, int ob_ob_thead_state)
{
return pthread_attr_setdetachstate(ob_thread_attr, ob_ob_thead_state);
}
int ob_thread_attr_getstacksize(ob_thread_attr_t *ob_thread_attr, size_t *ob_stacksize)
{
return pthread_attr_getstacksize(ob_thread_attr, ob_stacksize);
}
void ob_thread_yield()
{
sched_yield();
}
int ob_thread_once(ob_thread_once_t *ob_once_control, void (*ob_routine)(void))
{
return pthread_once(ob_once_control, ob_routine);
}
int ob_thread_create(ob_thread_handle *ob_thread, const ob_thread_attr_t *ob_thread_attr,
ob_start_routine ob_thread_func, void *ob_thread_arg)
{
return pthread_create(&ob_thread->thread, ob_thread_attr, ob_thread_func, ob_thread_arg);
}
int ob_thread_join(ob_thread_handle *ob_thread, void **ob_join_ptr)
{
return pthread_join(ob_thread->thread, ob_join_ptr);
}
int ob_thread_cancel(ob_thread_handle *ob_thread)
{
return pthread_cancel(ob_thread->thread);
}
void ob_thread_exit(void *ob_thread_exit_ptr)
{
pthread_exit(ob_thread_exit_ptr);
}
#endif