Files
sysbench/src/sb_win.c
2017-01-27 09:39:28 +03:00

288 lines
6.8 KiB
C

/*
Copyright (C) 2008 MySQL AB
Copyright (C) 2008-2010 Alexey Kopytov <akopytov@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
This file contains Windows port of Posix functionality used in sysbench
(partial implementation of pthreads, gettimeofday() and random()
*/
#define _CRT_RAND_S /* for rand_s */
#include <stdlib.h>
#include <windows.h>
#include <errno.h>
#include "sb_win.h"
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
cond->waiting= 0;
InitializeCriticalSection(&cond->lock_waiting);
cond->events[SIGNAL]= CreateEvent(NULL, FALSE, FALSE, NULL);
cond->events[BROADCAST]= CreateEvent(NULL, TRUE, FALSE, NULL);
cond->broadcast_block_event= CreateEvent(NULL, TRUE, TRUE, NULL);
if( cond->events[SIGNAL] == NULL ||
cond->events[BROADCAST] == NULL ||
cond->broadcast_block_event == NULL )
return ENOMEM;
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
DeleteCriticalSection(&cond->lock_waiting);
if (CloseHandle(cond->events[SIGNAL]) == 0 ||
CloseHandle(cond->events[BROADCAST]) == 0 ||
CloseHandle(cond->broadcast_block_event) == 0)
return EINVAL;
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
return pthread_cond_timedwait(cond,mutex,NULL);
}
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
struct timespec *abstime)
{
int result;
long timeout;
union {
FILETIME ft;
long long i64;
}now;
if( abstime != NULL )
{
long long stoptime_nanos = (abstime->tv_sec*1000000000 + abstime->tv_nsec);
long long now_nanos;
long long timeout_nanos;
GetSystemTimeAsFileTime(&now.ft);
now_nanos = now.i64 *100;
timeout_nanos = stoptime_nanos - now_nanos;
timeout = (long)(timeout_nanos /1000000);
}
else
{
/* No time specified; don't expire */
timeout= INFINITE;
}
/*
Block access if previous broadcast hasn't finished.
This is just for safety and should normally not
affect the total time spent in this function.
*/
WaitForSingleObject(cond->broadcast_block_event, INFINITE);
EnterCriticalSection(&cond->lock_waiting);
cond->waiting++;
LeaveCriticalSection(&cond->lock_waiting);
LeaveCriticalSection(mutex);
result= WaitForMultipleObjects(2, cond->events, FALSE, timeout);
EnterCriticalSection(&cond->lock_waiting);
cond->waiting--;
if (cond->waiting == 0 && result == (WAIT_OBJECT_0+BROADCAST))
{
/*
We're the last waiter to be notified or to stop waiting, so
reset the manual event.
*/
/* Close broadcast gate */
ResetEvent(cond->events[BROADCAST]);
/* Open block gate */
SetEvent(cond->broadcast_block_event);
}
LeaveCriticalSection(&cond->lock_waiting);
EnterCriticalSection(mutex);
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
}
int pthread_cond_signal(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
if(cond->waiting > 0)
SetEvent(cond->events[SIGNAL]);
LeaveCriticalSection(&cond->lock_waiting);
return 0;
}
int pthread_cond_broadcast(pthread_cond_t *cond)
{
EnterCriticalSection(&cond->lock_waiting);
/*
The mutex protect us from broadcasting if
there isn't any thread waiting to open the
block gate after this call has closed it.
*/
if(cond->waiting > 0)
{
/* Close block gate */
ResetEvent(cond->broadcast_block_event);
/* Open broadcast gate */
SetEvent(cond->events[BROADCAST]);
}
LeaveCriticalSection(&cond->lock_waiting);
return 0;
}
int pthread_attr_init(pthread_attr_t *attr)
{
attr->stacksize = 0;
return 0;
}
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
InitializeCriticalSection(mutex);
return 0;
}
int pthread_mutex_lock(pthread_mutex_t *mutex)
{
EnterCriticalSection(mutex);
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
LeaveCriticalSection(mutex);
return 0;
}
int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
DeleteCriticalSection(mutex);
return 0;
}
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg)
{
DWORD tid;
*thread = CreateThread(NULL, attr->stacksize,
(LPTHREAD_START_ROUTINE) start_routine, arg,
STACK_SIZE_PARAM_IS_A_RESERVATION, &tid);
if (*thread != NULL)
return 0;
return -1;
}
int pthread_cancel(pthread_t thread)
{
return !TerminateThread(thread, 0);
}
/* Minimal size of thread stack on Windows*/
#define PTHREAD_STACK_MIN 65536*2
int pthread_attr_setstacksize( pthread_attr_t *attr, size_t stacksize)
{
if(stacksize)
attr->stacksize = max(stacksize, PTHREAD_STACK_MIN);
return 0;
}
int pthread_join(pthread_t pthread, void **value_ptr)
{
if (WaitForSingleObject(pthread, INFINITE) != WAIT_OBJECT_0)
return -1;
if (value_ptr)
*value_ptr = 0;
return 0;
}
pthread_t pthread_self(void)
{
return GetCurrentThreadId();
}
/*
One time initialization. For simplicity, we assume initializer thread
does not exit within init_routine().
*/
int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void))
{
LONG state = InterlockedCompareExchange(once_control, PTHREAD_ONCE_INPROGRESS,
PTHREAD_ONCE_INIT);
switch(state)
{
case PTHREAD_ONCE_INIT:
/* This is initializer thread */
(*init_routine)();
*once_control = PTHREAD_ONCE_DONE;
break;
case PTHREAD_ONCE_INPROGRESS:
/* init_routine in progress. Wait for its completion */
while(*once_control == PTHREAD_ONCE_INPROGRESS)
{
Sleep(1);
}
break;
case PTHREAD_ONCE_DONE:
/* Nothing to do */
break;
}
return 0;
}
#include <time.h>
int gettimeofday(struct timeval * tp, void * tzp)
{
static long long qpf = 0, startup_time = 0;
long long qpc;
if(qpf == 0)
{
QueryPerformanceFrequency((LARGE_INTEGER *)&qpf);
}
if(startup_time == 0)
{
QueryPerformanceCounter((LARGE_INTEGER *)&qpc);
startup_time = time(NULL) - (qpc/qpf);
}
QueryPerformanceCounter((LARGE_INTEGER *)&qpc);
tp->tv_sec = (long)(startup_time + qpc/qpf);
tp->tv_usec = (long)((qpc%qpf)*1000000/qpf);
return 0;
}
int random()
{
int ret;
rand_s(&ret);
return ret;
}