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