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