* #35924 (zrtp): switch to libzrtpcpp
diff --git a/jni/libzrtp/sources/common/Thread.cpp b/jni/libzrtp/sources/common/Thread.cpp
new file mode 100644
index 0000000..1bec1f0
--- /dev/null
+++ b/jni/libzrtp/sources/common/Thread.cpp
@@ -0,0 +1,1129 @@
+//
+// Thread.cpp: implementation file
+//
+// Copyright (C) Walter E. Capers.  All rights reserved
+//
+// This source is free to use as you like.  If you make
+// any changes please keep me in the loop.  Email your changes
+// to walt.capers@comcast.net.
+//
+// PURPOSE:
+//
+//  To implement threading as a C++ object
+//
+// NOTES:
+//  This object supports two types of thread models, event driven and
+//  interval driven.  Under the event driven model, a thread waits
+//  in a paused state until the member function Event is called.  When
+//  the Event function is called the thread wakes up and calls OnTask.
+//  Under the interval driven model, the thread wakes up every
+//  m_dwIdle milli-seconds and calls OnTask.
+//
+//  You can switch between the two models from within the same object.
+//
+// COMPILER NOTES:
+// On Unix you must use -lpthread a -lrt
+// On Windows you must specify threaded under C++ code generation
+//
+// REVISIONS
+// =======================================================
+// Date: 10.24.07        
+// Name: Walter E. Capers
+// Description: File creation
+//
+// Date: 10.24.07 11:49 am
+// Name: Walter E. Capers
+// Description: Added SetIdle function to allow the idle time to be altered
+//              independent of the SetThreadType member function.
+//              Added sleep interval to Stop function.
+//
+// Date: 10.25.07
+// Name: Walter E. Capers
+// Description: Added support for other non-windows platforms.
+//
+//              Added static functions: ThreadIdsEqual and ThreadId.
+//
+//              Added que for handling multiple events.
+//
+//              Created the CEventClass and CMutexClass classes to facilitate
+//              platform independence.
+//
+// Date: 10.26.07
+// Name: Walter E. Capers
+// Description: Made object production ready...
+//              Added more comments
+//
+//              Addressed various issues with threads on UNIX systems.
+//                -- there was a defect in the Sleep function
+//                -- there was a defect in the main thread function THKERNEL
+//                   , when transitioning between thread models the CEvent::Reset
+//                   function was not being called when it was necessary resulting
+//                   in a lock up.
+//              
+//				 Transition between thread types also failed on WINDOWS since the Event
+//               member function was being called from within SetThreadType.  This
+//               resulted in an Event usage error.  To correct the problem m_event.Set
+//               is called instead.  Also, eliminated unecessary logic.
+//
+//               Got rid of OnStart, OnStop, OnDestroy... Could not override with a derived
+//				 class, not sure why I will come back to in a later release.
+//
+//				 Changed default behavior of thread.  If OnTask is not redefined in the derived
+//               class the default version now expects a CTask object.  The Class for CTask 
+//               is defined in thread.h.  A class must be derived from CTask to use it in
+//               the default version of OnTask(LPVOID).
+//
+// Date: 11.01.07
+// Name: Walter E. Capers
+// Description: I introduced more logic and ASSERTIONS to insure the integrity of CThread objects.  
+//              Both the Homogeneous and Specialized thread types can be physically set using the 
+//              SetThreadType member function.  If the thread type is not set, the thread will
+//              determine its type based on calls to member functions; however, this does not
+//              apply to interval-based threads.  Interval-based threads must be implicitly
+//              identified using the SetThreadType member function.  The new integrity tests
+//              are implemented to insure usage consistency with a CThread object.   
+//
+//              New member functions AtCapacity and PercentCapacity were added to determine
+//              if a thread is truly busy.  AtCapacity will return TRUE under one of two 
+//              conditions: the thread is processing an event and its stack is full, the thread
+//              is not running.  These new functions allow thread objects to be placed in arrays
+//              and tasked based on their workloads.
+//
+//              The Event member function has been modified to verify that a thread is running
+//              before posting an event.  This resolved a problem on SunOS were threads did not
+//              start right away; there was a small delay of a few milliseconds.    
+//
+//              Error flags are automatically reset when certain member functions are called this
+//              isolates error occurrences to specific call sequences.
+//
+//
+// Date: 11.01.07
+// Name: Walter E. Capers
+// Description: In THKernel, changed how events are released.  Events are now released right after
+//              They are recieved.
+
+#include "Thread.h"
+#ifdef USE_BEGIN_THREAD
+#include <process.h>
+#endif
+
+
+
+#ifndef WINDOWS
+
+#include <unistd.h>
+#include <pthread.h>
+
+extern "C"
+{
+ //int	usleep(useconds_t useconds);
+#ifdef NANO_SECOND_SLEEP
+ int 	nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+#endif
+}
+
+void Sleep( unsigned int milli )
+{
+#ifdef NANO_SECOND_SLEEP
+	struct timespec interval, remainder;
+	milli = milli * 1000000;
+	interval.tv_sec= 0;
+	interval.tv_nsec=milli;
+	nanosleep(&interval,&remainder);
+#else
+	usleep(milli*1000);
+#endif	
+}
+#endif
+
+#include <iostream>
+using namespace std;
+
+/**
+ * 
+ * _THKERNEL
+ * thread callback function used by CreateThread
+ *
+ *
+ **/
+#ifdef WINDOWS
+#ifdef USE_BEGIN_THREAD
+unsigned __stdcall
+#else
+DWORD WINAPI
+#endif
+#else
+LPVOID
+#endif
+_THKERNEL( LPVOID lpvData /* CThread Object */ 
+		  )
+{
+	CThread *pThread = (CThread *)lpvData;
+	ThreadType_t lastType;
+	/*
+	 *
+	 * initialization
+	 *
+	 */
+
+
+    pThread->m_mutex.Lock();
+		pThread->m_state = ThreadStateWaiting;
+		pThread->m_bRunning = TRUE;
+#ifndef WINDOWS
+		pThread->m_dwId = CThread::ThreadId();
+#endif
+	pThread->m_mutex.Unlock();
+	
+	while( TRUE )
+	{
+		lastType = pThread->m_type;
+
+		if( lastType == ThreadTypeHomogeneous ||
+			lastType == ThreadTypeSpecialized ||
+			lastType == ThreadTypeNotDefined )
+		{
+			if( ! pThread->m_event.Wait()  )  // wait for a message
+					break;
+			pThread->m_event.Reset(); // message recieved
+		}
+	
+		if( ! pThread->KernelProcess() ) 
+				break;
+
+
+		/*if( lastType == ThreadTypeHomogeneous ||
+			lastType == ThreadTypeSpecialized ||
+			lastType == ThreadTypeNotDefined )
+		{
+			pThread->m_event.Reset();
+		} */
+
+		if( pThread->m_type == ThreadTypeIntervalDriven )
+			Sleep(pThread->m_dwIdle);
+
+	}
+
+
+	pThread->m_mutex.Lock();
+		pThread->m_state = ThreadStateDown;
+		pThread->m_bRunning = FALSE;
+	pThread->m_mutex.Unlock();
+
+
+#ifdef WINDOWS
+	return 0;
+#else
+	return (LPVOID)0;
+#endif
+}
+
+/**
+ *
+ * FromSameThread
+ * determines if the calling thread is the same
+ * as the thread assoicated with the object
+ *
+ **/
+BOOL
+CThread::FromSameThread()
+{
+	ThreadId_t id = ThreadId();
+	if( ThreadIdsEqual(&id,&m_dwId) ) return TRUE;
+	return FALSE;
+}
+
+/**
+ *
+ * OnTask
+ * called when a thread is tasked using the Event
+ * member function
+ *
+ **/
+BOOL 
+CThread::OnTask( LPVOID lpvData /*data passed from thread*/ 
+					   )
+{
+    ASSERT(lpvData && m_type == ThreadTypeHomogeneous);
+
+	if( m_type != ThreadTypeHomogeneous )
+	{
+		cerr << "Warning CThread::OnTask:\n\tOnTask(LPVOID) called for a non-homogeneous thread!\n";
+		return FALSE;
+	}
+
+	((CTask *)lpvData)->SetTaskStatus(TaskStatusBeingProcessed);
+	BOOL bReturn = ((CTask *)lpvData)->Task();
+	((CTask *)lpvData)->SetTaskStatus(TaskStatusCompleted);
+
+	return bReturn; 
+} 
+
+
+
+/**
+ *
+ * OnTask
+ * overloaded implementation of OnTask that
+ * takes no arguments
+ *
+ **/
+BOOL
+CThread::OnTask()
+{
+	ASSERT(m_type == ThreadTypeIntervalDriven);
+	if( m_type != ThreadTypeIntervalDriven )
+	{
+		cerr << "Warning CThread::OnTask:\n\tOnTask() called for a non-event driven thread!\n";
+		return FALSE;
+	}
+
+	printf("\nthread is alive\n");
+
+	return TRUE;
+}
+
+/**
+ *
+ * CEvent
+ * used to place tasks on the threads event queue
+ * wakes up thread.
+ *
+ **/
+BOOL
+CThread::Event(CTask *pvTask /* data to be processed by thread */
+			   )
+{
+	m_mutex.Lock();
+
+	ASSERT(m_type == ThreadTypeHomogeneous ||
+	       m_type == ThreadTypeNotDefined );
+
+	try 
+	{
+		if( FromSameThread() )
+		{
+			throw "\n\tit is illegal for a thread to place an event on its own event stack!\n";
+		}
+
+
+		// make sure that the thread is running 
+		if( !m_bRunning && m_dwObjectCondition == NO_ERRORS )
+		{
+			m_mutex.Unlock();
+			PingThread(m_dwIdle*2); // wait two idle cycles for it to start
+			m_mutex.Lock();
+		}
+		if( !m_bRunning ) // if it is not running return FALSE;
+		{
+			m_mutex.Unlock();
+			return FALSE;
+		}
+
+
+		if( m_dwObjectCondition & ILLEGAL_USE_OF_EVENT )
+			m_dwObjectCondition = m_dwObjectCondition ^ ILLEGAL_USE_OF_EVENT;
+		if( m_dwObjectCondition & EVENT_AND_TYPE_DONT_MATCH)
+			m_dwObjectCondition = m_dwObjectCondition ^ EVENT_AND_TYPE_DONT_MATCH;
+
+		if( m_type != ThreadTypeHomogeneous &&
+			m_type != ThreadTypeNotDefined    )
+		{
+			m_mutex.Unlock();
+			m_dwObjectCondition |= ILLEGAL_USE_OF_EVENT;
+			m_dwObjectCondition |= EVENT_AND_TYPE_DONT_MATCH;
+			m_state = ThreadStateFault;
+			cerr << "Warning: invalid call to CEvent::Event(CTask *), thread type is not specialized\n";
+
+			return FALSE;
+		}
+
+		m_type = ThreadTypeHomogeneous;
+		m_mutex.Unlock();
+
+		pvTask->SetId(&m_dwId);
+		if( ! Push((LPVOID)pvTask) )
+			return FALSE;
+
+		pvTask->SetTaskStatus(TaskStatusWaitingOnQueue);
+		m_event.Set();
+
+	}
+	catch (char *psz)
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::CEvent",MB_ICONHAND);
+		exit(-1);
+#else
+		cerr << "Fatal exception CThread::CEvent(CTask *pvTask):" << psz;
+#endif
+
+	}
+	return TRUE;
+}
+
+/**
+ *
+ * Event
+ * used to place tasks on the threads event queue
+ * wakes up thread.
+ *
+ **/
+BOOL
+CThread::Event(LPVOID lpvData /* data to be processed by thread */
+			   )
+{
+
+	m_mutex.Lock();
+	ASSERT( m_type == ThreadTypeSpecialized ||
+		    m_type == ThreadTypeNotDefined );
+	try 
+	{
+		if( FromSameThread() )
+		{
+			throw "\n\tit is illegal for a thread to place an event on its own event stack!\n";
+		}
+	}
+	catch (char *psz)
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::CEvent",MB_ICONHAND);
+		exit(-1);
+#else
+		cerr << "Fatal exception CThread::CEvent(LPVOID lpvData):" << psz;
+#endif
+
+	}
+
+	// make sure that the thread is running 
+	if( !m_bRunning && m_dwObjectCondition == NO_ERRORS )
+	{
+		m_mutex.Unlock();
+		  PingThread(m_dwIdle*2); // wait two idle cycles for it to start
+		m_mutex.Lock();
+	}
+	if( !m_bRunning ) // if it is not running return FALSE;
+	{
+		m_mutex.Unlock();
+		return FALSE;
+	}
+
+	if( m_dwObjectCondition & ILLEGAL_USE_OF_EVENT )
+		m_dwObjectCondition = m_dwObjectCondition ^ ILLEGAL_USE_OF_EVENT;
+	if( m_dwObjectCondition & EVENT_AND_TYPE_DONT_MATCH)
+		m_dwObjectCondition = m_dwObjectCondition ^ EVENT_AND_TYPE_DONT_MATCH;
+
+	if( m_type != ThreadTypeSpecialized && 
+		m_type != ThreadTypeNotDefined )
+	{
+		m_dwObjectCondition |= ILLEGAL_USE_OF_EVENT;
+		m_dwObjectCondition |= EVENT_AND_TYPE_DONT_MATCH;
+		cerr << "Warning: invalid call to CEvent::Event(LPVOID), thread type is not specialized\n";
+		m_mutex.Unlock();
+		return FALSE;
+	}
+	m_type = ThreadTypeSpecialized;
+
+	m_mutex.Unlock();
+	if( ! Push(lpvData) )
+	{
+		return FALSE;
+	}
+
+	m_event.Set();
+
+	return TRUE;
+}
+
+
+/**
+ *
+ * SetPriority
+ * sets a threads run priority, see SetThreadPriority
+ * Note: only works for Windows family of operating systems
+ *
+ *
+ **/
+void
+CThread::SetPriority(DWORD dwPriority)
+{
+
+#ifdef WINDOWS
+	SetThreadPriority(m_thread,dwPriority);
+#endif
+}
+
+	  
+/**
+ *
+ * KernelProcess
+ * routes thread activity
+ *
+ **/
+BOOL
+CThread::KernelProcess()
+{
+
+	m_mutex.Lock();
+	m_state = ThreadStateBusy;
+	if( !m_bRunning )
+	{
+		m_state = ThreadStateShuttingDown;
+		m_mutex.Unlock();
+		return FALSE;
+	}
+	m_mutex.Unlock();
+
+	if( !Empty() )
+	{
+		while( !Empty() )
+		{
+			Pop();
+			if( !OnTask(m_lpvProcessor) )
+			{
+				m_mutex.Lock();
+				m_lpvProcessor = NULL;
+				m_state = ThreadStateShuttingDown;
+				m_mutex.Unlock();
+				return FALSE;
+			}
+		}
+		m_mutex.Lock();
+		m_lpvProcessor = NULL;
+		m_state = ThreadStateWaiting;
+	}
+	else {
+		if( !OnTask() )
+		{
+			m_mutex.Lock();
+			m_state = ThreadStateShuttingDown;
+			m_mutex.Unlock();
+			return FALSE;
+		}
+		m_mutex.Lock();
+		m_state = ThreadStateWaiting;
+	}
+
+	m_mutex.Unlock();
+
+	return TRUE;
+}
+
+
+/**
+ * 
+ * GetEventsPending
+ * returns the total number of vents waiting
+ * in the event que
+ * 
+ **/
+unsigned int
+CThread::GetEventsPending()
+{
+	unsigned int chEventsWaiting;
+
+	m_mutex.Lock();
+	  chEventsWaiting = m_queuePos;
+    m_mutex.Unlock();
+
+	return chEventsWaiting;
+}
+
+
+/**
+ *
+ * CThread
+ * instanciates thread object and
+ * starts thread.
+ *
+ **/
+CThread::CThread(void)
+:m_bRunning(FALSE)
+#ifdef WINDOWS
+,m_thread(NULL)
+#endif
+,m_dwId(0L)
+,m_state(ThreadStateDown)
+,m_dwIdle(100)
+,m_lppvQueue(NULL)
+,m_lpvProcessor(NULL)
+,m_chQueue(QUEUE_SIZE)
+,m_type(ThreadTypeNotDefined)
+,m_stackSize(DEFAULT_STACK_SIZE)
+,m_queuePos(0)
+,m_StopTimeout(30)
+{
+
+	m_dwObjectCondition = NO_ERRORS;
+
+	m_lppvQueue = new LPVOID [QUEUE_SIZE];
+
+	if( !m_lppvQueue ) 
+	{
+		m_dwObjectCondition |= MEMORY_FAULT;
+		m_state = ThreadStateFault;
+		return;
+	}
+
+	if( !m_mutex.m_bCreated )
+	{
+		perror("mutex creation failed");
+		m_dwObjectCondition |= MUTEX_CREATION;
+		m_state = ThreadStateFault;
+		return;
+	}
+
+
+	if( !m_event.m_bCreated )
+	{
+		perror("event creation failed");
+		m_dwObjectCondition |= EVENT_CREATION;
+		m_state = ThreadStateFault;
+		return;
+	}
+
+
+	Start();
+
+}
+
+
+/**
+ *
+ * PercentCapacity
+ * returns a floating point value identifying
+ * the current workload of the thread
+ *
+ **/
+float
+CThread::PercentCapacity()
+{
+	float fValue = 0;
+	m_mutex.Lock();
+		fValue = (float)m_queuePos/m_chQueue;
+	m_mutex.Unlock();
+	return fValue;
+}
+
+/**
+ *
+ * SetQueueSize
+ * changes the threads queue size
+ *
+ **/
+BOOL
+CThread::SetQueueSize( unsigned int ch )
+{
+	LPVOID * newQueue = NULL;
+
+	m_mutex.Lock();
+	    ASSERT(ch > m_queuePos);
+
+	    if( ch <= m_queuePos )
+		{
+			cerr << "Warning CThread::SetQueueSize:\n\tthe new queue size is less than the number of tasks on a non-empty queue! Request ignored.\n";
+			m_mutex.Unlock();
+			return FALSE;
+		}
+
+		newQueue = new LPVOID [ch];
+		if(  !newQueue )
+		{
+			cerr << "Warning CThread::SetQueueSize:\n\ta low memory, could not reallocate queue!\n";
+			m_mutex.Unlock();
+			return FALSE;
+		}
+
+		for( unsigned int i=0;i<m_queuePos; i++ )
+		{
+			newQueue[i] = m_lppvQueue[i];
+		}
+
+		delete [] m_lppvQueue;
+
+		m_chQueue = ch;
+		m_lppvQueue = newQueue;
+
+	m_mutex.Unlock();
+
+	return TRUE;
+}
+
+
+
+/**
+ *
+ * Empty
+ * returns a value of TRUE if there are no items on the threads que
+ * otherwise a value of FALSE is returned.
+ *
+ **/
+BOOL
+CThread::Empty()
+{
+	m_mutex.Lock();
+	if( m_queuePos <= 0 )
+	{
+		m_mutex.Unlock();
+		return TRUE;
+	}
+	m_mutex.Unlock();
+	return FALSE;
+}
+
+
+
+/**
+ *
+ * Push
+ * place a data object in the threads que
+ *
+ **/
+BOOL
+CThread::Push( LPVOID lpv )
+{
+	if( !lpv ) return TRUE;
+
+	m_mutex.Lock();
+
+	if( m_queuePos+1 >= m_chQueue ) {
+		m_dwObjectCondition |= STACK_OVERFLOW;
+		m_mutex.Unlock();
+		return FALSE;
+	}
+	if( m_dwObjectCondition & STACK_EMPTY    )
+		m_dwObjectCondition = m_dwObjectCondition ^ STACK_EMPTY;
+
+	if( m_dwObjectCondition & STACK_OVERFLOW ) 
+		m_dwObjectCondition = m_dwObjectCondition ^ STACK_OVERFLOW;
+
+	m_lppvQueue[m_queuePos++] = lpv;
+	if( m_queuePos+1 >= m_chQueue )
+		m_dwObjectCondition |= STACK_FULL;
+
+	m_mutex.Unlock();
+	return TRUE;
+}
+
+
+/**
+ *
+ * Pop
+ * move an object from the input que to the processor
+ *
+ **/
+BOOL
+CThread::Pop()
+{
+
+	m_mutex.Lock();
+	if( m_queuePos-1 < 0 )
+	{
+		m_queuePos = 0;
+		m_dwObjectCondition |= STACK_EMPTY;
+		m_mutex.Unlock();
+		return FALSE;
+	}
+	if( m_dwObjectCondition & STACK_EMPTY )
+		m_dwObjectCondition = m_dwObjectCondition ^ STACK_EMPTY;
+	if( m_dwObjectCondition & STACK_OVERFLOW )
+		m_dwObjectCondition = m_dwObjectCondition ^ STACK_OVERFLOW;
+	if( m_dwObjectCondition & STACK_FULL )
+		m_dwObjectCondition = m_dwObjectCondition ^ STACK_FULL;
+
+	m_queuePos--;
+	m_lpvProcessor = m_lppvQueue[m_queuePos];
+	m_mutex.Unlock();
+	return TRUE;
+}
+
+
+/**
+ *
+ * SetThreadType
+ * specifies the type of threading that is to be performed.
+ *
+ * ThreadTypeEventDriven (default): an event must be physically sent
+ *									to the thread using the Event member
+ *									function.
+ *
+ * ThreadTypeIntervalDriven       : an event occurs automatically every 
+ *                                  dwIdle milli seconds.
+ *
+ **/
+void
+CThread::SetThreadType(ThreadType_t typ,
+              DWORD dwIdle)
+{
+
+	try 
+	{
+		if( FromSameThread() )
+		{
+			throw "\n\tit is illegal for a thread to change its own type!\n";
+		}
+
+
+		m_mutex.Lock();
+		m_dwIdle = dwIdle;
+
+
+		if( m_type == typ ) {
+			m_mutex.Unlock();
+			return;
+		}
+		if( m_dwObjectCondition & ILLEGAL_USE_OF_EVENT )
+			m_dwObjectCondition = m_dwObjectCondition ^ ILLEGAL_USE_OF_EVENT;
+		if( m_dwObjectCondition & EVENT_AND_TYPE_DONT_MATCH )
+			m_dwObjectCondition = m_dwObjectCondition ^ EVENT_AND_TYPE_DONT_MATCH;
+
+		m_type = typ;
+
+
+		m_mutex.Unlock();
+		m_event.Set();
+	}
+	catch (char *psz)
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::SetThreadType",MB_ICONHAND);
+		exit(-1);
+#else
+		cerr << "Fatal exception CThread::SetThreadType(ThreadType_t typ):" << psz;
+#endif
+
+	}
+}
+
+
+/**
+ *
+ * Stop
+ * stop thread 
+ *
+ **/
+BOOL
+CThread::Stop()
+{
+	try 
+	{
+		if( FromSameThread() )
+		{
+			throw "\n\tit is illegal for a thread to attempt to signal itself to stop!\n";
+		}
+
+		m_mutex.Lock();
+		m_bRunning = FALSE;
+		m_mutex.Unlock();
+		m_event.Set();
+
+		int ticks = (m_StopTimeout*1000)/100;
+
+		for( int i=0; i<ticks; i++ )
+		{
+			Sleep(100);
+
+			m_mutex.Lock();
+			if( m_state == ThreadStateDown )
+			{
+				m_mutex.Unlock();
+				return TRUE;
+			}
+			m_mutex.Unlock();
+
+		} 
+	}
+	catch (char *psz)
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::Stop",MB_ICONHAND);
+		exit(-1);
+#else
+		cerr << "Fatal exception CThread::Stop():" << psz;
+#endif
+
+	}
+	return FALSE;
+}
+
+
+/**
+ *
+ * SetIdle
+ * changes the threads idle interval
+ *
+ **/
+void
+CThread::SetIdle(DWORD dwIdle)
+{
+	m_mutex.Lock();
+		m_dwIdle = dwIdle;
+	m_mutex.Unlock();
+}
+
+/**
+ *
+ * Start
+ * start thread
+ *
+ **/
+BOOL
+CThread::Start()
+{
+	try 
+	{
+		if( FromSameThread() )
+		{
+			throw "\n\tit is illegal for a thread to attempt to start itself!\n";
+		}
+
+
+		m_mutex.Lock();
+		if( m_bRunning ) 
+		{
+			m_mutex.Unlock();
+			return TRUE;
+		}
+
+		m_mutex.Unlock();
+
+
+		if( m_dwObjectCondition & THREAD_CREATION )
+			m_dwObjectCondition = m_dwObjectCondition ^ THREAD_CREATION;
+
+#ifdef WINDOWS
+		if( m_thread ) CloseHandle(m_thread);
+#ifdef USE_BEGIN_THREAD
+		m_thread = (HANDLE )_beginthreadex(NULL,(unsigned int)m_stackSize,_THKERNEL,(LPVOID)this,0,&m_dwId);
+#else
+		m_thread = CreateThread(NULL,m_stackSize ,_THKERNEL,(LPVOID)this,0,&m_dwId);
+#endif
+		if( !m_thread )
+		{
+			perror("thread creation failed");
+			m_dwObjectCondition |= THREAD_CREATION;
+			m_state = ThreadStateFault;
+			return FALSE;
+		}
+#else
+		pthread_attr_t attr;
+
+		pthread_attr_init(&attr);
+
+#ifdef VMS
+		if( m_stackSize == 0 )
+			pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN*10);
+#endif
+		if( m_stackSize != 0 )
+			pthread_attr_setstacksize(&attr,m_stackSize);
+
+		int error = pthread_create(&m_thread,&attr,_THKERNEL,(LPVOID)this);
+
+		if( error != 0 )
+		{
+			m_dwObjectCondition |= THREAD_CREATION;
+			m_state = ThreadStateFault;
+
+#if defined(HPUX) || defined(SUNOS) || defined(LINUX)
+			switch(error)/* show the thread error */
+			{
+
+			case EINVAL:
+				cerr << "error: attr in an invalid thread attributes object\n";
+				break;
+			case EAGAIN:
+				cerr << "error: the necessary resources to create a thread are not\n";
+				cerr << "available.\n";
+				break;
+			case EPERM:
+				cerr << "error: the caller does not have the privileges to create\n";
+				cerr << "the thread with the specified attr object.\n";
+				break;
+#if defined(HPUX)
+			case ENOSYS:
+
+				cerr << "error: pthread_create not implemented!\n";
+				if( __is_threadlib_linked()==0 )
+				{
+					cerr << "error: threaded library not being used, improper linkage \"-lpthread -lc\"!\n";
+				}
+				break;
+#endif
+			default:
+				cerr << "error: an unknown error was encountered attempting to create\n";
+				cerr << "the requested thread.\n";
+				break;
+			}
+#else
+			cerr << "error: could not create thread, pthread_create failed (" << error << ")!\n";
+#endif
+			return FALSE;	
+		}
+#endif
+	}
+	catch (char *psz)
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::Start",MB_ICONHAND);
+#else
+		cerr << "Fatal exception CThread::Start():" << psz;
+#endif
+		exit(-1);
+	}
+	return TRUE;
+}
+
+/**
+ *
+ * AtCapacity
+ * returns TRUE if the threads queue is full, and the thread
+ * is busy processing an event or the thread is not running
+ *
+ **/
+BOOL
+CThread::AtCapacity()
+{
+	m_mutex.Lock();
+		if( ((m_dwObjectCondition & STACK_OVERFLOW ||
+			  m_dwObjectCondition & STACK_FULL ) &&
+			  m_state == ThreadStateBusy) || !m_bRunning)
+		{
+			m_mutex.Unlock();
+			return TRUE;
+		}
+	m_mutex.Unlock();
+	return FALSE;
+}
+
+/**
+ *
+ * ThreadState
+ * return the current state of the thread
+ *
+ **/
+ThreadState_t 
+CThread::ThreadState()
+{
+	ThreadState_t currentState;
+	m_mutex.Lock();
+		currentState = m_state;
+	m_mutex.Unlock();
+	return currentState;
+}
+
+/**
+ *
+ * ~CThread
+ * destructor.  Stop should be called prior to destruction to
+ * allow for gracefull thread termination.
+ *
+ **/
+CThread::~CThread(void)
+{
+	if( m_bRunning ) // gracefull termination
+	{
+		try 
+		{
+			if( !Stop() )
+			{
+				throw "\n\tthread failed to stop in a timely manner!\n";
+			}
+		}
+		catch( char *psz )
+		{
+#ifdef WINDOWS
+		    MessageBoxA(NULL,&psz[2],"Fatal exception CThread::Stop",MB_ICONHAND);
+		    exit(-1);
+#else
+			cerr << "Fatal exception CThread::Stop: " << psz;
+#endif
+		}
+	}
+#ifdef WINDOWS
+	CloseHandle(m_thread);
+#endif
+
+	delete [] m_lppvQueue;
+}
+
+
+/**
+ *
+ * PingThread
+ * used to determine if a thread is running
+ *
+ **/
+BOOL
+CThread::PingThread(DWORD dwTimeout /* timeout in milli-seconds */
+				 )
+{
+    DWORD dwTotal = 0;
+
+	while(TRUE)
+	{
+		if( dwTotal > dwTimeout && dwTimeout > 0 )
+			return FALSE;
+		m_mutex.Lock();
+			if( m_bRunning )
+			{
+				m_mutex.Unlock();
+				return TRUE;
+			}
+		dwTotal += m_dwIdle;
+		m_mutex.Unlock();
+		Sleep(m_dwIdle);
+	}
+
+	return FALSE;
+}
+
+/**
+ *
+ * WaitTillExit
+ * blocks caller until thread exits
+ *
+ **/
+void
+CThread::WaitTillExit()
+{
+
+	/*
+	 *
+	 * prevent users from calling this function from within the same thread
+	 * of execution
+	 *
+	 */
+	try 
+	{
+		if( FromSameThread() )
+			throw "\n\tthis function can not be called from within the same thread!\n";
+
+
+
+
+		if( !m_bRunning ) return;
+
+
+#ifdef WINDOWS
+		WaitForSingleObject(m_thread,INFINITE);
+#else
+		LPVOID lpv;
+
+		pthread_join(m_thread,&lpv);
+#endif
+	}
+	catch( char *psz )
+	{
+#ifdef WINDOWS
+		MessageBoxA(NULL,&psz[2],"Fatal exception CThread::WaitTillExit",MB_ICONHAND);
+		exit(-1);
+#else
+		cerr << "Fatal exception CThread::WaitTillExit: " << psz;
+#endif
+
+	}
+}
+
+
+
+