mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-13 01:29:11 +01:00
da088e62ad
For testing purpose only (I can't test with lots of games) because it may break some sync. Besides, I'm not satisfied with the way things are done. So just uncomment "//#define THREAD_VIDEO_WAKEUP_ONIDLE" in thread.h in order to test it. Works fine with movies, 2D and simple 3D in ZWW at least. If it's ok I'll clean up the code. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@658 8ced0084-cf51-0410-be5f-012b33b47a6e
351 lines
5.9 KiB
C++
351 lines
5.9 KiB
C++
// Copyright (C) 2003-2008 Dolphin Project.
|
|
|
|
// 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/
|
|
|
|
#include "Common.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#elif __GNUC__
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#else
|
|
#error unsupported platform
|
|
#endif
|
|
|
|
#include "Thread.h"
|
|
|
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
|
HANDLE g_hEventOnIdle=NULL;
|
|
#endif
|
|
|
|
namespace Common
|
|
{
|
|
#ifdef _WIN32
|
|
CriticalSection::CriticalSection(int spincount)
|
|
{
|
|
if (spincount)
|
|
{
|
|
InitializeCriticalSectionAndSpinCount(§ion, spincount);
|
|
}
|
|
else
|
|
{
|
|
InitializeCriticalSection(§ion);
|
|
}
|
|
}
|
|
|
|
|
|
CriticalSection::~CriticalSection()
|
|
{
|
|
DeleteCriticalSection(§ion);
|
|
}
|
|
|
|
|
|
void CriticalSection::Enter()
|
|
{
|
|
EnterCriticalSection(§ion);
|
|
}
|
|
|
|
|
|
bool CriticalSection::TryEnter()
|
|
{
|
|
return(TryEnterCriticalSection(§ion) ? true : false);
|
|
}
|
|
|
|
|
|
void CriticalSection::Leave()
|
|
{
|
|
LeaveCriticalSection(§ion);
|
|
}
|
|
|
|
|
|
Thread::Thread(ThreadFunc function, void* arg)
|
|
: m_hThread(NULL), m_threadId(0)
|
|
{
|
|
m_hThread = CreateThread(
|
|
0, // Security attributes
|
|
0, // Stack size
|
|
function,
|
|
arg,
|
|
0,
|
|
&m_threadId);
|
|
}
|
|
|
|
|
|
Thread::~Thread()
|
|
{
|
|
WaitForDeath();
|
|
}
|
|
|
|
|
|
void Thread::WaitForDeath()
|
|
{
|
|
if (m_hThread)
|
|
{
|
|
WaitForSingleObject(m_hThread, INFINITE);
|
|
CloseHandle(m_hThread);
|
|
m_hThread = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void Thread::SetAffinity(int mask)
|
|
{
|
|
SetThreadAffinityMask(m_hThread, mask);
|
|
}
|
|
|
|
|
|
void Thread::SetCurrentThreadAffinity(int mask)
|
|
{
|
|
SetThreadAffinityMask(GetCurrentThread(), mask);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
void Event::Wait()
|
|
{
|
|
WaitForSingleObject(m_hEvent, INFINITE);
|
|
}
|
|
|
|
|
|
void SleepCurrentThread(int ms)
|
|
{
|
|
Sleep(ms);
|
|
}
|
|
|
|
|
|
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
|
|
|
|
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;
|
|
#else
|
|
info.szName = szThreadName;
|
|
#endif
|
|
|
|
info.dwThreadID = -1; //dwThreadID;
|
|
info.dwFlags = 0;
|
|
__try
|
|
{
|
|
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
|
|
}
|
|
__except(EXCEPTION_CONTINUE_EXECUTION)
|
|
{}
|
|
}
|
|
|
|
|
|
#elif __GNUC__
|
|
CriticalSection::CriticalSection(int spincount_unused)
|
|
{
|
|
pthread_mutex_init(&mutex, 0);
|
|
}
|
|
|
|
|
|
CriticalSection::~CriticalSection()
|
|
{
|
|
pthread_mutex_destroy(&mutex);
|
|
}
|
|
|
|
|
|
void CriticalSection::Enter()
|
|
{
|
|
pthread_mutex_lock(&mutex);
|
|
}
|
|
|
|
|
|
bool CriticalSection::TryEnter()
|
|
{
|
|
return(!pthread_mutex_trylock(&mutex));
|
|
}
|
|
|
|
|
|
void CriticalSection::Leave()
|
|
{
|
|
pthread_mutex_unlock(&mutex);
|
|
}
|
|
|
|
|
|
Thread::Thread(ThreadFunc function, void* arg)
|
|
: thread_id(0)
|
|
{
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
pthread_attr_setstacksize(&attr, 1024 * 1024);
|
|
pthread_create(&thread_id, &attr, function, arg);
|
|
}
|
|
|
|
|
|
Thread::~Thread()
|
|
{
|
|
WaitForDeath();
|
|
}
|
|
|
|
|
|
void Thread::WaitForDeath()
|
|
{
|
|
if (thread_id)
|
|
{
|
|
void* exit_status;
|
|
pthread_join(thread_id, &exit_status);
|
|
thread_id = 0;
|
|
}
|
|
}
|
|
|
|
|
|
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++)
|
|
{
|
|
if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
|
|
}
|
|
|
|
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
|
|
#endif
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
|
|
|
|
void SleepCurrentThread(int ms)
|
|
{
|
|
usleep(1000 * ms);
|
|
}
|
|
|
|
|
|
void SetCurrentThreadName(const TCHAR* szThreadName)
|
|
{
|
|
// noop
|
|
}
|
|
|
|
|
|
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_);
|
|
}
|
|
|
|
pthread_mutex_unlock(&mutex_);
|
|
}
|
|
|
|
|
|
void Event::Wait()
|
|
{
|
|
pthread_mutex_lock(&mutex_);
|
|
|
|
while (!is_set_)
|
|
{
|
|
pthread_cond_wait(&event_, &mutex_);
|
|
}
|
|
|
|
is_set_ = false;
|
|
pthread_mutex_unlock(&mutex_);
|
|
}
|
|
#endif
|
|
|
|
|
|
} // end of namespace Common
|