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