Rewrite IThreader implementation around new synchronization primitives (
bug 5862, r=fyren).
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "ThreadWorker.h"
34 ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks) : BaseWorker(hooks),
37 m_think_time(DEFAULT_THINK_TIME_MS)
39 m_state = Worker_Invalid;
42 ThreadWorker::ThreadWorker(IThreadWorkerCallbacks *hooks, IThreader *pThreader, unsigned int thinktime) :
44 m_Threader(pThreader),
46 m_think_time(thinktime)
48 m_state = m_Threader ? Worker_Stopped : Worker_Invalid;
51 ThreadWorker::~ThreadWorker()
53 if (m_state != Worker_Stopped || m_state != Worker_Invalid)
56 if (m_ThreadQueue.size())
60 void ThreadWorker::OnTerminate(IThreadHandle *pHandle, bool cancel)
62 //we don't particularly care
66 void ThreadWorker::RunThread(IThreadHandle *pHandle)
69 m_pHooks->OnWorkerStart(this);
71 ke::AutoLock lock(&monitor_);
75 if (m_state == Worker_Paused)
77 // Wait until we're told to wake up.
82 if (m_state == Worker_Stopped)
84 // We've been told to stop entirely. If we've also been told to
85 // flush the queue, do that now.
86 while (!m_ThreadQueue.empty())
88 // Release the lock since PopThreadFromQueue() will re-acquire it. The
89 // main thread is blocking anyway.
90 ke::AutoUnlock unlock(&monitor_);
93 assert(m_state == Worker_Stopped);
97 assert(m_state == Worker_Running);
100 WorkerState oldstate = m_state;
102 ke::AutoUnlock unlock(&monitor_);
106 // If the state changed, loop back and process the new state.
107 if (m_state != oldstate)
110 // If the thread queue is now empty, wait for a signal. Otherwise, if
111 // we're on a delay, wait for either a notification or a timeout to
112 // process the next item. If the queue has items and we don't have a
113 // delay, then we just loop around and keep processing.
114 if (m_ThreadQueue.empty())
116 else if (m_think_time)
117 monitor_.Wait(m_think_time);
121 ke::AutoUnlock unlock(&monitor_);
123 m_pHooks->OnWorkerStop(this);
127 SWThreadHandle *ThreadWorker::PopThreadFromQueue()
129 ke::AutoLock lock(&monitor_);
130 if (m_state <= Worker_Stopped)
133 return BaseWorker::PopThreadFromQueue();
136 void ThreadWorker::AddThreadToQueue(SWThreadHandle *pHandle)
138 ke::AutoLock lock(&monitor_);
139 if (m_state <= Worker_Stopped)
142 BaseWorker::AddThreadToQueue(pHandle);
146 WorkerState ThreadWorker::GetStatus(unsigned int *threads)
148 ke::AutoLock lock(&monitor_);
149 return BaseWorker::GetStatus(threads);
152 void ThreadWorker::SetThinkTimePerFrame(unsigned int thinktime)
154 m_think_time = thinktime;
157 bool ThreadWorker::Start()
159 if (m_state == Worker_Invalid && m_Threader == NULL)
162 if (m_state != Worker_Stopped)
165 m_state = Worker_Running;
168 pt.flags = Thread_Default;
169 pt.prio = ThreadPrio_Normal;
170 me = m_Threader->MakeThread(this, &pt);
174 bool ThreadWorker::Stop(bool flush_cancel)
176 // Change the state to signal a stop, and then trigger a notify.
178 ke::AutoLock lock(&monitor_);
179 if (m_state == Worker_Invalid || m_state == Worker_Stopped)
182 m_state = Worker_Stopped;
183 m_FlushType = flush_cancel;
190 //flush all remaining events
197 bool ThreadWorker::Pause()
199 if (m_state != Worker_Running)
202 ke::AutoLock lock(&monitor_);
203 m_state = Worker_Paused;
209 bool ThreadWorker::Unpause()
211 if (m_state != Worker_Paused)
214 ke::AutoLock lock(&monitor_);
215 m_state = Worker_Running;