sourcemod/public/sourcepawn/ke_thread_windows.h
David Anderson 3ac43497b9 Implement a watchdog timer for scripts that take too long to execute (bug 5837, r=fyren).
--HG--
extra : rebase_source : ffacb38457eca581660ce8f15c444ad828b7fedd
2013-08-14 23:54:25 -07:00

145 lines
3.0 KiB
C++

// vim: set ts=8 sts=2 sw=2 tw=99 et:
//
// This file is part of SourcePawn.
//
// SourcePawn 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 3 of the License, or
// (at your option) any later version.
//
// SourcePawn 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 SourcePawn. If not, see <http://www.gnu.org/licenses/>.
#ifndef _include_sourcepawn_thread_windows_h_
#define _include_sourcepawn_thread_windows_h_
#include <windows.h>
namespace ke {
class CriticalSection : public Lockable
{
public:
CriticalSection() {
InitializeCriticalSection(&cs_);
}
~CriticalSection() {
DeleteCriticalSection(&cs_);
}
bool DoTryLock() {
return !!TryEnterCriticalSection(&cs_);
}
void DoLock() {
EnterCriticalSection(&cs_);
}
void DoUnlock() {
LeaveCriticalSection(&cs_);
}
private:
CRITICAL_SECTION cs_;
};
typedef CriticalSection Mutex;
// Currently, this class only supports single-listener CVs.
class ConditionVariable : public Lockable
{
public:
ConditionVariable() {
event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
}
~ConditionVariable() {
CloseHandle(event_);
}
bool DoTryLock() {
return cs_.DoTryLock();
}
void DoLock() {
cs_.DoLock();
}
void DoUnlock() {
cs_.DoUnlock();
}
void Notify() {
AssertCurrentThreadOwns();
SetEvent(event_);
}
WaitResult Wait(size_t timeout_ms) {
// This will assert if the lock has not been acquired. We don't need to be
// atomic here, like pthread_cond_wait, because the event bit will stick
// until reset by a wait function.
Unlock();
DWORD rv = WaitForSingleObject(event_, timeout_ms);
Lock();
if (rv == WAIT_TIMEOUT)
return Wait_Timeout;
if (rv == WAIT_FAILED)
return Wait_Error;
return Wait_Signaled;
}
WaitResult Wait() {
return Wait(INFINITE);
}
private:
CriticalSection cs_;
HANDLE event_;
};
class Thread
{
public:
Thread(IRunnable *run, const char *name = NULL) {
thread_ = CreateThread(NULL, 0, Main, run, 0, NULL);
}
~Thread() {
if (!thread_)
return;
CloseHandle(thread_);
}
bool Succeeded() const {
return !!thread_;
}
void Join() {
if (!Succeeded())
return;
WaitForSingleObject(thread_, INFINITE);
}
private:
static DWORD WINAPI Main(LPVOID arg) {
((IRunnable *)arg)->Run();
return 0;
}
#pragma pack(push, 8)
struct ThreadNameInfo {
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
};
#pragma pack(pop)
private:
HANDLE thread_;
};
} // namespace ke
#endif // _include_sourcepawn_thread_windows_h_