| 
									
										
										
										
											2009-07-28 21:32:10 +00:00
										 |  |  | // Copyright (C) 2003 Dolphin Project.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, version 2.0.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU General Public License 2.0 for more details.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A copy of the GPL 2.0 should have been included with the program.
 | 
					
						
							|  |  |  | // If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Official SVN repository and contact information can be found at
 | 
					
						
							|  |  |  | // http://code.google.com/p/dolphin-emu/
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-22 21:16:12 +00:00
										 |  |  | #include "Setup.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #include "Thread.h"
 | 
					
						
							| 
									
										
										
										
											2009-08-06 06:18:22 +00:00
										 |  |  | #include "Common.h"
 | 
					
						
							| 
									
										
										
										
											2009-07-10 20:22:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef USE_BEGINTHREADEX
 | 
					
						
							|  |  |  | #include <process.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | namespace Common | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	int Thread::CurrentId() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2009-09-07 12:40:43 +00:00
										 |  |  | 		return GetCurrentThreadId(); | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2009-09-07 12:40:43 +00:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	CriticalSection::CriticalSection(int spincount) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (spincount) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (!InitializeCriticalSectionAndSpinCount(§ion, spincount)) | 
					
						
							|  |  |  | 				ERROR_LOG(COMMON, "CriticalSection could not be initialized!\n%s", GetLastErrorMsg()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			InitializeCriticalSection(§ion); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	CriticalSection::~CriticalSection() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		DeleteCriticalSection(§ion); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	void CriticalSection::Enter() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		EnterCriticalSection(§ion); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	bool CriticalSection::TryEnter() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return TryEnterCriticalSection(§ion) ? true : false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void CriticalSection::Leave() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		LeaveCriticalSection(§ion); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Thread::Thread(ThreadFunc function, void* arg) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	: m_hThread(NULL), m_threadId(0) | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-07-10 20:22:25 +00:00
										 |  |  | #ifdef USE_BEGINTHREADEX
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		m_hThread = (HANDLE)_beginthreadex(NULL, 0, function, arg, 0, &m_threadId); | 
					
						
							| 
									
										
										
										
											2009-07-10 20:22:25 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		m_hThread = CreateThread(NULL, 0, function, arg, 0, &m_threadId); | 
					
						
							| 
									
										
										
										
											2009-07-10 20:22:25 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Thread::~Thread() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		WaitForDeath(); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	DWORD Thread::WaitForDeath(const int iWait) | 
					
						
							| 
									
										
										
										
											2010-01-14 10:52:14 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		if (m_hThread) | 
					
						
							| 
									
										
										
										
											2010-01-14 10:52:14 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			DWORD Wait = WaitForSingleObject(m_hThread, iWait); | 
					
						
							|  |  |  | 			CloseHandle(m_hThread); | 
					
						
							|  |  |  | 			m_hThread = NULL; | 
					
						
							|  |  |  | 			return Wait; | 
					
						
							| 
									
										
										
										
											2010-01-14 10:52:14 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2010-01-14 10:52:14 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	void Thread::SetAffinity(int mask) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SetThreadAffinityMask(m_hThread, mask); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Thread::SetPriority(int priority) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SetThreadPriority(m_hThread, priority); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Thread::SetCurrentThreadAffinity(int mask) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SetThreadAffinityMask(GetCurrentThread(), mask); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	bool Thread::IsCurrentThread() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return GetCurrentThreadId() == m_threadId; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	EventEx::EventEx() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		InterlockedExchange(&m_Lock, 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void EventEx::Init() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		InterlockedExchange(&m_Lock, 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void EventEx::Shutdown() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		InterlockedExchange(&m_Lock, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void EventEx::Set() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		InterlockedExchange(&m_Lock, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void EventEx::Spin() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		while (InterlockedCompareExchange(&m_Lock, 1, 0)) | 
					
						
							|  |  |  | 			// This only yields when there is a runnable thread on this core
 | 
					
						
							|  |  |  | 			// If not, spin
 | 
					
						
							|  |  |  | 			SwitchToThread(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void EventEx::Wait() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		while (InterlockedCompareExchange(&m_Lock, 1, 0)) | 
					
						
							|  |  |  | 			// This directly enters Ring0 and enforces a sleep about 15ms
 | 
					
						
							|  |  |  | 			SleepCurrentThread(1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	bool EventEx::MsgWait() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		while (InterlockedCompareExchange(&m_Lock, 1, 0)) | 
					
						
							| 
									
										
										
										
											2009-02-22 22:49:42 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			MSG msg; | 
					
						
							|  |  |  | 			while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (msg.message == WM_QUIT) return false; | 
					
						
							|  |  |  | 				TranslateMessage(&msg); | 
					
						
							|  |  |  | 				DispatchMessage(&msg); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// This directly enters Ring0 and enforces a sleep about 15ms
 | 
					
						
							|  |  |  | 			SleepCurrentThread(1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// Regular same thread loop based waiting
 | 
					
						
							|  |  |  | 	Event::Event() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_hEvent = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Init() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Shutdown() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		CloseHandle(m_hEvent); | 
					
						
							|  |  |  | 		m_hEvent = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Set() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SetEvent(m_hEvent); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	bool Event::Wait(const u32 timeout) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return WaitForSingleObject(m_hEvent, timeout) != WAIT_OBJECT_0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	inline HRESULT MsgWaitForSingleObject(HANDLE handle, DWORD timeout) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return MsgWaitForMultipleObjects(1, &handle, FALSE, timeout, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::MsgWait() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// Adapted from MSDN example http://msdn.microsoft.com/en-us/library/ms687060.aspx
 | 
					
						
							|  |  |  | 		while (true) | 
					
						
							| 
									
										
										
										
											2009-02-22 22:49:42 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			DWORD result;  | 
					
						
							|  |  |  | 			MSG msg;  | 
					
						
							|  |  |  | 			// Read all of the messages in this next loop, 
 | 
					
						
							|  |  |  | 			// removing each message as we read it.
 | 
					
						
							|  |  |  | 			while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))  | 
					
						
							|  |  |  | 			{  | 
					
						
							|  |  |  | 				// If it is a quit message, exit.
 | 
					
						
							|  |  |  | 				if (msg.message == WM_QUIT)   | 
					
						
							|  |  |  | 					return;  | 
					
						
							|  |  |  | 				// Otherwise, dispatch the message.
 | 
					
						
							|  |  |  | 				TranslateMessage(&msg); | 
					
						
							|  |  |  | 				DispatchMessage(&msg);  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			// Wait for any message sent or posted to this queue 
 | 
					
						
							|  |  |  | 			// or for one of the passed handles be set to signaled.
 | 
					
						
							|  |  |  | 			result = MsgWaitForSingleObject(m_hEvent, THREAD_WAIT_TIMEOUT);  | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			// The result tells us the type of event we have.
 | 
					
						
							|  |  |  | 			if (result == (WAIT_OBJECT_0 + 1)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				// New messages have arrived. 
 | 
					
						
							|  |  |  | 				// Continue to the top of the always while loop to 
 | 
					
						
							|  |  |  | 				// dispatch them and resume waiting.
 | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			}  | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				// result == WAIT_OBJECT_0
 | 
					
						
							|  |  |  | 				// Our event got signaled
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-02-22 22:49:42 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-16 14:22:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	// Supporting functions
 | 
					
						
							|  |  |  | 	void SleepCurrentThread(int ms) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		Sleep(ms); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-06-16 14:22:17 +00:00
										 |  |  | 	void SwitchCurrentThread() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		SwitchToThread(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	typedef struct tagTHREADNAME_INFO | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		DWORD dwType; // must be 0x1000
 | 
					
						
							|  |  |  | 		LPCSTR szName; // pointer to name (in user addr space)
 | 
					
						
							|  |  |  | 		DWORD dwThreadID; // thread ID (-1=caller thread)
 | 
					
						
							|  |  |  | 		DWORD dwFlags; // reserved for future use, must be zero
 | 
					
						
							|  |  |  | 	} THREADNAME_INFO; | 
					
						
							|  |  |  | 	// Usage: SetThreadName (-1, "MainThread");
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Sets the debugger-visible name of the current thread.
 | 
					
						
							|  |  |  | 	// Uses undocumented (actually, it is now documented) trick.
 | 
					
						
							|  |  |  | 	// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// This is implemented much nicer in upcoming msvc++, see:
 | 
					
						
							|  |  |  | 	// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
 | 
					
						
							|  |  |  | 	void SetCurrentThreadName(const TCHAR* szThreadName) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		THREADNAME_INFO info; | 
					
						
							|  |  |  | 		info.dwType = 0x1000; | 
					
						
							|  |  |  | #ifdef UNICODE
 | 
					
						
							|  |  |  | 		//TODO: Find the proper way to do this.
 | 
					
						
							|  |  |  | 		char tname[256]; | 
					
						
							|  |  |  | 		unsigned int i; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		for (i = 0; i < _tcslen(szThreadName); i++) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		tname[i] = 0; | 
					
						
							|  |  |  | 		info.szName = tname; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		info.szName = szThreadName; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		info.dwThreadID = -1; //dwThreadID;
 | 
					
						
							|  |  |  | 		info.dwFlags = 0; | 
					
						
							|  |  |  | 		__try | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		__except(EXCEPTION_CONTINUE_EXECUTION) | 
					
						
							|  |  |  | 		{} | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-01-09 12:10:02 +00:00
										 |  |  | #else // !WIN32, so must be POSIX threads
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 	static pthread_key_t threadname_key; | 
					
						
							|  |  |  | 	static pthread_once_t threadname_key_once = PTHREAD_ONCE_INIT; | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	CriticalSection::CriticalSection(int spincount_unused) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		pthread_mutex_init(&mutex, NULL); | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	CriticalSection::~CriticalSection() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		pthread_mutex_destroy(&mutex); | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	void CriticalSection::Enter() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		int ret = pthread_mutex_lock(&mutex); | 
					
						
							|  |  |  | 		if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_lock(%p) failed: %s\n",  | 
					
						
							|  |  |  | 						   __FUNCTION__, &mutex, strerror(ret)); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	bool CriticalSection::TryEnter() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		return(!pthread_mutex_trylock(&mutex)); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void CriticalSection::Leave() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		int ret = pthread_mutex_unlock(&mutex); | 
					
						
							|  |  |  | 		if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_unlock(%p) failed: %s\n",  | 
					
						
							|  |  |  | 						   __FUNCTION__, &mutex, strerror(ret)); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-01-09 12:10:02 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	Thread::Thread(ThreadFunc function, void* arg) | 
					
						
							|  |  |  | 	: thread_id(0) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		pthread_attr_t attr; | 
					
						
							|  |  |  | 		pthread_attr_init(&attr); | 
					
						
							|  |  |  | 		pthread_attr_setstacksize(&attr, 1024 * 1024); | 
					
						
							|  |  |  | 		int ret = pthread_create(&thread_id, &attr, function, arg); | 
					
						
							|  |  |  | 		if (ret) ERROR_LOG(COMMON, "%s: pthread_create(%p, %p, %p, %p) failed: %s\n",  | 
					
						
							|  |  |  | 						   __FUNCTION__, &thread_id, &attr, function, arg, strerror(ret)); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		INFO_LOG(COMMON, "created new thread %lu (func=%p, arg=%p)\n", thread_id, function, arg); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Thread::~Thread() | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		WaitForDeath(); | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	void Thread::WaitForDeath() | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		if (thread_id) | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			void* exit_status; | 
					
						
							|  |  |  | 			int ret = pthread_join(thread_id, &exit_status); | 
					
						
							|  |  |  | 			if (ret) ERROR_LOG(COMMON, "error joining thread %lu: %s\n", thread_id, strerror(ret)); | 
					
						
							|  |  |  | 			if (exit_status) | 
					
						
							|  |  |  | 				ERROR_LOG(COMMON, "thread %lu exited with status %d\n", thread_id, *(int *)exit_status); | 
					
						
							|  |  |  | 			thread_id = 0; | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Thread::SetAffinity(int mask) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// This is non-standard
 | 
					
						
							|  |  |  | #ifdef __linux__
 | 
					
						
							|  |  |  | 		cpu_set_t cpu_set; | 
					
						
							|  |  |  | 		CPU_ZERO(&cpu_set); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		for (unsigned int i = 0; i < sizeof(mask) * 8; i++) | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			if ((mask >> i) & 1){CPU_SET(i, &cpu_set);} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	void Thread::SetCurrentThreadAffinity(int mask) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | #ifdef __linux__
 | 
					
						
							|  |  |  | 		cpu_set_t cpu_set; | 
					
						
							|  |  |  | 		CPU_ZERO(&cpu_set); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		for (size_t i = 0; i < sizeof(mask) * 8; i++) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if ((mask >> i) & 1){CPU_SET(i, &cpu_set);} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	bool Thread::IsCurrentThread() | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		return pthread_equal(pthread_self(), thread_id) != 0; | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-16 14:22:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	void SleepCurrentThread(int ms) | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		usleep(1000 * ms); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-06-16 14:22:17 +00:00
										 |  |  | 	void SwitchCurrentThread() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		usleep(1000 * 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 	static void FreeThreadName(void* threadname) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		free(threadname); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static void ThreadnameKeyAlloc() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		pthread_key_create(&threadname_key, FreeThreadName); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	void SetCurrentThreadName(const TCHAR* szThreadName) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-07-06 16:16:07 +00:00
										 |  |  | 		pthread_once(&threadname_key_once, ThreadnameKeyAlloc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		void* threadname; | 
					
						
							|  |  |  | 		if ((threadname = pthread_getspecific(threadname_key)) != NULL) | 
					
						
							|  |  |  | 			free(threadname); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pthread_setspecific(threadname_key, strdup(szThreadName)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Event::Event() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		is_set_ = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Init() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		pthread_cond_init(&event_, 0); | 
					
						
							|  |  |  | 		pthread_mutex_init(&mutex_, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Shutdown() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		pthread_mutex_destroy(&mutex_); | 
					
						
							|  |  |  | 		pthread_cond_destroy(&event_); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	void Event::Set() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		pthread_mutex_lock(&mutex_); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (!is_set_) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			is_set_ = true; | 
					
						
							|  |  |  | 			pthread_cond_signal(&event_); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		pthread_mutex_unlock(&mutex_); | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	bool Event::Wait(const u32 timeout) | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		bool timedout = false; | 
					
						
							|  |  |  | 		struct timespec wait; | 
					
						
							|  |  |  | 		pthread_mutex_lock(&mutex_); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (timeout != INFINITE)  | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			struct timeval now; | 
					
						
							|  |  |  | 			gettimeofday(&now, NULL); | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			memset(&wait, 0, sizeof(wait)); | 
					
						
							|  |  |  | 			//TODO: timespec also has nanoseconds, but do we need them?
 | 
					
						
							|  |  |  | 			//as consequence, waiting is limited to seconds for now.
 | 
					
						
							|  |  |  | 			//the following just looks ridiculous, and probably fails for
 | 
					
						
							|  |  |  | 			//values 429 < ms <= 999 since it overflows the long.
 | 
					
						
							|  |  |  | 			//wait.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000);
 | 
					
						
							|  |  |  | 			wait.tv_sec = now.tv_sec + (timeout / 1000); | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		while (!is_set_ && !timedout) | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 			if (timeout == INFINITE)  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				pthread_cond_wait(&event_, &mutex_); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				timedout = pthread_cond_timedwait(&event_, &mutex_, &wait) == ETIMEDOUT; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-01-09 19:06:23 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		is_set_ = false; | 
					
						
							|  |  |  | 		pthread_mutex_unlock(&mutex_); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		return timedout; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-04-29 12:50:12 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2010-04-29 13:46:20 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } // namespace Common
 |