added threader to core (not used yet)
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401090
This commit is contained in:
parent
8bca9a9b32
commit
b13e48ae0b
35
core/ThreadSupport.cpp
Normal file
35
core/ThreadSupport.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ThreadSupport.h"
|
||||
#include "sm_globals.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
#if defined PLATFORM_POSIX
|
||||
#include "thread/PosixThreads.h"
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
#include "thread/WinThreads.h"
|
||||
#endif
|
||||
|
||||
MainThreader g_MainThreader;
|
||||
IThreader *g_pThreader = &g_MainThreader;
|
||||
|
||||
class RegThreadStuff : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
g_ShareSys.AddInterface(NULL, g_pThreader);
|
||||
}
|
||||
};
|
33
core/ThreadSupport.h
Normal file
33
core/ThreadSupport.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod Threader API
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. 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; 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.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||
#define _INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
||||
|
||||
#include <IThreader.h>
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
extern IThreader *g_pThreader;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_THREAD_SUPPORT_H
|
@ -41,7 +41,7 @@
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\;..\systems;..\..\public;..\..\public\sourcepawn"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD;SM_DEFAULT_THREADER"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
@ -120,7 +120,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\;..\systems;..\..\public;..\..\public\sourcepawn"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMOD_MM_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;SOURCEMOD_BUILD;SM_DEFAULT_THREADER"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
@ -289,6 +289,10 @@
|
||||
RelativePath="..\TextParsers.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ThreadSupport.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TimerSys.cpp"
|
||||
>
|
||||
@ -391,6 +395,10 @@
|
||||
RelativePath="..\sm_autonatives.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_cachelist.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_fastlink.h"
|
||||
>
|
||||
@ -407,6 +415,14 @@
|
||||
RelativePath="..\..\public\sm_platform.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_queue.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_simple_prioqueue.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sm_srvcmds.h"
|
||||
>
|
||||
@ -439,6 +455,10 @@
|
||||
RelativePath="..\TextParsers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\thread\ThreadSupport.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\TimerSys.h"
|
||||
>
|
||||
@ -913,6 +933,42 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Threader"
|
||||
>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\thread\BaseWorker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\thread\ThreadWorker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\thread\WinThreads.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\thread\BaseWorker.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\thread\ThreadWorker.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\thread\WinThreads.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
|
263
core/thread/BaseWorker.cpp
Normal file
263
core/thread/BaseWorker.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "BaseWorker.h"
|
||||
|
||||
BaseWorker::BaseWorker() :
|
||||
m_perFrame(SM_DEFAULT_THREADS_PER_FRAME),
|
||||
m_state(Worker_Stopped)
|
||||
{
|
||||
}
|
||||
|
||||
BaseWorker::~BaseWorker()
|
||||
{
|
||||
if (m_state != Worker_Stopped || m_state != Worker_Invalid)
|
||||
Stop(true);
|
||||
|
||||
if (m_ThreadQueue.size())
|
||||
Flush(true);
|
||||
}
|
||||
|
||||
void BaseWorker::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams pt;
|
||||
|
||||
pt.flags = Thread_AutoRelease;
|
||||
pt.prio = ThreadPrio_Normal;
|
||||
|
||||
MakeThread(pThread, &pt);
|
||||
}
|
||||
|
||||
IThreadHandle *BaseWorker::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams pt;
|
||||
|
||||
pt.flags = flags;
|
||||
pt.prio = ThreadPrio_Normal;
|
||||
|
||||
return MakeThread(pThread, &pt);
|
||||
}
|
||||
|
||||
IThreadHandle *BaseWorker::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
if (m_state != Worker_Running)
|
||||
return NULL;
|
||||
|
||||
SWThreadHandle *swt = new SWThreadHandle(this, params, pThread);
|
||||
|
||||
AddThreadToQueue(swt);
|
||||
|
||||
return swt;
|
||||
}
|
||||
|
||||
void BaseWorker::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
max = ThreadPrio_Normal;
|
||||
min = ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
unsigned int BaseWorker::Flush(bool flush_cancel)
|
||||
{
|
||||
SWThreadHandle *swt;
|
||||
unsigned int num = 0;
|
||||
|
||||
while ((swt=PopThreadFromQueue()) != NULL)
|
||||
{
|
||||
swt->m_state = Thread_Done;
|
||||
if (!flush_cancel)
|
||||
swt->pThread->RunThread(swt);
|
||||
swt->pThread->OnTerminate(swt, flush_cancel);
|
||||
if (swt->m_params.flags & Thread_AutoRelease)
|
||||
delete swt;
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
SWThreadHandle *BaseWorker::PopThreadFromQueue()
|
||||
{
|
||||
if (!m_ThreadQueue.size())
|
||||
return NULL;
|
||||
|
||||
SourceHook::List<SWThreadHandle *>::iterator begin;
|
||||
SWThreadHandle *swt;
|
||||
|
||||
begin = m_ThreadQueue.begin();
|
||||
swt = (*begin);
|
||||
m_ThreadQueue.erase(begin);
|
||||
|
||||
return swt;
|
||||
}
|
||||
|
||||
void BaseWorker::AddThreadToQueue(SWThreadHandle *pHandle)
|
||||
{
|
||||
m_ThreadQueue.push_back(pHandle);
|
||||
}
|
||||
|
||||
unsigned int BaseWorker::GetMaxThreadsPerFrame()
|
||||
{
|
||||
return m_perFrame;
|
||||
}
|
||||
|
||||
WorkerState BaseWorker::GetStatus(unsigned int *threads)
|
||||
{
|
||||
if (threads)
|
||||
*threads = m_perFrame;
|
||||
|
||||
return m_state;
|
||||
}
|
||||
|
||||
unsigned int BaseWorker::RunFrame()
|
||||
{
|
||||
unsigned int done = 0;
|
||||
unsigned int max = GetMaxThreadsPerFrame();
|
||||
SWThreadHandle *swt = NULL;
|
||||
IThread *pThread = NULL;
|
||||
|
||||
while (done < max)
|
||||
{
|
||||
if ((swt=PopThreadFromQueue()) == NULL)
|
||||
break;
|
||||
pThread = swt->pThread;
|
||||
swt->m_state = Thread_Running;
|
||||
pThread->RunThread(swt);
|
||||
swt->m_state = Thread_Done;
|
||||
pThread->OnTerminate(swt, false);
|
||||
if (swt->m_params.flags & Thread_AutoRelease)
|
||||
delete swt;
|
||||
done++;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
void BaseWorker::SetMaxThreadsPerFrame(unsigned int threads)
|
||||
{
|
||||
m_perFrame = threads;
|
||||
}
|
||||
|
||||
bool BaseWorker::Start()
|
||||
{
|
||||
if (m_state != Worker_Invalid && m_state != Worker_Stopped)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_state = Worker_Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseWorker::Stop(bool flush_cancel)
|
||||
{
|
||||
if (m_state == Worker_Invalid || m_state == Worker_Stopped)
|
||||
return false;
|
||||
|
||||
if (m_state == Worker_Paused)
|
||||
{
|
||||
if (!Unpause())
|
||||
return false;
|
||||
}
|
||||
|
||||
m_state = Worker_Stopped;
|
||||
Flush(flush_cancel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseWorker::Pause()
|
||||
{
|
||||
if (m_state != Worker_Running)
|
||||
return false;
|
||||
|
||||
m_state = Worker_Paused;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BaseWorker::Unpause()
|
||||
{
|
||||
if (m_state != Worker_Paused)
|
||||
return false;
|
||||
|
||||
m_state = Worker_Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* THREAD HANDLE STUFF *
|
||||
***********************/
|
||||
|
||||
void SWThreadHandle::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void SWThreadHandle::GetParams(ThreadParams *p)
|
||||
{
|
||||
*p = m_params;
|
||||
}
|
||||
|
||||
ThreadPriority SWThreadHandle::GetPriority()
|
||||
{
|
||||
return m_params.prio;
|
||||
}
|
||||
|
||||
ThreadState SWThreadHandle::GetState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
IThreadCreator *SWThreadHandle::Parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
bool SWThreadHandle::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
if (m_params.prio != ThreadPrio_Normal)
|
||||
return false;
|
||||
|
||||
m_params.prio = prio;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SWThreadHandle::Unpause()
|
||||
{
|
||||
if (m_state != Thread_Paused)
|
||||
return false;
|
||||
|
||||
m_state = Thread_Running;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SWThreadHandle::WaitForThread()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SWThreadHandle::SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread) :
|
||||
m_state(Thread_Paused), m_params(*p), m_parent(parent), pThread(thread)
|
||||
{
|
||||
}
|
||||
|
||||
IThread *SWThreadHandle::GetThread()
|
||||
{
|
||||
return pThread;
|
||||
}
|
86
core/thread/BaseWorker.h
Normal file
86
core/thread/BaseWorker.h
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_BASEWORKER_H
|
||||
#define _INCLUDE_SOURCEMOD_BASEWORKER_H
|
||||
|
||||
#include "sh_list.h"
|
||||
#include "ThreadSupport.h"
|
||||
|
||||
#define SM_DEFAULT_THREADS_PER_FRAME 1
|
||||
|
||||
class BaseWorker;
|
||||
|
||||
//SW = Simple Wrapper
|
||||
class SWThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class BaseWorker;
|
||||
public:
|
||||
SWThreadHandle(IThreadCreator *parent, const ThreadParams *p, IThread *thread);
|
||||
IThread *GetThread();
|
||||
public:
|
||||
//NOTE: We don't support this by default.
|
||||
//It's specific usage that'd require many mutexes
|
||||
virtual bool WaitForThread();
|
||||
public:
|
||||
virtual void DestroyThis();
|
||||
virtual IThreadCreator *Parent();
|
||||
virtual void GetParams(ThreadParams *ptparams);
|
||||
public:
|
||||
//Priorities not supported by default.
|
||||
virtual ThreadPriority GetPriority();
|
||||
virtual bool SetPriority(ThreadPriority prio);
|
||||
public:
|
||||
virtual ThreadState GetState();
|
||||
virtual bool Unpause();
|
||||
private:
|
||||
ThreadState m_state;
|
||||
ThreadParams m_params;
|
||||
IThreadCreator *m_parent;
|
||||
IThread *pThread;
|
||||
};
|
||||
|
||||
class BaseWorker : public IThreadWorker
|
||||
{
|
||||
public:
|
||||
BaseWorker();
|
||||
virtual ~BaseWorker();
|
||||
public: //IWorker
|
||||
virtual unsigned int RunFrame();
|
||||
//Controls the worker
|
||||
virtual bool Pause();
|
||||
virtual bool Unpause();
|
||||
virtual bool Start();
|
||||
virtual bool Stop(bool flush_cancel);
|
||||
//Flushes out any remaining threads
|
||||
virtual unsigned int Flush(bool flush_cancel);
|
||||
//returns status and number of threads in queue
|
||||
virtual WorkerState GetStatus(unsigned int *numThreads);
|
||||
public: //IThreadCreator
|
||||
virtual void MakeThread(IThread *pThread);
|
||||
virtual IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags);
|
||||
virtual IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params);
|
||||
virtual void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min);
|
||||
public: //BaseWorker
|
||||
virtual void AddThreadToQueue(SWThreadHandle *pHandle);
|
||||
virtual SWThreadHandle *PopThreadFromQueue();
|
||||
virtual void SetMaxThreadsPerFrame(unsigned int threads);
|
||||
virtual unsigned int GetMaxThreadsPerFrame();
|
||||
protected:
|
||||
SourceHook::List<SWThreadHandle *> m_ThreadQueue;
|
||||
unsigned int m_perFrame;
|
||||
volatile WorkerState m_state;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_BASEWORKER_H
|
301
core/thread/PosixThreads.cpp
Normal file
301
core/thread/PosixThreads.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod Threader API
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. 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; 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.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "PosixThreads.h"
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
IThreadWorker *PosixThreader::MakeWorker(bool threaded)
|
||||
{
|
||||
if (threaded)
|
||||
{
|
||||
return new ThreadWorker(this, DEFAULT_THINK_TIME_MS);
|
||||
} else {
|
||||
return new BaseWorker();
|
||||
}
|
||||
}
|
||||
|
||||
void PosixThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||
{
|
||||
delete pWorker;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadSleep(unsigned int ms)
|
||||
{
|
||||
usleep( ms * 1000 );
|
||||
}
|
||||
|
||||
void PosixThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
max = ThreadPrio_Normal;
|
||||
min = ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
IMutex *PosixThreader::MakeMutex()
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
if (pthread_mutex_init(&mutex, NULL) != 0)
|
||||
return NULL;
|
||||
|
||||
PosixMutex *pMutex = new PosixMutex(mutex);
|
||||
|
||||
return pMutex;
|
||||
}
|
||||
|
||||
|
||||
void PosixThreader::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = Thread_AutoRelease;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
IThreadHandle *PosixThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = flags;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
return MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
void *Posix_ThreadGate(void *param)
|
||||
{
|
||||
PosixThreader::ThreadHandle *pHandle =
|
||||
reinterpret_cast<PosixThreader::ThreadHandle *>(param);
|
||||
|
||||
//Block this thread from being started initially.
|
||||
pthread_mutex_lock(&pHandle->m_runlock);
|
||||
//if we get here, we've obtained the lock and are allowed to run.
|
||||
//unlock and continue.
|
||||
pthread_mutex_unlock(&pHandle->m_runlock);
|
||||
|
||||
pHandle->m_run->RunThread(pHandle);
|
||||
|
||||
ThreadParams params;
|
||||
pthread_mutex_lock(&pHandle->m_statelock);
|
||||
pHandle->m_state = Thread_Done;
|
||||
pHandle->GetParams(¶ms);
|
||||
pthread_mutex_unlock(&pHandle->m_statelock);
|
||||
|
||||
pHandle->m_run->OnTerminate(pHandle, false);
|
||||
if (params.flags & Thread_AutoRelease)
|
||||
delete pHandle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ThreadParams g_defparams;
|
||||
IThreadHandle *PosixThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
params = &g_defparams;
|
||||
|
||||
PosixThreader::ThreadHandle *pHandle =
|
||||
new PosixThreader::ThreadHandle(this, pThread, params);
|
||||
|
||||
pthread_mutex_lock(&pHandle->m_runlock);
|
||||
|
||||
int err;
|
||||
err = pthread_create(&pHandle->m_thread, NULL, Posix_ThreadGate, (void *)pHandle);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock(&pHandle->m_runlock);
|
||||
delete pHandle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Don't bother setting priority...
|
||||
|
||||
if (!(pHandle->m_params.flags & Thread_CreateSuspended))
|
||||
{
|
||||
pHandle->m_state = Thread_Running;
|
||||
err = pthread_mutex_unlock(&pHandle->m_runlock);
|
||||
if (err != 0)
|
||||
pHandle->m_state = Thread_Paused;
|
||||
}
|
||||
|
||||
return pHandle;
|
||||
}
|
||||
|
||||
IEventSignal *PosixThreader::MakeEventSignal()
|
||||
{
|
||||
return new PosixEventSignal();
|
||||
}
|
||||
|
||||
/*****************
|
||||
**** Mutexes ****
|
||||
*****************/
|
||||
|
||||
PosixThreader::PosixMutex::~PosixMutex()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
}
|
||||
|
||||
bool PosixThreader::PosixMutex::TryLock()
|
||||
{
|
||||
int err = pthread_mutex_trylock(&m_mutex);
|
||||
|
||||
return (err == 0);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixMutex::Lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixMutex::Unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixMutex::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
/******************
|
||||
* Thread Handles *
|
||||
******************/
|
||||
|
||||
PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) :
|
||||
m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused)
|
||||
{
|
||||
pthread_mutex_init(&m_runlock, NULL);
|
||||
pthread_mutex_init(&m_statelock, NULL);
|
||||
}
|
||||
|
||||
PosixThreader::ThreadHandle::~ThreadHandle()
|
||||
{
|
||||
pthread_mutex_destroy(&m_runlock);
|
||||
pthread_mutex_destroy(&m_statelock);
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::WaitForThread()
|
||||
{
|
||||
void *arg;
|
||||
|
||||
if (pthread_join(m_thread, &arg) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadState PosixThreader::ThreadHandle::GetState()
|
||||
{
|
||||
ThreadState state;
|
||||
|
||||
pthread_mutex_lock(&m_statelock);
|
||||
state = m_state;
|
||||
pthread_mutex_unlock(&m_statelock);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
IThreadCreator *PosixThreader::ThreadHandle::Parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadHandle::DestroyThis()
|
||||
{
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
return;
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PosixThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
|
||||
{
|
||||
if (!ptparams)
|
||||
return;
|
||||
|
||||
*ptparams = m_params;
|
||||
}
|
||||
|
||||
ThreadPriority PosixThreader::ThreadHandle::GetPriority()
|
||||
{
|
||||
return ThreadPrio_Normal;
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
return (prio == ThreadPrio_Normal);
|
||||
}
|
||||
|
||||
bool PosixThreader::ThreadHandle::Unpause()
|
||||
{
|
||||
if (m_state != Thread_Paused)
|
||||
return false;
|
||||
|
||||
m_state = Thread_Running;
|
||||
|
||||
if (pthread_mutex_unlock(&m_runlock) != 0)
|
||||
{
|
||||
m_state = Thread_Paused;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************
|
||||
* EVENT SIGNALS *
|
||||
*****************/
|
||||
|
||||
PosixThreader::PosixEventSignal::PosixEventSignal()
|
||||
{
|
||||
pthread_cond_init(&m_cond, NULL);
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
PosixThreader::PosixEventSignal::~PosixEventSignal()
|
||||
{
|
||||
pthread_cond_destroy(&m_cond);
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixEventSignal::Wait()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_cond_wait(&m_cond, &m_mutex);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixEventSignal::Signal()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
pthread_cond_broadcast(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
void PosixThreader::PosixEventSignal::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
107
core/thread/PosixThreads.h
Normal file
107
core/thread/PosixThreads.h
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod Threader API
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. 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; 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.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_POSIXTHREADS_H_
|
||||
#define _INCLUDE_POSIXTHREADS_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include "IThreader.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
void *Posix_ThreadGate(void *param);
|
||||
|
||||
class PosixThreader : public IThreader
|
||||
{
|
||||
public:
|
||||
class ThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class PosixThreader;
|
||||
friend void *Posix_ThreadGate(void *param);
|
||||
public:
|
||||
ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params);
|
||||
virtual ~ThreadHandle();
|
||||
public:
|
||||
virtual bool WaitForThread();
|
||||
virtual void DestroyThis();
|
||||
virtual IThreadCreator *Parent();
|
||||
virtual void GetParams(ThreadParams *ptparams);
|
||||
virtual ThreadPriority GetPriority();
|
||||
virtual bool SetPriority(ThreadPriority prio);
|
||||
virtual ThreadState GetState();
|
||||
virtual bool Unpause();
|
||||
protected:
|
||||
IThreader *m_parent; //Parent handle
|
||||
pthread_t m_thread; //Windows HANDLE
|
||||
ThreadParams m_params; //Current Parameters
|
||||
IThread *m_run; //Runnable context
|
||||
pthread_mutex_t m_statelock;
|
||||
pthread_mutex_t m_runlock;
|
||||
ThreadState m_state; //internal state
|
||||
};
|
||||
class PosixMutex : public IMutex
|
||||
{
|
||||
public:
|
||||
PosixMutex(pthread_mutex_t m) : m_mutex(m)
|
||||
{
|
||||
};
|
||||
virtual ~PosixMutex();
|
||||
public:
|
||||
virtual bool TryLock();
|
||||
virtual void Lock();
|
||||
virtual void Unlock();
|
||||
virtual void DestroyThis();
|
||||
protected:
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
class PosixEventSignal : public IEventSignal
|
||||
{
|
||||
public:
|
||||
PosixEventSignal();
|
||||
virtual ~PosixEventSignal();
|
||||
public:
|
||||
virtual void Wait();
|
||||
virtual void Signal();
|
||||
virtual void DestroyThis();
|
||||
protected:
|
||||
pthread_cond_t m_cond;
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
public:
|
||||
IMutex *MakeMutex();
|
||||
void MakeThread(IThread *pThread);
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags);
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params);
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min);
|
||||
void ThreadSleep(unsigned int ms);
|
||||
IEventSignal *MakeEventSignal();
|
||||
IThreadWorker *MakeWorker(bool threaded);
|
||||
void DestroyWorker(IThreadWorker *pWorker);
|
||||
};
|
||||
|
||||
#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER
|
||||
#define SM_MAIN_THREADER PosixThreader;
|
||||
typedef class PosixThreader MainThreader;
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_POSIXTHREADS_H_
|
272
core/thread/ThreadWorker.cpp
Normal file
272
core/thread/ThreadWorker.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
ThreadWorker::ThreadWorker() :
|
||||
m_Threader(NULL),
|
||||
m_QueueLock(NULL),
|
||||
m_StateLock(NULL),
|
||||
m_PauseSignal(NULL),
|
||||
m_AddSignal(NULL),
|
||||
me(NULL),
|
||||
m_think_time(DEFAULT_THINK_TIME_MS)
|
||||
{
|
||||
m_state = Worker_Invalid;
|
||||
}
|
||||
|
||||
ThreadWorker::ThreadWorker(IThreader *pThreader, unsigned int thinktime) :
|
||||
m_Threader(pThreader),
|
||||
m_QueueLock(NULL),
|
||||
m_StateLock(NULL),
|
||||
m_PauseSignal(NULL),
|
||||
m_AddSignal(NULL),
|
||||
me(NULL),
|
||||
m_think_time(thinktime)
|
||||
{
|
||||
if (m_Threader)
|
||||
{
|
||||
m_state = Worker_Stopped;
|
||||
} else {
|
||||
m_state = Worker_Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadWorker::~ThreadWorker()
|
||||
{
|
||||
if (m_state != Worker_Stopped || m_state != Worker_Invalid)
|
||||
Stop(true);
|
||||
|
||||
if (m_ThreadQueue.size())
|
||||
Flush(true);
|
||||
}
|
||||
|
||||
void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
|
||||
{
|
||||
//we don't particularly care
|
||||
return;
|
||||
}
|
||||
|
||||
void ThreadWorker::RunThread(IThreadHandle *pHandle)
|
||||
{
|
||||
WorkerState this_state = Worker_Running;
|
||||
size_t num;
|
||||
|
||||
while (true)
|
||||
{
|
||||
/**
|
||||
* Check number of items in the queue
|
||||
*/
|
||||
m_StateLock->Lock();
|
||||
this_state = m_state;
|
||||
m_StateLock->Unlock();
|
||||
if (this_state != Worker_Stopped)
|
||||
{
|
||||
m_QueueLock->Lock();
|
||||
num = m_ThreadQueue.size();
|
||||
if (!num)
|
||||
{
|
||||
/**
|
||||
* if none, wait for an item
|
||||
*/
|
||||
m_Waiting = true;
|
||||
m_QueueLock->Unlock();
|
||||
/* first check if we should end again */
|
||||
if (this_state == Worker_Stopped)
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_AddSignal->Wait();
|
||||
m_Waiting = false;
|
||||
} else {
|
||||
m_QueueLock->Unlock();
|
||||
}
|
||||
}
|
||||
m_StateLock->Lock();
|
||||
this_state = m_state;
|
||||
m_StateLock->Unlock();
|
||||
if (this_state != Worker_Running)
|
||||
{
|
||||
if (this_state == Worker_Paused || this_state == Worker_Stopped)
|
||||
{
|
||||
//wait until the lock is cleared.
|
||||
if (this_state == Worker_Paused)
|
||||
{
|
||||
m_PauseSignal->Wait();
|
||||
}
|
||||
if (this_state == Worker_Stopped)
|
||||
{
|
||||
//if we're supposed to flush cleanrly,
|
||||
// run all of the remaining frames first.
|
||||
if (!m_FlushType)
|
||||
{
|
||||
while (m_ThreadQueue.size())
|
||||
RunFrame();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Run the frame.
|
||||
*/
|
||||
RunFrame();
|
||||
|
||||
/**
|
||||
* wait in between threads if specified
|
||||
*/
|
||||
if (m_think_time)
|
||||
m_Threader->ThreadSleep(m_think_time);
|
||||
}
|
||||
}
|
||||
|
||||
SWThreadHandle *ThreadWorker::PopThreadFromQueue()
|
||||
{
|
||||
if (m_state <= Worker_Stopped && !m_QueueLock)
|
||||
return NULL;
|
||||
|
||||
SWThreadHandle *swt;
|
||||
m_QueueLock->Lock();
|
||||
swt = BaseWorker::PopThreadFromQueue();
|
||||
m_QueueLock->Unlock();
|
||||
|
||||
return swt;
|
||||
}
|
||||
|
||||
void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
|
||||
{
|
||||
if (m_state <= Worker_Stopped)
|
||||
return;
|
||||
|
||||
m_QueueLock->Lock();
|
||||
BaseWorker::AddThreadToQueue(pHandle);
|
||||
if (m_Waiting)
|
||||
{
|
||||
m_AddSignal->Signal();
|
||||
}
|
||||
m_QueueLock->Unlock();
|
||||
}
|
||||
|
||||
WorkerState ThreadWorker::GetStatus(unsigned int *threads)
|
||||
{
|
||||
WorkerState state;
|
||||
|
||||
m_StateLock->Lock();
|
||||
state = BaseWorker::GetStatus(threads);
|
||||
m_StateLock->Unlock();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Start()
|
||||
{
|
||||
if (m_state == Worker_Invalid)
|
||||
{
|
||||
if (m_Threader == NULL)
|
||||
return false;
|
||||
} else if (m_state != Worker_Stopped) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Waiting = false;
|
||||
m_QueueLock = m_Threader->MakeMutex();
|
||||
m_StateLock = m_Threader->MakeMutex();
|
||||
m_PauseSignal = m_Threader->MakeEventSignal();
|
||||
m_AddSignal = m_Threader->MakeEventSignal();
|
||||
m_state = Worker_Running;
|
||||
ThreadParams pt;
|
||||
pt.flags = Thread_Default;
|
||||
pt.prio = ThreadPrio_Normal;
|
||||
me = m_Threader->MakeThread(this, &pt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Stop(bool flush_cancel)
|
||||
{
|
||||
if (m_state == Worker_Invalid || m_state == Worker_Stopped)
|
||||
return false;
|
||||
|
||||
WorkerState oldstate;
|
||||
|
||||
//set new state
|
||||
m_StateLock->Lock();
|
||||
oldstate = m_state;
|
||||
m_state = Worker_Stopped;
|
||||
m_FlushType = flush_cancel;
|
||||
m_StateLock->Unlock();
|
||||
|
||||
if (oldstate == Worker_Paused)
|
||||
{
|
||||
Unpause();
|
||||
} else {
|
||||
m_QueueLock->Lock();
|
||||
if (m_Waiting)
|
||||
{
|
||||
m_AddSignal->Signal();
|
||||
}
|
||||
m_QueueLock->Unlock();
|
||||
}
|
||||
|
||||
me->WaitForThread();
|
||||
//destroy it
|
||||
me->DestroyThis();
|
||||
//flush all remaining events
|
||||
Flush(true);
|
||||
|
||||
//free mutex locks
|
||||
m_QueueLock->DestroyThis();
|
||||
m_StateLock->DestroyThis();
|
||||
m_PauseSignal->DestroyThis();
|
||||
m_AddSignal->DestroyThis();
|
||||
|
||||
//invalidizzle
|
||||
m_QueueLock = NULL;
|
||||
m_StateLock = NULL;
|
||||
m_PauseSignal = NULL;
|
||||
m_AddSignal = NULL;
|
||||
me = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadWorker::Pause()
|
||||
{
|
||||
if (m_state != Worker_Running)
|
||||
return false;
|
||||
|
||||
m_StateLock->Lock();
|
||||
m_state = Worker_Paused;
|
||||
m_StateLock->Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ThreadWorker::Unpause()
|
||||
{
|
||||
if (m_state != Worker_Paused)
|
||||
return false;
|
||||
|
||||
m_StateLock->Lock();
|
||||
m_state = Worker_Running;
|
||||
m_StateLock->Unlock();
|
||||
m_PauseSignal->Signal();
|
||||
if (m_Waiting)
|
||||
{
|
||||
m_AddSignal->Signal();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
54
core/thread/ThreadWorker.h
Normal file
54
core/thread/ThreadWorker.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_THREADWORKER_H
|
||||
#define _INCLUDE_SOURCEMOD_THREADWORKER_H
|
||||
|
||||
#include "BaseWorker.h"
|
||||
|
||||
#define DEFAULT_THINK_TIME_MS 500
|
||||
|
||||
class ThreadWorker : public BaseWorker, public IThread
|
||||
{
|
||||
public:
|
||||
ThreadWorker();
|
||||
ThreadWorker(IThreader *pThreader, unsigned int thinktime=DEFAULT_THINK_TIME_MS);
|
||||
virtual ~ThreadWorker();
|
||||
public: //IThread
|
||||
virtual void OnTerminate(IThreadHandle *pHandle, bool cancel);
|
||||
virtual void RunThread(IThreadHandle *pHandle);
|
||||
public: //IWorker
|
||||
//Controls the worker
|
||||
virtual bool Pause();
|
||||
virtual bool Unpause();
|
||||
virtual bool Start();
|
||||
virtual bool Stop(bool flush_cancel);
|
||||
//returns status and number of threads in queue
|
||||
virtual WorkerState GetStatus(unsigned int *numThreads);
|
||||
public: //BaseWorker
|
||||
virtual void AddThreadToQueue(SWThreadHandle *pHandle);
|
||||
virtual SWThreadHandle *PopThreadFromQueue();
|
||||
protected:
|
||||
IThreader *m_Threader;
|
||||
IMutex *m_QueueLock;
|
||||
IMutex *m_StateLock;
|
||||
IEventSignal *m_PauseSignal;
|
||||
IEventSignal *m_AddSignal;
|
||||
IThreadHandle *me;
|
||||
unsigned int m_think_time;
|
||||
volatile bool m_Waiting;
|
||||
volatile bool m_FlushType;
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_THREADWORKER_H
|
318
core/thread/WinThreads.cpp
Normal file
318
core/thread/WinThreads.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "WinThreads.h"
|
||||
#include "ThreadWorker.h"
|
||||
|
||||
IThreadWorker *WinThreader::MakeWorker(bool threaded)
|
||||
{
|
||||
if (threaded)
|
||||
{
|
||||
return new ThreadWorker(this, DEFAULT_THINK_TIME_MS);
|
||||
} else {
|
||||
return new BaseWorker();
|
||||
}
|
||||
}
|
||||
|
||||
void WinThreader::DestroyWorker(IThreadWorker *pWorker)
|
||||
{
|
||||
delete pWorker;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadSleep(unsigned int ms)
|
||||
{
|
||||
Sleep((DWORD)ms);
|
||||
}
|
||||
|
||||
IMutex *WinThreader::MakeMutex()
|
||||
{
|
||||
HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
|
||||
|
||||
if (mutex == NULL)
|
||||
return NULL;
|
||||
|
||||
WinMutex *pMutex = new WinMutex(mutex);
|
||||
|
||||
return pMutex;
|
||||
}
|
||||
|
||||
IThreadHandle *WinThreader::MakeThread(IThread *pThread, ThreadFlags flags)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = flags;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
return MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
void WinThreader::MakeThread(IThread *pThread)
|
||||
{
|
||||
ThreadParams defparams;
|
||||
|
||||
defparams.flags = Thread_AutoRelease;
|
||||
defparams.prio = ThreadPrio_Normal;
|
||||
|
||||
MakeThread(pThread, &defparams);
|
||||
}
|
||||
|
||||
DWORD WINAPI Win32_ThreadGate(LPVOID param)
|
||||
{
|
||||
WinThreader::ThreadHandle *pHandle =
|
||||
reinterpret_cast<WinThreader::ThreadHandle *>(param);
|
||||
|
||||
pHandle->m_run->RunThread(pHandle);
|
||||
|
||||
ThreadParams params;
|
||||
EnterCriticalSection(&pHandle->m_crit);
|
||||
pHandle->m_state = Thread_Done;
|
||||
pHandle->GetParams(¶ms);
|
||||
LeaveCriticalSection(&pHandle->m_crit);
|
||||
|
||||
pHandle->m_run->OnTerminate(pHandle, false);
|
||||
if (params.flags & Thread_AutoRelease)
|
||||
delete pHandle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WinThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
|
||||
{
|
||||
max = ThreadPrio_Maximum;
|
||||
min = ThreadPrio_Minimum;
|
||||
}
|
||||
|
||||
ThreadParams g_defparams;
|
||||
IThreadHandle *WinThreader::MakeThread(IThread *pThread, const ThreadParams *params)
|
||||
{
|
||||
if (params == NULL)
|
||||
params = &g_defparams;
|
||||
|
||||
WinThreader::ThreadHandle *pHandle =
|
||||
new WinThreader::ThreadHandle(this, NULL, pThread, params);
|
||||
|
||||
DWORD tid;
|
||||
pHandle->m_thread =
|
||||
CreateThread(NULL, 0, &Win32_ThreadGate, (LPVOID)pHandle, CREATE_SUSPENDED, &tid);
|
||||
|
||||
if (!pHandle->m_thread)
|
||||
{
|
||||
delete pHandle;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pHandle->m_params.prio != ThreadPrio_Normal)
|
||||
{
|
||||
pHandle->SetPriority(pHandle->m_params.prio);
|
||||
}
|
||||
|
||||
if (!(pHandle->m_params.flags & Thread_CreateSuspended))
|
||||
{
|
||||
pHandle->Unpause();
|
||||
}
|
||||
|
||||
return pHandle;
|
||||
}
|
||||
|
||||
IEventSignal *WinThreader::MakeEventSignal()
|
||||
{
|
||||
HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (!event)
|
||||
return NULL;
|
||||
|
||||
WinEvent *pEvent = new WinEvent(event);
|
||||
|
||||
return pEvent;
|
||||
}
|
||||
|
||||
/*****************
|
||||
**** Mutexes ****
|
||||
*****************/
|
||||
|
||||
WinThreader::WinMutex::~WinMutex()
|
||||
{
|
||||
if (m_mutex)
|
||||
{
|
||||
CloseHandle(m_mutex);
|
||||
m_mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool WinThreader::WinMutex::TryLock()
|
||||
{
|
||||
if (!m_mutex)
|
||||
return false;
|
||||
|
||||
if (WaitForSingleObject(m_mutex, 0) != WAIT_FAILED)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WinThreader::WinMutex::Lock()
|
||||
{
|
||||
if (!m_mutex)
|
||||
return;
|
||||
|
||||
WaitForSingleObject(m_mutex, INFINITE);
|
||||
}
|
||||
|
||||
void WinThreader::WinMutex::Unlock()
|
||||
{
|
||||
if (!m_mutex)
|
||||
return;
|
||||
|
||||
ReleaseMutex(m_mutex);
|
||||
}
|
||||
|
||||
void WinThreader::WinMutex::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
/******************
|
||||
* Thread Handles *
|
||||
******************/
|
||||
|
||||
WinThreader::ThreadHandle::ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params) :
|
||||
m_parent(parent), m_thread(hthread), m_run(run), m_params(*params),
|
||||
m_state(Thread_Paused)
|
||||
{
|
||||
InitializeCriticalSection(&m_crit);
|
||||
}
|
||||
|
||||
WinThreader::ThreadHandle::~ThreadHandle()
|
||||
{
|
||||
if (m_thread)
|
||||
{
|
||||
CloseHandle(m_thread);
|
||||
m_thread = NULL;
|
||||
}
|
||||
DeleteCriticalSection(&m_crit);
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::WaitForThread()
|
||||
{
|
||||
if (m_thread == NULL)
|
||||
return false;
|
||||
|
||||
if (WaitForSingleObject(m_thread, INFINITE) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadState WinThreader::ThreadHandle::GetState()
|
||||
{
|
||||
ThreadState state;
|
||||
|
||||
EnterCriticalSection(&m_crit);
|
||||
state = m_state;
|
||||
LeaveCriticalSection(&m_crit);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
IThreadCreator *WinThreader::ThreadHandle::Parent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadHandle::DestroyThis()
|
||||
{
|
||||
if (m_params.flags & Thread_AutoRelease)
|
||||
return;
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WinThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
|
||||
{
|
||||
if (!ptparams)
|
||||
return;
|
||||
|
||||
*ptparams = m_params;
|
||||
}
|
||||
|
||||
ThreadPriority WinThreader::ThreadHandle::GetPriority()
|
||||
{
|
||||
return m_params.prio;
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::SetPriority(ThreadPriority prio)
|
||||
{
|
||||
if (!m_thread)
|
||||
return false;
|
||||
|
||||
BOOL res = FALSE;
|
||||
|
||||
if (prio >= ThreadPrio_Maximum)
|
||||
res = SetThreadPriority(m_thread, THREAD_PRIORITY_HIGHEST);
|
||||
else if (prio <= ThreadPrio_Minimum)
|
||||
res = SetThreadPriority(m_thread, THREAD_PRIORITY_LOWEST);
|
||||
else if (prio == ThreadPrio_Normal)
|
||||
res = SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);
|
||||
else if (prio == ThreadPrio_High)
|
||||
res = SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
else if (prio == ThreadPrio_Low)
|
||||
res = SetThreadPriority(m_thread, THREAD_PRIORITY_BELOW_NORMAL);
|
||||
|
||||
m_params.prio = prio;
|
||||
|
||||
return (res != FALSE);
|
||||
}
|
||||
|
||||
bool WinThreader::ThreadHandle::Unpause()
|
||||
{
|
||||
if (!m_thread)
|
||||
return false;
|
||||
|
||||
if (m_state != Thread_Paused)
|
||||
return false;
|
||||
|
||||
m_state = Thread_Running;
|
||||
|
||||
if (ResumeThread(m_thread) == -1)
|
||||
{
|
||||
m_state = Thread_Paused;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************
|
||||
* EVENT SIGNALS *
|
||||
*****************/
|
||||
|
||||
WinThreader::WinEvent::~WinEvent()
|
||||
{
|
||||
CloseHandle(m_event);
|
||||
}
|
||||
|
||||
void WinThreader::WinEvent::Wait()
|
||||
{
|
||||
WaitForSingleObject(m_event, INFINITE);
|
||||
}
|
||||
|
||||
void WinThreader::WinEvent::Signal()
|
||||
{
|
||||
SetEvent(m_event);
|
||||
}
|
||||
|
||||
void WinThreader::WinEvent::DestroyThis()
|
||||
{
|
||||
delete this;
|
||||
}
|
98
core/thread/WinThreads.h
Normal file
98
core/thread/WinThreads.h
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit
|
||||
* written permission of AlliedModders LLC. This file may not be redistributed
|
||||
* in whole or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_WINTHREADS_H_
|
||||
#define _INCLUDE_WINTHREADS_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "IThreader.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
DWORD WINAPI Win32_ThreadGate(LPVOID param);
|
||||
|
||||
class WinThreader : public IThreader
|
||||
{
|
||||
public:
|
||||
class ThreadHandle : public IThreadHandle
|
||||
{
|
||||
friend class WinThreader;
|
||||
friend DWORD WINAPI Win32_ThreadGate(LPVOID param);
|
||||
public:
|
||||
ThreadHandle(IThreader *parent, HANDLE hthread, IThread *run, const ThreadParams *params);
|
||||
virtual ~ThreadHandle();
|
||||
public:
|
||||
virtual bool WaitForThread();
|
||||
virtual void DestroyThis();
|
||||
virtual IThreadCreator *Parent();
|
||||
virtual void GetParams(ThreadParams *ptparams);
|
||||
virtual ThreadPriority GetPriority();
|
||||
virtual bool SetPriority(ThreadPriority prio);
|
||||
virtual ThreadState GetState();
|
||||
virtual bool Unpause();
|
||||
protected:
|
||||
IThreader *m_parent; //Parent handle
|
||||
HANDLE m_thread; //Windows HANDLE
|
||||
ThreadParams m_params; //Current Parameters
|
||||
IThread *m_run; //Runnable context
|
||||
ThreadState m_state; //internal state
|
||||
CRITICAL_SECTION m_crit;
|
||||
};
|
||||
class WinMutex : public IMutex
|
||||
{
|
||||
public:
|
||||
WinMutex(HANDLE mutex) : m_mutex(mutex)
|
||||
{
|
||||
};
|
||||
virtual ~WinMutex();
|
||||
public:
|
||||
virtual bool TryLock();
|
||||
virtual void Lock();
|
||||
virtual void Unlock();
|
||||
virtual void DestroyThis();
|
||||
protected:
|
||||
HANDLE m_mutex;
|
||||
};
|
||||
class WinEvent : public IEventSignal
|
||||
{
|
||||
public:
|
||||
WinEvent(HANDLE event) : m_event(event)
|
||||
{
|
||||
};
|
||||
virtual ~WinEvent();
|
||||
public:
|
||||
virtual void Wait();
|
||||
virtual void Signal();
|
||||
virtual void DestroyThis();
|
||||
public:
|
||||
HANDLE m_event;
|
||||
};
|
||||
public:
|
||||
IMutex *MakeMutex();
|
||||
void MakeThread(IThread *pThread);
|
||||
IThreadHandle *MakeThread(IThread *pThread, ThreadFlags flags);
|
||||
IThreadHandle *MakeThread(IThread *pThread, const ThreadParams *params);
|
||||
void GetPriorityBounds(ThreadPriority &max, ThreadPriority &min);
|
||||
void ThreadSleep(unsigned int ms);
|
||||
IEventSignal *MakeEventSignal();
|
||||
IThreadWorker *MakeWorker(bool threaded);
|
||||
void DestroyWorker(IThreadWorker *pWorker);
|
||||
};
|
||||
|
||||
#if defined SM_DEFAULT_THREADER && !defined SM_MAIN_THREADER
|
||||
#define SM_MAIN_THREADER WinThreader;
|
||||
typedef class WinThreader MainThreader;
|
||||
#endif
|
||||
|
||||
#endif //_INCLUDE_WINTHREADS_H_
|
Loading…
Reference in New Issue
Block a user