/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 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; version 2 of the License. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ /***************************************************************************** ** Simulation of posix threads calls for Windows *****************************************************************************/ #if defined (_WIN32) /* SAFE_MUTEX will not work until the thread structure is up to date */ #undef SAFE_MUTEX #include "mysys_priv.h" #include #include struct thread_start_parameter { pthread_handler func; void *arg; }; /** Adapter to @c pthread_mutex_trylock() @retval 0 Mutex was acquired @retval EBUSY Mutex was already locked by a thread */ int win_pthread_mutex_trylock(pthread_mutex_t *mutex) { if (TryEnterCriticalSection(mutex)) { /* Don't allow recursive lock */ if (mutex->RecursionCount > 1){ LeaveCriticalSection(mutex); return EBUSY; } return 0; } return EBUSY; } static unsigned int __stdcall pthread_start(void *p) { struct thread_start_parameter *par= (struct thread_start_parameter *)p; pthread_handler func= par->func; void *arg= par->arg; free(p); (*func)(arg); return 0; } int pthread_create(pthread_t *thread_id, const pthread_attr_t *attr, pthread_handler func, void *param) { uintptr_t handle; struct thread_start_parameter *par; unsigned int stack_size; int error_no; DBUG_ENTER("pthread_create"); par= (struct thread_start_parameter *)malloc(sizeof(*par)); if (!par) goto error_return; par->func= func; par->arg= param; stack_size= attr?attr->dwStackSize:0; handle= _beginthreadex(NULL, stack_size , pthread_start, par, 0, thread_id); if (!handle) goto error_return; DBUG_PRINT("info", ("thread id=%u",*thread_id)); /* Do not need thread handle, close it */ CloseHandle((HANDLE)handle); DBUG_RETURN(0); error_return: error_no= errno; DBUG_PRINT("error", ("Can't create thread to handle request (error %d)",error_no)); DBUG_RETURN(error_no); } void pthread_exit(void *a) { _endthreadex(0); } int pthread_join(pthread_t thread, void **value_ptr) { DWORD ret; HANDLE handle; handle= OpenThread(SYNCHRONIZE, FALSE, thread); if (!handle) { errno= EINVAL; goto error_return; } ret= WaitForSingleObject(handle, INFINITE); if(ret != WAIT_OBJECT_0) { errno= EINVAL; goto error_return; } CloseHandle(handle); return 0; error_return: if(handle) CloseHandle(handle); return -1; } int pthread_cancel(pthread_t thread) { HANDLE handle= 0; BOOL ok= FALSE; handle= OpenThread(THREAD_TERMINATE, FALSE, thread); if (handle) { ok= TerminateThread(handle,0); CloseHandle(handle); } if (ok) return 0; errno= EINVAL; return -1; } /* One time initialization. For simplicity, we assume initializer thread does not exit within init_routine(). */ int my_pthread_once(my_pthread_once_t *once_control, void (*init_routine)(void)) { LONG state; /* Do "dirty" read to find out if initialization is already done, to save an interlocked operation in common case. Memory barriers are ensured by Visual C++ volatile implementation. */ if (*once_control == MY_PTHREAD_ONCE_DONE) return 0; state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS, MY_PTHREAD_ONCE_INIT); switch(state) { case MY_PTHREAD_ONCE_INIT: /* This is initializer thread */ (*init_routine)(); *once_control= MY_PTHREAD_ONCE_DONE; break; case MY_PTHREAD_ONCE_INPROGRESS: /* init_routine in progress. Wait for its completion */ while(*once_control == MY_PTHREAD_ONCE_INPROGRESS) { Sleep(1); } break; case MY_PTHREAD_ONCE_DONE: /* Nothing to do */ break; } return 0; } #endif