197 lines
3.6 KiB
C
197 lines
3.6 KiB
C
/*
|
|
* Copyright (C) 2013 Martin Willi
|
|
* Copyright (C) 2013 revosec AG
|
|
*
|
|
* 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. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "thread.h"
|
|
|
|
#include <utils/debug.h>
|
|
#include <threading/mutex.h>
|
|
#include <threading/condvar.h>
|
|
|
|
typedef struct private_mutex_t private_mutex_t;
|
|
typedef struct private_condvar_t private_condvar_t;
|
|
|
|
/**
|
|
* private data of mutex
|
|
*/
|
|
struct private_mutex_t {
|
|
|
|
/**
|
|
* public functions
|
|
*/
|
|
mutex_t public;
|
|
|
|
/**
|
|
* wrapped critical section
|
|
*/
|
|
CRITICAL_SECTION cs;
|
|
|
|
/**
|
|
* Recursive lock count
|
|
*/
|
|
u_int times;
|
|
};
|
|
|
|
/**
|
|
* private data of condvar
|
|
*/
|
|
struct private_condvar_t {
|
|
|
|
/**
|
|
* public functions
|
|
*/
|
|
condvar_t public;
|
|
|
|
/**
|
|
* wrapped condition variable
|
|
*/
|
|
CONDITION_VARIABLE cv;
|
|
};
|
|
|
|
|
|
METHOD(mutex_t, lock, void,
|
|
private_mutex_t *this)
|
|
{
|
|
EnterCriticalSection(&this->cs);
|
|
this->times++;
|
|
}
|
|
|
|
METHOD(mutex_t, unlock, void,
|
|
private_mutex_t *this)
|
|
{
|
|
this->times--;
|
|
LeaveCriticalSection(&this->cs);
|
|
}
|
|
|
|
METHOD(mutex_t, mutex_destroy, void,
|
|
private_mutex_t *this)
|
|
{
|
|
DeleteCriticalSection(&this->cs);
|
|
free(this);
|
|
}
|
|
|
|
/*
|
|
* see header file
|
|
*/
|
|
mutex_t *mutex_create(mutex_type_t type)
|
|
{
|
|
private_mutex_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.lock = _lock,
|
|
.unlock = _unlock,
|
|
.destroy = _mutex_destroy,
|
|
},
|
|
);
|
|
|
|
/* CriticalSections are recursive, we use it for all mutex types. */
|
|
InitializeCriticalSection(&this->cs);
|
|
|
|
return &this->public;
|
|
}
|
|
|
|
METHOD(condvar_t, timed_wait, bool,
|
|
private_condvar_t *this, mutex_t *pubmutex, u_int timeout)
|
|
{
|
|
private_mutex_t *mutex = (private_mutex_t*)pubmutex;
|
|
u_int times;
|
|
bool ret;
|
|
|
|
thread_set_active_condvar(&this->cv);
|
|
|
|
/* while a CriticalSection is recursive, waiting in a condvar releases
|
|
* only one mutex. So release (and reacquire) all locks except the last. */
|
|
times = mutex->times;
|
|
while (mutex->times-- > 1)
|
|
{
|
|
LeaveCriticalSection(&mutex->cs);
|
|
}
|
|
|
|
ret = SleepConditionVariableCS(&this->cv, &mutex->cs, timeout);
|
|
|
|
while (++mutex->times < times)
|
|
{
|
|
EnterCriticalSection(&mutex->cs);
|
|
}
|
|
|
|
thread_set_active_condvar(NULL);
|
|
|
|
return ret == 0;
|
|
}
|
|
|
|
METHOD(condvar_t, wait_, void,
|
|
private_condvar_t *this, mutex_t *mutex)
|
|
{
|
|
timed_wait(this, mutex, INFINITE);
|
|
}
|
|
|
|
METHOD(condvar_t, timed_wait_abs, bool,
|
|
private_condvar_t *this, mutex_t *mutex, timeval_t tv)
|
|
{
|
|
DWORD timeout;
|
|
timeval_t now, diff;
|
|
|
|
time_monotonic(&now);
|
|
if (timercmp(&now, &tv, >))
|
|
{
|
|
return TRUE;
|
|
}
|
|
timersub(&tv, &now, &diff);
|
|
timeout = diff.tv_sec * 1000 + diff.tv_usec / 1000;
|
|
|
|
return timed_wait(this, mutex, timeout);
|
|
}
|
|
|
|
METHOD(condvar_t, signal_, void,
|
|
private_condvar_t *this)
|
|
{
|
|
WakeConditionVariable(&this->cv);
|
|
}
|
|
|
|
METHOD(condvar_t, broadcast, void,
|
|
private_condvar_t *this)
|
|
{
|
|
WakeAllConditionVariable(&this->cv);
|
|
}
|
|
|
|
METHOD(condvar_t, condvar_destroy, void,
|
|
private_condvar_t *this)
|
|
{
|
|
free(this);
|
|
}
|
|
|
|
/*
|
|
* see header file
|
|
*/
|
|
condvar_t *condvar_create(condvar_type_t type)
|
|
{
|
|
private_condvar_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.wait = _wait_,
|
|
.timed_wait = _timed_wait,
|
|
.timed_wait_abs = _timed_wait_abs,
|
|
.signal = _signal_,
|
|
.broadcast = _broadcast,
|
|
.destroy = _condvar_destroy,
|
|
}
|
|
);
|
|
|
|
InitializeConditionVariable(&this->cv);
|
|
|
|
return &this->public;
|
|
}
|