core/thread/PosixThreads.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jul 12 16:57:26 2007 +0000 (2007-07-12)
changeset 1090 5c54e353c019
parent 1084 241c1b9b4048
child 1231 17badaf66ce4
permissions -rw-r--r--
- added callback functionality to IThreadWorker
- added exposure of IThreader to sample sdk
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod Threader API
     5  * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
     6  * ===============================================================
     7  *
     8  * This program is free software; you can redistribute it and/or
     9  * modify it under the terms of the GNU General Public License
    10  * as published by the Free Software Foundation; either version 2
    11  * of the License, or (at your option) any later version.
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  * 
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    20  *
    21  * Version: $Id$
    22  */
    23 
    24 #include <unistd.h>
    25 #include "PosixThreads.h"
    26 #include "ThreadWorker.h"
    27 
    28 IThreadWorker *PosixThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
    29 {
    30 	if (threaded)
    31 	{
    32 		return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
    33 	} else {
    34 		return new BaseWorker(hooks);
    35 	}
    36 }
    37 
    38 void PosixThreader::DestroyWorker(IThreadWorker *pWorker)
    39 {
    40 	delete pWorker;
    41 }
    42 
    43 void PosixThreader::ThreadSleep(unsigned int ms)
    44 {
    45 	usleep( ms * 1000 );
    46 }
    47 
    48 void PosixThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
    49 {
    50 	max = ThreadPrio_Normal;
    51 	min = ThreadPrio_Normal;
    52 }
    53 
    54 IMutex *PosixThreader::MakeMutex()
    55 {
    56 	pthread_mutex_t mutex;
    57 
    58 	if (pthread_mutex_init(&mutex, NULL) != 0)
    59 		return NULL;
    60 
    61 	PosixMutex *pMutex = new PosixMutex(mutex);
    62 
    63 	return pMutex;
    64 }
    65 
    66 
    67 void PosixThreader::MakeThread(IThread *pThread)
    68 {
    69 	ThreadParams defparams;
    70 
    71 	defparams.flags = Thread_AutoRelease;
    72 	defparams.prio = ThreadPrio_Normal;
    73 
    74 	MakeThread(pThread, &defparams);
    75 }
    76 
    77 IThreadHandle *PosixThreader::MakeThread(IThread *pThread, ThreadFlags flags)
    78 {
    79 	ThreadParams defparams;
    80 
    81 	defparams.flags = flags;
    82 	defparams.prio = ThreadPrio_Normal;
    83 
    84 	return MakeThread(pThread, &defparams);
    85 }
    86 
    87 void *Posix_ThreadGate(void *param)
    88 {
    89 	PosixThreader::ThreadHandle *pHandle = 
    90 		reinterpret_cast<PosixThreader::ThreadHandle *>(param);
    91 
    92 	//Block this thread from being started initially.
    93 	pthread_mutex_lock(&pHandle->m_runlock);
    94 	//if we get here, we've obtained the lock and are allowed to run.
    95 	//unlock and continue.
    96 	pthread_mutex_unlock(&pHandle->m_runlock);
    97 
    98 	pHandle->m_run->RunThread(pHandle);
    99 
   100 	ThreadParams params;
   101 	pthread_mutex_lock(&pHandle->m_statelock);
   102 	pHandle->m_state = Thread_Done;
   103 	pHandle->GetParams(&params);
   104 	pthread_mutex_unlock(&pHandle->m_statelock);
   105 
   106 	pHandle->m_run->OnTerminate(pHandle, false);
   107 	if (params.flags & Thread_AutoRelease)
   108 		delete pHandle;
   109 
   110 	return 0;
   111 }
   112 
   113 ThreadParams g_defparams;
   114 IThreadHandle *PosixThreader::MakeThread(IThread *pThread, const ThreadParams *params)
   115 {
   116 	if (params == NULL)
   117 		params = &g_defparams;
   118 
   119 	PosixThreader::ThreadHandle *pHandle = 
   120 		new PosixThreader::ThreadHandle(this, pThread, params);
   121 
   122 	pthread_mutex_lock(&pHandle->m_runlock);
   123 
   124 	int err;
   125 	err = pthread_create(&pHandle->m_thread, NULL, Posix_ThreadGate, (void *)pHandle);	
   126 
   127 	if (err != 0)
   128 	{
   129 		pthread_mutex_unlock(&pHandle->m_runlock);
   130 		delete pHandle;
   131 		return NULL;
   132 	}
   133 
   134 	//Don't bother setting priority...
   135 
   136 	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
   137 	{
   138 		pHandle->m_state = Thread_Running;
   139 		err = pthread_mutex_unlock(&pHandle->m_runlock);
   140 		if (err != 0)
   141 			pHandle->m_state = Thread_Paused;
   142 	}
   143 
   144 	return pHandle;
   145 }
   146 
   147 IEventSignal *PosixThreader::MakeEventSignal()
   148 {
   149 	return new PosixEventSignal();
   150 }
   151 
   152 /*****************
   153 **** Mutexes ****
   154 *****************/
   155 
   156 PosixThreader::PosixMutex::~PosixMutex()
   157 {
   158 	pthread_mutex_destroy(&m_mutex);
   159 }
   160 
   161 bool PosixThreader::PosixMutex::TryLock()
   162 {
   163 	int err = pthread_mutex_trylock(&m_mutex);
   164 
   165 	return (err == 0);
   166 }
   167 
   168 void PosixThreader::PosixMutex::Lock()
   169 {
   170 	pthread_mutex_lock(&m_mutex);
   171 }
   172 
   173 void PosixThreader::PosixMutex::Unlock()
   174 {
   175 	pthread_mutex_unlock(&m_mutex);
   176 }
   177 
   178 void PosixThreader::PosixMutex::DestroyThis()
   179 {
   180 	delete this;
   181 }
   182 
   183 /******************
   184 * Thread Handles *
   185 ******************/
   186 
   187 PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : 
   188 	m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused)
   189 {
   190 	pthread_mutex_init(&m_runlock, NULL);
   191 	pthread_mutex_init(&m_statelock, NULL);
   192 }
   193 
   194 PosixThreader::ThreadHandle::~ThreadHandle()
   195 {
   196 	pthread_mutex_destroy(&m_runlock);
   197 	pthread_mutex_destroy(&m_statelock);
   198 }
   199 
   200 bool PosixThreader::ThreadHandle::WaitForThread()
   201 {
   202 	void *arg;
   203 	
   204 	if (pthread_join(m_thread, &arg) != 0)
   205 		return false;
   206 
   207 	return true;
   208 }
   209 
   210 ThreadState PosixThreader::ThreadHandle::GetState()
   211 {
   212 	ThreadState state;
   213 
   214 	pthread_mutex_lock(&m_statelock);
   215 	state = m_state;
   216 	pthread_mutex_unlock(&m_statelock);
   217 
   218 	return state;
   219 }
   220 
   221 IThreadCreator *PosixThreader::ThreadHandle::Parent()
   222 {
   223 	return m_parent;
   224 }
   225 
   226 void PosixThreader::ThreadHandle::DestroyThis()
   227 {
   228 	if (m_params.flags & Thread_AutoRelease)
   229 		return;
   230 
   231 	delete this;
   232 }
   233 
   234 void PosixThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
   235 {
   236 	if (!ptparams)
   237 		return;
   238 
   239 	*ptparams = m_params;
   240 }
   241 
   242 ThreadPriority PosixThreader::ThreadHandle::GetPriority()
   243 {
   244 	return ThreadPrio_Normal;
   245 }
   246 
   247 bool PosixThreader::ThreadHandle::SetPriority(ThreadPriority prio)
   248 {
   249 	return (prio == ThreadPrio_Normal);
   250 }
   251 
   252 bool PosixThreader::ThreadHandle::Unpause()
   253 {
   254 	if (m_state != Thread_Paused)
   255 		return false;
   256 
   257 	m_state = Thread_Running;
   258 
   259 	if (pthread_mutex_unlock(&m_runlock) != 0)
   260 	{
   261 		m_state = Thread_Paused;
   262 		return false;
   263 	}
   264 
   265 	return true;
   266 }
   267 
   268 /*****************
   269  * EVENT SIGNALS *
   270  *****************/
   271 
   272 PosixThreader::PosixEventSignal::PosixEventSignal()
   273 {
   274 	pthread_cond_init(&m_cond, NULL);
   275 	pthread_mutex_init(&m_mutex, NULL);
   276 }
   277 
   278 PosixThreader::PosixEventSignal::~PosixEventSignal()
   279 {
   280 	pthread_cond_destroy(&m_cond);
   281 	pthread_mutex_destroy(&m_mutex);
   282 }
   283 
   284 void PosixThreader::PosixEventSignal::Wait()
   285 {
   286 	pthread_mutex_lock(&m_mutex);
   287 	pthread_cond_wait(&m_cond, &m_mutex);
   288 	pthread_mutex_unlock(&m_mutex);
   289 }
   290 
   291 void PosixThreader::PosixEventSignal::Signal()
   292 {
   293 	pthread_mutex_lock(&m_mutex);
   294 	pthread_cond_broadcast(&m_cond);
   295 	pthread_mutex_unlock(&m_mutex);
   296 }
   297 
   298 void PosixThreader::PosixEventSignal::DestroyThis()
   299 {
   300         delete this;
   301 }