core/thread/PosixThreads.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1947 e73a1e51833b
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <unistd.h>
    33 #include "PosixThreads.h"
    34 #include "ThreadWorker.h"
    35 
    36 IThreadWorker *PosixThreader::MakeWorker(IThreadWorkerCallbacks *hooks, bool threaded)
    37 {
    38 	if (threaded)
    39 	{
    40 		return new ThreadWorker(hooks, this, DEFAULT_THINK_TIME_MS);
    41 	} else {
    42 		return new BaseWorker(hooks);
    43 	}
    44 }
    45 
    46 void PosixThreader::DestroyWorker(IThreadWorker *pWorker)
    47 {
    48 	delete pWorker;
    49 }
    50 
    51 void PosixThreader::ThreadSleep(unsigned int ms)
    52 {
    53 	usleep( ms * 1000 );
    54 }
    55 
    56 void PosixThreader::GetPriorityBounds(ThreadPriority &max, ThreadPriority &min)
    57 {
    58 	max = ThreadPrio_Normal;
    59 	min = ThreadPrio_Normal;
    60 }
    61 
    62 IMutex *PosixThreader::MakeMutex()
    63 {
    64 	pthread_mutex_t mutex;
    65 
    66 	if (pthread_mutex_init(&mutex, NULL) != 0)
    67 		return NULL;
    68 
    69 	PosixMutex *pMutex = new PosixMutex(mutex);
    70 
    71 	return pMutex;
    72 }
    73 
    74 
    75 void PosixThreader::MakeThread(IThread *pThread)
    76 {
    77 	ThreadParams defparams;
    78 
    79 	defparams.flags = Thread_AutoRelease;
    80 	defparams.prio = ThreadPrio_Normal;
    81 
    82 	MakeThread(pThread, &defparams);
    83 }
    84 
    85 IThreadHandle *PosixThreader::MakeThread(IThread *pThread, ThreadFlags flags)
    86 {
    87 	ThreadParams defparams;
    88 
    89 	defparams.flags = flags;
    90 	defparams.prio = ThreadPrio_Normal;
    91 
    92 	return MakeThread(pThread, &defparams);
    93 }
    94 
    95 void *Posix_ThreadGate(void *param)
    96 {
    97 	PosixThreader::ThreadHandle *pHandle = 
    98 		reinterpret_cast<PosixThreader::ThreadHandle *>(param);
    99 
   100 	//Block this thread from being started initially.
   101 	pthread_mutex_lock(&pHandle->m_runlock);
   102 	//if we get here, we've obtained the lock and are allowed to run.
   103 	//unlock and continue.
   104 	pthread_mutex_unlock(&pHandle->m_runlock);
   105 
   106 	pHandle->m_run->RunThread(pHandle);
   107 
   108 	ThreadParams params;
   109 	pthread_mutex_lock(&pHandle->m_statelock);
   110 	pHandle->m_state = Thread_Done;
   111 	pHandle->GetParams(&params);
   112 	pthread_mutex_unlock(&pHandle->m_statelock);
   113 
   114 	pHandle->m_run->OnTerminate(pHandle, false);
   115 	if (params.flags & Thread_AutoRelease)
   116 		delete pHandle;
   117 
   118 	return 0;
   119 }
   120 
   121 ThreadParams g_defparams;
   122 IThreadHandle *PosixThreader::MakeThread(IThread *pThread, const ThreadParams *params)
   123 {
   124 	if (params == NULL)
   125 		params = &g_defparams;
   126 
   127 	PosixThreader::ThreadHandle *pHandle = 
   128 		new PosixThreader::ThreadHandle(this, pThread, params);
   129 
   130 	pthread_mutex_lock(&pHandle->m_runlock);
   131 
   132 	int err;
   133 	err = pthread_create(&pHandle->m_thread, NULL, Posix_ThreadGate, (void *)pHandle);	
   134 
   135 	if (err != 0)
   136 	{
   137 		pthread_mutex_unlock(&pHandle->m_runlock);
   138 		delete pHandle;
   139 		return NULL;
   140 	}
   141 
   142 	//Don't bother setting priority...
   143 
   144 	if (!(pHandle->m_params.flags & Thread_CreateSuspended))
   145 	{
   146 		pHandle->m_state = Thread_Running;
   147 		err = pthread_mutex_unlock(&pHandle->m_runlock);
   148 		if (err != 0)
   149 			pHandle->m_state = Thread_Paused;
   150 	}
   151 
   152 	return pHandle;
   153 }
   154 
   155 IEventSignal *PosixThreader::MakeEventSignal()
   156 {
   157 	return new PosixEventSignal();
   158 }
   159 
   160 /*****************
   161 **** Mutexes ****
   162 *****************/
   163 
   164 PosixThreader::PosixMutex::~PosixMutex()
   165 {
   166 	pthread_mutex_destroy(&m_mutex);
   167 }
   168 
   169 bool PosixThreader::PosixMutex::TryLock()
   170 {
   171 	int err = pthread_mutex_trylock(&m_mutex);
   172 
   173 	return (err == 0);
   174 }
   175 
   176 void PosixThreader::PosixMutex::Lock()
   177 {
   178 	pthread_mutex_lock(&m_mutex);
   179 }
   180 
   181 void PosixThreader::PosixMutex::Unlock()
   182 {
   183 	pthread_mutex_unlock(&m_mutex);
   184 }
   185 
   186 void PosixThreader::PosixMutex::DestroyThis()
   187 {
   188 	delete this;
   189 }
   190 
   191 /******************
   192 * Thread Handles *
   193 ******************/
   194 
   195 PosixThreader::ThreadHandle::ThreadHandle(IThreader *parent, IThread *run, const ThreadParams *params) : 
   196 	m_parent(parent), m_params(*params), m_run(run), m_state(Thread_Paused)
   197 {
   198 	pthread_mutex_init(&m_runlock, NULL);
   199 	pthread_mutex_init(&m_statelock, NULL);
   200 }
   201 
   202 PosixThreader::ThreadHandle::~ThreadHandle()
   203 {
   204 	pthread_mutex_destroy(&m_runlock);
   205 	pthread_mutex_destroy(&m_statelock);
   206 }
   207 
   208 bool PosixThreader::ThreadHandle::WaitForThread()
   209 {
   210 	void *arg;
   211 	
   212 	if (pthread_join(m_thread, &arg) != 0)
   213 		return false;
   214 
   215 	return true;
   216 }
   217 
   218 ThreadState PosixThreader::ThreadHandle::GetState()
   219 {
   220 	ThreadState state;
   221 
   222 	pthread_mutex_lock(&m_statelock);
   223 	state = m_state;
   224 	pthread_mutex_unlock(&m_statelock);
   225 
   226 	return state;
   227 }
   228 
   229 IThreadCreator *PosixThreader::ThreadHandle::Parent()
   230 {
   231 	return m_parent;
   232 }
   233 
   234 void PosixThreader::ThreadHandle::DestroyThis()
   235 {
   236 	if (m_params.flags & Thread_AutoRelease)
   237 		return;
   238 
   239 	delete this;
   240 }
   241 
   242 void PosixThreader::ThreadHandle::GetParams(ThreadParams *ptparams)
   243 {
   244 	if (!ptparams)
   245 		return;
   246 
   247 	*ptparams = m_params;
   248 }
   249 
   250 ThreadPriority PosixThreader::ThreadHandle::GetPriority()
   251 {
   252 	return ThreadPrio_Normal;
   253 }
   254 
   255 bool PosixThreader::ThreadHandle::SetPriority(ThreadPriority prio)
   256 {
   257 	return (prio == ThreadPrio_Normal);
   258 }
   259 
   260 bool PosixThreader::ThreadHandle::Unpause()
   261 {
   262 	if (m_state != Thread_Paused)
   263 		return false;
   264 
   265 	m_state = Thread_Running;
   266 
   267 	if (pthread_mutex_unlock(&m_runlock) != 0)
   268 	{
   269 		m_state = Thread_Paused;
   270 		return false;
   271 	}
   272 
   273 	return true;
   274 }
   275 
   276 /*****************
   277  * EVENT SIGNALS *
   278  *****************/
   279 
   280 PosixThreader::PosixEventSignal::PosixEventSignal()
   281 {
   282 	pthread_cond_init(&m_cond, NULL);
   283 	pthread_mutex_init(&m_mutex, NULL);
   284 }
   285 
   286 PosixThreader::PosixEventSignal::~PosixEventSignal()
   287 {
   288 	pthread_cond_destroy(&m_cond);
   289 	pthread_mutex_destroy(&m_mutex);
   290 }
   291 
   292 void PosixThreader::PosixEventSignal::Wait()
   293 {
   294 	pthread_mutex_lock(&m_mutex);
   295 	pthread_cond_wait(&m_cond, &m_mutex);
   296 	pthread_mutex_unlock(&m_mutex);
   297 }
   298 
   299 void PosixThreader::PosixEventSignal::Signal()
   300 {
   301 	pthread_mutex_lock(&m_mutex);
   302 	pthread_cond_broadcast(&m_cond);
   303 	pthread_mutex_unlock(&m_mutex);
   304 }
   305 
   306 void PosixThreader::PosixEventSignal::DestroyThis()
   307 {
   308         delete this;
   309 }