Switch from Nz prefix to namespace Nz
What a huge commit Former-commit-id: 38ac5eebf70adc1180f571f6006192d28fb99897
This commit is contained in:
@@ -8,35 +8,38 @@
|
||||
#include <windows.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
LARGE_INTEGER frequency; // La fréquence ne varie pas pas au cours de l'exécution
|
||||
}
|
||||
|
||||
bool NzClockImplInitializeHighPrecision()
|
||||
{
|
||||
return QueryPerformanceFrequency(&frequency) != 0;
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMicroseconds()
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
|
||||
//HANDLE thread = GetCurrentThread();
|
||||
//DWORD oldMask = SetThreadAffinityMask(thread, 1);
|
||||
|
||||
LARGE_INTEGER time;
|
||||
QueryPerformanceCounter(&time);
|
||||
|
||||
//SetThreadAffinityMask(thread, oldMask);
|
||||
|
||||
return time.QuadPart*1000000ULL / frequency.QuadPart;
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMilliseconds()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS_VISTA
|
||||
return GetTickCount64();
|
||||
#else
|
||||
return GetTickCount();
|
||||
#endif
|
||||
namespace
|
||||
{
|
||||
LARGE_INTEGER s_frequency; // La fréquence ne varie pas pas au cours de l'exécution
|
||||
}
|
||||
|
||||
bool ClockImplInitializeHighPrecision()
|
||||
{
|
||||
return QueryPerformanceFrequency(&s_frequency) != 0;
|
||||
}
|
||||
|
||||
UInt64 ClockImplGetElapsedMicroseconds()
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
|
||||
//HANDLE thread = GetCurrentThread();
|
||||
//DWORD oldMask = SetThreadAffinityMask(thread, 1);
|
||||
|
||||
LARGE_INTEGER time;
|
||||
QueryPerformanceCounter(&time);
|
||||
|
||||
//SetThreadAffinityMask(thread, oldMask);
|
||||
|
||||
return time.QuadPart*1000000ULL / s_frequency.QuadPart;
|
||||
}
|
||||
|
||||
UInt64 ClockImplGetElapsedMilliseconds()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS_VISTA
|
||||
return GetTickCount64();
|
||||
#else
|
||||
return GetTickCount();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
bool NzClockImplInitializeHighPrecision();
|
||||
nzUInt64 NzClockImplGetMicroseconds();
|
||||
nzUInt64 NzClockImplGetMilliseconds();
|
||||
namespace Nz
|
||||
{
|
||||
bool ClockImplInitializeHighPrecision();
|
||||
UInt64 ClockImplGetElapsedMicroseconds();
|
||||
UInt64 ClockImplGetElapsedMilliseconds();
|
||||
}
|
||||
|
||||
#endif // NAZARA_CLOCKIMPL_WINDOWS_HPP
|
||||
|
||||
@@ -8,73 +8,77 @@
|
||||
#include <Nazara/Core/Win32/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzConditionVariableImpl::NzConditionVariableImpl()
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
InitializeConditionVariable(&m_cv);
|
||||
#else
|
||||
m_count = 0;
|
||||
m_events[BROADCAST] = CreateEvent(nullptr, true, false, nullptr); // manual-reset event
|
||||
m_events[SIGNAL] = CreateEvent(nullptr, false, false, nullptr); // auto-reset event
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NAZARA_CORE_WINDOWS_VISTA
|
||||
NzConditionVariableImpl::~NzConditionVariableImpl()
|
||||
{
|
||||
CloseHandle(m_events[BROADCAST]);
|
||||
CloseHandle(m_events[SIGNAL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void NzConditionVariableImpl::Signal()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[SIGNAL]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::SignalAll()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeAllConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[BROADCAST]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::Wait(NzMutexImpl* mutex)
|
||||
{
|
||||
Wait(mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool NzConditionVariableImpl::Wait(NzMutexImpl* mutex, nzUInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout);
|
||||
#else
|
||||
m_count++;
|
||||
|
||||
// It's ok to release the mutex here since Win32
|
||||
// manual-reset events maintain state when used with SetEvent.
|
||||
// This avoids the "lost wakeup" bug...
|
||||
LeaveCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
// Wait for either event to become signaled due to Signal being called or SignalAll being called.
|
||||
int result = WaitForMultipleObjects(2, m_events, false, timeout);
|
||||
|
||||
// Some thread called SignalAll
|
||||
if (--m_count == 0 && result == WAIT_OBJECT_0 + BROADCAST)
|
||||
// We're the last waiter to be notified or to stop waiting, so reset the manual event.
|
||||
ResetEvent(m_events[BROADCAST]);
|
||||
|
||||
// Reacquire the mutex.
|
||||
EnterCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
return result != WAIT_TIMEOUT;
|
||||
ConditionVariableImpl::ConditionVariableImpl()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
InitializeConditionVariable(&m_cv);
|
||||
#else
|
||||
m_count = 0;
|
||||
m_events[BROADCAST] = CreateEvent(nullptr, true, false, nullptr); // manual-reset event
|
||||
m_events[SIGNAL] = CreateEvent(nullptr, false, false, nullptr); // auto-reset event
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NAZARA_CORE_WINDOWS_VISTA
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
{
|
||||
CloseHandle(m_events[BROADCAST]);
|
||||
CloseHandle(m_events[SIGNAL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[SIGNAL]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::SignalAll()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeAllConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[BROADCAST]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Wait(MutexImpl* mutex)
|
||||
{
|
||||
Wait(mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::Wait(MutexImpl* mutex, UInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout);
|
||||
#else
|
||||
m_count++;
|
||||
|
||||
// It's ok to release the mutex here since Win32
|
||||
// manual-reset events maintain state when used with SetEvent.
|
||||
// This avoids the "lost wakeup" bug...
|
||||
LeaveCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
// Wait for either event to become signaled due to Signal being called or SignalAll being called.
|
||||
int result = WaitForMultipleObjects(2, m_events, false, timeout);
|
||||
|
||||
// Some thread called SignalAll
|
||||
if (--m_count == 0 && result == WAIT_OBJECT_0 + BROADCAST)
|
||||
// We're the last waiter to be notified or to stop waiting, so reset the manual event.
|
||||
ResetEvent(m_events[BROADCAST]);
|
||||
|
||||
// Reacquire the mutex.
|
||||
EnterCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
return result != WAIT_TIMEOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,39 +13,41 @@
|
||||
#include <atomic>
|
||||
#include <windows.h>
|
||||
|
||||
class NzMutexImpl;
|
||||
|
||||
class NzConditionVariableImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzConditionVariableImpl();
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
~NzConditionVariableImpl() = default;
|
||||
#else
|
||||
~NzConditionVariableImpl();
|
||||
#endif
|
||||
class MutexImpl;
|
||||
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
class ConditionVariableImpl
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
~ConditionVariableImpl() = default;
|
||||
#else
|
||||
~ConditionVariableImpl();
|
||||
#endif
|
||||
|
||||
void Wait(NzMutexImpl* mutex);
|
||||
bool Wait(NzMutexImpl* mutex, nzUInt32 timeout);
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
|
||||
private:
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
CONDITION_VARIABLE m_cv;
|
||||
#else
|
||||
enum
|
||||
{
|
||||
SIGNAL,
|
||||
BROADCAST,
|
||||
MAX_EVENTS
|
||||
};
|
||||
void Wait(MutexImpl* mutex);
|
||||
bool Wait(MutexImpl* mutex, UInt32 timeout);
|
||||
|
||||
std::atomic_uint m_count;
|
||||
HANDLE m_events[MAX_EVENTS];
|
||||
#endif
|
||||
private:
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
CONDITION_VARIABLE m_cv;
|
||||
#else
|
||||
enum
|
||||
{
|
||||
SIGNAL,
|
||||
BROADCAST,
|
||||
MAX_EVENTS
|
||||
};
|
||||
|
||||
};
|
||||
std::atomic_uint m_count;
|
||||
HANDLE m_events[MAX_EVENTS];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONDITIONVARIABLEIMPL_HPP
|
||||
|
||||
@@ -7,113 +7,116 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDirectoryImpl::NzDirectoryImpl(const NzDirectory* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzDirectoryImpl::Close()
|
||||
{
|
||||
FindClose(m_handle);
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetResultName() const
|
||||
{
|
||||
return NzString::Unicode(m_result.cFileName);
|
||||
}
|
||||
|
||||
nzUInt64 NzDirectoryImpl::GetResultSize() const
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
size.HighPart = m_result.nFileSizeHigh;
|
||||
size.LowPart = m_result.nFileSizeLow;
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
if (m_result.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (m_result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::NextResult()
|
||||
{
|
||||
if (m_firstCall) // Nous devons ignorer le premier appel car FindFirstFile nous a déjà renvoyé des résultats
|
||||
DirectoryImpl::DirectoryImpl(const Directory* parent)
|
||||
{
|
||||
m_firstCall = false;
|
||||
return true;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
if (FindNextFileW(m_handle, &m_result))
|
||||
return true;
|
||||
else
|
||||
void DirectoryImpl::Close()
|
||||
{
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
NazaraError("Unable to get next result: " + NzError::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Open(const NzString& dirPath)
|
||||
{
|
||||
NzString searchPath = dirPath + "\\*";
|
||||
|
||||
m_handle = FindFirstFileW(searchPath.GetWideString().data(), &m_result);
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
FindClose(m_handle);
|
||||
}
|
||||
|
||||
m_firstCall = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Create(const NzString& dirPath)
|
||||
{
|
||||
return (CreateDirectoryW(dirPath.GetWideString().data(), nullptr) != 0) || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Exists(const NzString& dirPath)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW(dirPath.GetWideString().data());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetCurrent()
|
||||
{
|
||||
NzString currentPath;
|
||||
std::unique_ptr<wchar_t[]> path(new wchar_t[MAX_PATH]);
|
||||
|
||||
unsigned int size = GetCurrentDirectoryW(MAX_PATH, path.get());
|
||||
if (size > MAX_PATH) // La taille prends en compte le caractère nul
|
||||
String DirectoryImpl::GetResultName() const
|
||||
{
|
||||
path.reset(new wchar_t[size]);
|
||||
if (GetCurrentDirectoryW(size, path.get()) != 0)
|
||||
currentPath = NzString::Unicode(path.get());
|
||||
return String::Unicode(m_result.cFileName);
|
||||
}
|
||||
|
||||
UInt64 DirectoryImpl::GetResultSize() const
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
size.HighPart = m_result.nFileSizeHigh;
|
||||
size.LowPart = m_result.nFileSizeLow;
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
if (m_result.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (m_result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
else if (size == 0)
|
||||
NazaraError("Unable to get current directory: " + NzError::GetLastSystemError());
|
||||
else
|
||||
currentPath = NzString::Unicode(path.get());
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Remove(const NzString& dirPath)
|
||||
{
|
||||
bool success = RemoveDirectoryW(dirPath.GetWideString().data()) != 0;
|
||||
|
||||
DWORD error = GetLastError();
|
||||
return success || error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
|
||||
bool DirectoryImpl::NextResult()
|
||||
{
|
||||
if (m_firstCall) // Nous devons ignorer le premier appel car FindFirstFile nous a déjà renvoyé des résultats
|
||||
{
|
||||
m_firstCall = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FindNextFileW(m_handle, &m_result))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
NazaraError("Unable to get next result: " + Error::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Open(const String& dirPath)
|
||||
{
|
||||
String searchPath = dirPath + "\\*";
|
||||
|
||||
m_handle = FindFirstFileW(searchPath.GetWideString().data(), &m_result);
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_firstCall = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Create(const String& dirPath)
|
||||
{
|
||||
return (CreateDirectoryW(dirPath.GetWideString().data(), nullptr) != 0) || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Exists(const String& dirPath)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW(dirPath.GetWideString().data());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
String DirectoryImpl::GetCurrent()
|
||||
{
|
||||
String currentPath;
|
||||
std::unique_ptr<wchar_t[]> path(new wchar_t[MAX_PATH]);
|
||||
|
||||
unsigned int size = GetCurrentDirectoryW(MAX_PATH, path.get());
|
||||
if (size > MAX_PATH) // La taille prends en compte le caractère nul
|
||||
{
|
||||
path.reset(new wchar_t[size]);
|
||||
if (GetCurrentDirectoryW(size, path.get()) != 0)
|
||||
currentPath = String::Unicode(path.get());
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + Error::GetLastSystemError());
|
||||
}
|
||||
else if (size == 0)
|
||||
NazaraError("Unable to get current directory: " + Error::GetLastSystemError());
|
||||
else
|
||||
currentPath = String::Unicode(path.get());
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Remove(const String& dirPath)
|
||||
{
|
||||
bool success = RemoveDirectoryW(dirPath.GetWideString().data()) != 0;
|
||||
|
||||
DWORD error = GetLastError();
|
||||
return success || error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,40 +10,43 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzDirectory;
|
||||
class NzString;
|
||||
|
||||
class NzDirectoryImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDirectoryImpl(const NzDirectory* parent);
|
||||
NzDirectoryImpl(const NzDirectoryImpl&) = delete;
|
||||
NzDirectoryImpl(NzDirectoryImpl&&) = delete; ///TODO
|
||||
~NzDirectoryImpl() = default;
|
||||
class Directory;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
class DirectoryImpl
|
||||
{
|
||||
public:
|
||||
DirectoryImpl(const Directory* parent);
|
||||
DirectoryImpl(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl(DirectoryImpl&&) = delete; ///TODO
|
||||
~DirectoryImpl() = default;
|
||||
|
||||
NzString GetResultName() const;
|
||||
nzUInt64 GetResultSize() const;
|
||||
void Close();
|
||||
|
||||
bool IsResultDirectory() const;
|
||||
String GetResultName() const;
|
||||
UInt64 GetResultSize() const;
|
||||
|
||||
bool NextResult();
|
||||
bool IsResultDirectory() const;
|
||||
|
||||
bool Open(const NzString& dirPath);
|
||||
bool NextResult();
|
||||
|
||||
NzDirectoryImpl& operator=(const NzDirectoryImpl&) = delete;
|
||||
NzDirectoryImpl& operator=(NzDirectoryImpl&&) = delete; ///TODO
|
||||
bool Open(const String& dirPath);
|
||||
|
||||
static bool Create(const NzString& dirPath);
|
||||
static bool Exists(const NzString& dirPath);
|
||||
static NzString GetCurrent();
|
||||
static bool Remove(const NzString& dirPath);
|
||||
DirectoryImpl& operator=(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl& operator=(DirectoryImpl&&) = delete; ///TODO
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
WIN32_FIND_DATAW m_result;
|
||||
bool m_firstCall;
|
||||
};
|
||||
static bool Create(const String& dirPath);
|
||||
static bool Exists(const String& dirPath);
|
||||
static String GetCurrent();
|
||||
static bool Remove(const String& dirPath);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
WIN32_FIND_DATAW m_result;
|
||||
bool m_firstCall;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DIRECTORYIMPL_HPP
|
||||
|
||||
@@ -10,37 +10,41 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDynLibImpl::NzDynLibImpl(NzDynLib* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
NzDynLibFunc NzDynLibImpl::GetSymbol(const NzString& symbol, NzString* errorMessage) const
|
||||
{
|
||||
NzDynLibFunc sym = reinterpret_cast<NzDynLibFunc>(GetProcAddress(m_handle, symbol.GetConstBuffer()));
|
||||
if (!sym)
|
||||
*errorMessage = NzError::GetLastSystemError();
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
bool NzDynLibImpl::Load(const NzString& libraryPath, NzString* errorMessage)
|
||||
{
|
||||
NzString path = libraryPath;
|
||||
if (!path.EndsWith(".dll"))
|
||||
path += ".dll";
|
||||
|
||||
m_handle = LoadLibraryExW(path.GetWideString().data(), nullptr, (NzFile::IsAbsolute(path)) ? LOAD_WITH_ALTERED_SEARCH_PATH : 0);
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
DynLibImpl::DynLibImpl(DynLib* parent)
|
||||
{
|
||||
*errorMessage = NzError::GetLastSystemError();
|
||||
return false;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
DynLibFunc DynLibImpl::GetSymbol(const String& symbol, String* errorMessage) const
|
||||
{
|
||||
DynLibFunc sym = reinterpret_cast<DynLibFunc>(GetProcAddress(m_handle, symbol.GetConstBuffer()));
|
||||
if (!sym)
|
||||
*errorMessage = Error::GetLastSystemError();
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
bool DynLibImpl::Load(const String& libraryPath, String* errorMessage)
|
||||
{
|
||||
String path = libraryPath;
|
||||
if (!path.EndsWith(".dll"))
|
||||
path += ".dll";
|
||||
|
||||
m_handle = LoadLibraryExW(path.GetWideString().data(), nullptr, (File::IsAbsolute(path)) ? LOAD_WITH_ALTERED_SEARCH_PATH : 0);
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
*errorMessage = Error::GetLastSystemError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DynLibImpl::Unload()
|
||||
{
|
||||
FreeLibrary(m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void NzDynLibImpl::Unload()
|
||||
{
|
||||
FreeLibrary(m_handle);
|
||||
}
|
||||
|
||||
@@ -11,25 +11,28 @@
|
||||
#include <Nazara/Core/DynLib.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzString;
|
||||
|
||||
class NzDynLibImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDynLibImpl(NzDynLib* m_parent);
|
||||
NzDynLibImpl(const NzDynLibImpl&) = delete;
|
||||
NzDynLibImpl(NzDynLibImpl&&) = delete; ///TODO?
|
||||
~NzDynLibImpl() = default;
|
||||
class String;
|
||||
|
||||
NzDynLibFunc GetSymbol(const NzString& symbol, NzString* errorMessage) const;
|
||||
bool Load(const NzString& libraryPath, NzString* errorMessage);
|
||||
void Unload();
|
||||
class DynLibImpl
|
||||
{
|
||||
public:
|
||||
DynLibImpl(DynLib* m_parent);
|
||||
DynLibImpl(const DynLibImpl&) = delete;
|
||||
DynLibImpl(DynLibImpl&&) = delete; ///TODO?
|
||||
~DynLibImpl() = default;
|
||||
|
||||
NzDynLibImpl& operator=(const NzDynLibImpl&) = delete;
|
||||
NzDynLibImpl& operator=(NzDynLibImpl&&) = delete; ///TODO?
|
||||
DynLibFunc GetSymbol(const String& symbol, String* errorMessage) const;
|
||||
bool Load(const String& libraryPath, String* errorMessage);
|
||||
void Unload();
|
||||
|
||||
private:
|
||||
HMODULE m_handle;
|
||||
};
|
||||
DynLibImpl& operator=(const DynLibImpl&) = delete;
|
||||
DynLibImpl& operator=(DynLibImpl&&) = delete; ///TODO?
|
||||
|
||||
private:
|
||||
HMODULE m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DYNLIBIMPL_HPP
|
||||
|
||||
@@ -8,288 +8,291 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzFileImpl::NzFileImpl(const NzFile* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzFileImpl::Close()
|
||||
{
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
bool NzFileImpl::EndOfFile() const
|
||||
{
|
||||
if (!m_endOfFileUpdated)
|
||||
FileImpl::FileImpl(const File* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
{
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(m_handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<nzUInt64>(fileSize.QuadPart));
|
||||
m_endOfFileUpdated = true;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void NzFileImpl::Flush()
|
||||
{
|
||||
if (!FlushFileBuffers(m_handle))
|
||||
NazaraError("Unable to flush file: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetCursorPos() const
|
||||
{
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
|
||||
LARGE_INTEGER position;
|
||||
SetFilePointerEx(m_handle, zero, &position, FILE_CURRENT);
|
||||
|
||||
return position.QuadPart;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Open(const NzString& filePath, unsigned int mode)
|
||||
{
|
||||
DWORD access;
|
||||
DWORD shareMode = FILE_SHARE_READ;
|
||||
DWORD openMode;
|
||||
if (mode & nzOpenMode_ReadOnly)
|
||||
void FileImpl::Close()
|
||||
{
|
||||
access = GENERIC_READ;
|
||||
openMode = OPEN_EXISTING;
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
else if (mode & nzOpenMode_ReadWrite)
|
||||
|
||||
bool FileImpl::EndOfFile() const
|
||||
{
|
||||
if (mode & nzOpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else if (mode & nzOpenMode_WriteOnly)
|
||||
{
|
||||
if (mode & nzOpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_WRITE;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if ((mode & nzOpenMode_Lock) == 0)
|
||||
shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_handle = CreateFileW(filePath.GetWideString().data(), access, shareMode, nullptr, openMode, 0, nullptr);
|
||||
return m_handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
//nzUInt64 oldCursorPos = GetCursorPos();
|
||||
|
||||
DWORD read = 0;
|
||||
if (ReadFile(m_handle, buffer, size, &read, nullptr))
|
||||
{
|
||||
m_endOfFile = (read != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return read;
|
||||
///FIXME: D'après la documentation, read vaut 0 si ReadFile atteint la fin du fichier
|
||||
/// D'après les tests, ce n'est pas le cas, la taille lue est inférieure à la taille en argument, mais pas nulle
|
||||
/// Peut-être ais-je mal compris la documentation
|
||||
/// Le correctif (dans le cas où la doc serait vraie) est commenté en début de fonction et après ce commentaire
|
||||
/// Il est cependant plus lourd, et ne fonctionne pas avec le comportement observé de la fonction
|
||||
/*
|
||||
if (read == 0)
|
||||
if (!m_endOfFileUpdated)
|
||||
{
|
||||
// Si nous atteignons la fin du fichier, la taille lue vaut 0
|
||||
// pour renvoyer le nombre d'octets lus nous comparons la position du curseur
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365690(v=vs.85).aspx
|
||||
m_endOfFile = true;
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(m_handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<UInt64>(fileSize.QuadPart));
|
||||
m_endOfFileUpdated = true;
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void FileImpl::Flush()
|
||||
{
|
||||
if (!FlushFileBuffers(m_handle))
|
||||
NazaraError("Unable to flush file: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetCursorPos() const
|
||||
{
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
|
||||
LARGE_INTEGER position;
|
||||
SetFilePointerEx(m_handle, zero, &position, FILE_CURRENT);
|
||||
|
||||
return position.QuadPart;
|
||||
}
|
||||
|
||||
bool FileImpl::Open(const String& filePath, unsigned int mode)
|
||||
{
|
||||
DWORD access;
|
||||
DWORD shareMode = FILE_SHARE_READ;
|
||||
DWORD openMode;
|
||||
if (mode & OpenMode_ReadOnly)
|
||||
{
|
||||
access = GENERIC_READ;
|
||||
openMode = OPEN_EXISTING;
|
||||
}
|
||||
else if (mode & OpenMode_ReadWrite)
|
||||
{
|
||||
if (mode & OpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
|
||||
if (mode & OpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else if (mode & OpenMode_WriteOnly)
|
||||
{
|
||||
if (mode & OpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_WRITE;
|
||||
|
||||
if (mode & OpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if ((mode & OpenMode_Lock) == 0)
|
||||
shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_handle = CreateFileW(filePath.GetWideString().data(), access, shareMode, nullptr, openMode, 0, nullptr);
|
||||
return m_handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
std::size_t FileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
//UInt64 oldCursorPos = GetCursorPos();
|
||||
|
||||
DWORD read = 0;
|
||||
if (ReadFile(m_handle, buffer, size, &read, nullptr))
|
||||
{
|
||||
m_endOfFile = (read != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return GetCursorPos()-oldCursorPos;
|
||||
return read;
|
||||
///FIXME: D'après la documentation, read vaut 0 si ReadFile atteint la fin du fichier
|
||||
/// D'après les tests, ce n'est pas le cas, la taille lue est inférieure à la taille en argument, mais pas nulle
|
||||
/// Peut-être ais-je mal compris la documentation
|
||||
/// Le correctif (dans le cas où la doc serait vraie) est commenté en début de fonction et après ce commentaire
|
||||
/// Il est cependant plus lourd, et ne fonctionne pas avec le comportement observé de la fonction
|
||||
/*
|
||||
if (read == 0)
|
||||
{
|
||||
// Si nous atteignons la fin du fichier, la taille lue vaut 0
|
||||
// pour renvoyer le nombre d'octets lus nous comparons la position du curseur
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365690(v=vs.85).aspx
|
||||
m_endOfFile = true;
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return GetCursorPos()-oldCursorPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endOfFileUpdated = false;
|
||||
return read;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset)
|
||||
{
|
||||
DWORD moveMethod;
|
||||
switch (pos)
|
||||
{
|
||||
m_endOfFileUpdated = false;
|
||||
return read;
|
||||
case CursorPosition_AtBegin:
|
||||
moveMethod = FILE_BEGIN;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtCurrent:
|
||||
moveMethod = FILE_CURRENT;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtEnd:
|
||||
moveMethod = FILE_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = offset;
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return SetFilePointerEx(m_handle, distance, nullptr, moveMethod) != 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NzFileImpl::SetCursorPos(nzCursorPosition pos, nzInt64 offset)
|
||||
{
|
||||
DWORD moveMethod;
|
||||
switch (pos)
|
||||
std::size_t FileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
case nzCursorPosition_AtBegin:
|
||||
moveMethod = FILE_BEGIN;
|
||||
break;
|
||||
DWORD written = 0;
|
||||
|
||||
case nzCursorPosition_AtCurrent:
|
||||
moveMethod = FILE_CURRENT;
|
||||
break;
|
||||
LARGE_INTEGER cursorPos;
|
||||
cursorPos.QuadPart = GetCursorPos();
|
||||
|
||||
case nzCursorPosition_AtEnd:
|
||||
moveMethod = FILE_END;
|
||||
break;
|
||||
LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
WriteFile(m_handle, buffer, size, &written, nullptr);
|
||||
UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + NzString::Number(pos, 16) + ')');
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool FileImpl::Copy(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
if (CopyFileW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), false))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to copy file: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = offset;
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return SetFilePointerEx(m_handle, distance, nullptr, moveMethod) != 0;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
DWORD written = 0;
|
||||
|
||||
LARGE_INTEGER cursorPos;
|
||||
cursorPos.QuadPart = GetCursorPos();
|
||||
|
||||
LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
WriteFile(m_handle, buffer, size, &written, nullptr);
|
||||
UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Copy(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
if (CopyFileW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), false))
|
||||
return true;
|
||||
else
|
||||
bool FileImpl::Delete(const String& filePath)
|
||||
{
|
||||
NazaraError("Failed to copy file: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
if (DeleteFileW(filePath.GetWideString().data()))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NzFileImpl::Delete(const NzString& filePath)
|
||||
{
|
||||
if (DeleteFileW(filePath.GetWideString().data()))
|
||||
return true;
|
||||
else
|
||||
bool FileImpl::Exists(const String& filePath)
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
bool NzFileImpl::Exists(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
CloseHandle(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetCreationTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME creationTime;
|
||||
if (!GetFileTime(handle, &creationTime, nullptr, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get creation time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&creationTime);
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastAccessTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME accessTime;
|
||||
if (!GetFileTime(handle, nullptr, &accessTime, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last access time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&accessTime);
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastWriteTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME writeTime;
|
||||
if (!GetFileTime(handle, nullptr, nullptr, &writeTime))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last write time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&writeTime);
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetSize(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
CloseHandle(handle);
|
||||
return fileSize.QuadPart;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Rename(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
if (MoveFileExW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), MOVEFILE_COPY_ALLOWED))
|
||||
return true;
|
||||
else
|
||||
}
|
||||
|
||||
time_t FileImpl::GetCreationTime(const String& filePath)
|
||||
{
|
||||
NazaraError("Unable to rename file: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME creationTime;
|
||||
if (!GetFileTime(handle, &creationTime, nullptr, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get creation time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&creationTime);
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastAccessTime(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME accessTime;
|
||||
if (!GetFileTime(handle, nullptr, &accessTime, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last access time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&accessTime);
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastWriteTime(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME writeTime;
|
||||
if (!GetFileTime(handle, nullptr, nullptr, &writeTime))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last write time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&writeTime);
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetSize(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
CloseHandle(handle);
|
||||
return fileSize.QuadPart;
|
||||
}
|
||||
|
||||
bool FileImpl::Rename(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
if (MoveFileExW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), MOVEFILE_COPY_ALLOWED))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Unable to rename file: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,42 +12,45 @@
|
||||
#include <ctime>
|
||||
#include <windows.h>
|
||||
|
||||
class NzFile;
|
||||
class NzString;
|
||||
|
||||
class NzFileImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzFileImpl(const NzFile* parent);
|
||||
NzFileImpl(const NzFileImpl&) = delete;
|
||||
NzFileImpl(NzFileImpl&&) = delete; ///TODO
|
||||
~NzFileImpl() = default;
|
||||
class File;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
nzUInt64 GetCursorPos() const;
|
||||
bool Open(const NzString& filePath, unsigned int mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(nzCursorPosition pos, nzInt64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
class FileImpl
|
||||
{
|
||||
public:
|
||||
FileImpl(const File* parent);
|
||||
FileImpl(const FileImpl&) = delete;
|
||||
FileImpl(FileImpl&&) = delete; ///TODO
|
||||
~FileImpl() = default;
|
||||
|
||||
NzFileImpl& operator=(const NzFileImpl&) = delete;
|
||||
NzFileImpl& operator=(NzFileImpl&&) = delete; ///TODO
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
UInt64 GetCursorPos() const;
|
||||
bool Open(const String& filePath, unsigned int mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(CursorPosition pos, Int64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
|
||||
static bool Copy(const NzString& sourcePath, const NzString& targetPath);
|
||||
static bool Delete(const NzString& filePath);
|
||||
static bool Exists(const NzString& filePath);
|
||||
static time_t GetCreationTime(const NzString& filePath);
|
||||
static time_t GetLastAccessTime(const NzString& filePath);
|
||||
static time_t GetLastWriteTime(const NzString& filePath);
|
||||
static nzUInt64 GetSize(const NzString& filePath);
|
||||
static bool Rename(const NzString& sourcePath, const NzString& targetPath);
|
||||
FileImpl& operator=(const FileImpl&) = delete;
|
||||
FileImpl& operator=(FileImpl&&) = delete; ///TODO
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
static bool Copy(const String& sourcePath, const String& targetPath);
|
||||
static bool Delete(const String& filePath);
|
||||
static bool Exists(const String& filePath);
|
||||
static time_t GetCreationTime(const String& filePath);
|
||||
static time_t GetLastAccessTime(const String& filePath);
|
||||
static time_t GetLastWriteTime(const String& filePath);
|
||||
static UInt64 GetSize(const String& filePath);
|
||||
static bool Rename(const String& sourcePath, const String& targetPath);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_FILEIMPL_HPP
|
||||
|
||||
@@ -12,86 +12,89 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
|
||||
namespace Nz
|
||||
{
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed");
|
||||
|
||||
// Visual propose une fonction intrinsèque pour le cpuid
|
||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int NzHardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
SYSTEM_INFO infos;
|
||||
GetNativeSystemInfo(&infos);
|
||||
|
||||
return infos.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
nzUInt64 NzHardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
|
||||
return memStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
bool NzHardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
int supported;
|
||||
__asm
|
||||
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
||||
{
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
xor eax, ecx
|
||||
mov supported, eax
|
||||
push ecx
|
||||
popfd
|
||||
};
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
static_assert(sizeof(UInt32) == sizeof(int), "Assertion failed");
|
||||
|
||||
return supported != 0;
|
||||
// Visual propose une fonction intrinsèque pour le cpuid
|
||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
return false;
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int HardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
SYSTEM_INFO infos;
|
||||
GetNativeSystemInfo(&infos);
|
||||
|
||||
return infos.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
UInt64 HardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
|
||||
return memStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
bool HardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
int supported;
|
||||
__asm
|
||||
{
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
xor eax, ecx
|
||||
mov supported, eax
|
||||
push ecx
|
||||
popfd
|
||||
};
|
||||
|
||||
return supported != 0;
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,16 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
class NzHardwareInfoImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static nzUInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
class HardwareInfoImpl
|
||||
{
|
||||
public:
|
||||
static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static UInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_HARDWAREINFOIMPL_WINDOWS_HPP
|
||||
|
||||
@@ -5,31 +5,34 @@
|
||||
#include <Nazara/Core/Win32/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzMutexImpl::NzMutexImpl()
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_CS_SPINLOCKS > 0
|
||||
InitializeCriticalSectionAndSpinCount(&m_criticalSection, NAZARA_CORE_WINDOWS_CS_SPINLOCKS);
|
||||
#else
|
||||
InitializeCriticalSection(&m_criticalSection);
|
||||
#endif
|
||||
}
|
||||
MutexImpl::MutexImpl()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_CS_SPINLOCKS > 0
|
||||
InitializeCriticalSectionAndSpinCount(&m_criticalSection, NAZARA_CORE_WINDOWS_CS_SPINLOCKS);
|
||||
#else
|
||||
InitializeCriticalSection(&m_criticalSection);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzMutexImpl::~NzMutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&m_criticalSection);
|
||||
}
|
||||
MutexImpl::~MutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
void NzMutexImpl::Lock()
|
||||
{
|
||||
EnterCriticalSection(&m_criticalSection);
|
||||
}
|
||||
void MutexImpl::Lock()
|
||||
{
|
||||
EnterCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
bool NzMutexImpl::TryLock()
|
||||
{
|
||||
return TryEnterCriticalSection(&m_criticalSection) != 0;
|
||||
}
|
||||
bool MutexImpl::TryLock()
|
||||
{
|
||||
return TryEnterCriticalSection(&m_criticalSection) != 0;
|
||||
}
|
||||
|
||||
void NzMutexImpl::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&m_criticalSection);
|
||||
void MutexImpl::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&m_criticalSection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,20 +10,23 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzMutexImpl
|
||||
namespace Nz
|
||||
{
|
||||
friend class NzConditionVariableImpl;
|
||||
class MutexImpl
|
||||
{
|
||||
friend class ConditionVariableImpl;
|
||||
|
||||
public:
|
||||
NzMutexImpl();
|
||||
~NzMutexImpl();
|
||||
public:
|
||||
MutexImpl();
|
||||
~MutexImpl();
|
||||
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION m_criticalSection;
|
||||
};
|
||||
private:
|
||||
CRITICAL_SECTION m_criticalSection;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_MUTEXIMPL_HPP
|
||||
|
||||
@@ -8,57 +8,60 @@
|
||||
#include <limits>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count)
|
||||
namespace Nz
|
||||
{
|
||||
m_semaphore = CreateSemaphoreW(nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
|
||||
if (!m_semaphore)
|
||||
NazaraError("Failed to create semaphore: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
NzSemaphoreImpl::~NzSemaphoreImpl()
|
||||
{
|
||||
CloseHandle(m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int NzSemaphoreImpl::GetCount() const
|
||||
{
|
||||
LONG count;
|
||||
ReleaseSemaphore(m_semaphore, 0, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!ReleaseSemaphore(m_semaphore, 1, nullptr))
|
||||
NazaraError("Failed to release semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
ReleaseSemaphore(m_semaphore, 1, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (WaitForSingleObject(m_semaphore, INFINITE) == WAIT_FAILED)
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
WaitForSingleObject(m_semaphore, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NzSemaphoreImpl::Wait(nzUInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
DWORD result = WaitForSingleObject(m_semaphore, timeout);
|
||||
if (result == WAIT_FAILED)
|
||||
SemaphoreImpl::SemaphoreImpl(unsigned int count)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
m_semaphore = CreateSemaphoreW(nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
|
||||
if (!m_semaphore)
|
||||
NazaraError("Failed to create semaphore: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
SemaphoreImpl::~SemaphoreImpl()
|
||||
{
|
||||
CloseHandle(m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int SemaphoreImpl::GetCount() const
|
||||
{
|
||||
LONG count;
|
||||
ReleaseSemaphore(m_semaphore, 0, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!ReleaseSemaphore(m_semaphore, 1, nullptr))
|
||||
NazaraError("Failed to release semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
ReleaseSemaphore(m_semaphore, 1, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (WaitForSingleObject(m_semaphore, INFINITE) == WAIT_FAILED)
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
WaitForSingleObject(m_semaphore, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SemaphoreImpl::Wait(UInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
DWORD result = WaitForSingleObject(m_semaphore, timeout);
|
||||
if (result == WAIT_FAILED)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return result == WAIT_OBJECT_0;
|
||||
#else
|
||||
return WaitForSingleObject(m_semaphore, timeout) == WAIT_OBJECT_0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return result == WAIT_OBJECT_0;
|
||||
#else
|
||||
return WaitForSingleObject(m_semaphore, timeout) == WAIT_OBJECT_0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10,19 +10,22 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzSemaphoreImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzSemaphoreImpl(unsigned int count);
|
||||
~NzSemaphoreImpl();
|
||||
class SemaphoreImpl
|
||||
{
|
||||
public:
|
||||
SemaphoreImpl(unsigned int count);
|
||||
~SemaphoreImpl();
|
||||
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(nzUInt32 timeout);
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(UInt32 timeout);
|
||||
|
||||
private:
|
||||
HANDLE m_semaphore;
|
||||
};
|
||||
private:
|
||||
HANDLE m_semaphore;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SEMAPHOREIMPL_HPP
|
||||
|
||||
@@ -9,237 +9,240 @@
|
||||
#include <process.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount)
|
||||
namespace Nz
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
bool TaskSchedulerImpl::Initialize(unsigned int workerCount)
|
||||
{
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
s_workerCount = workerCount;
|
||||
s_doneEvents.reset(new HANDLE[workerCount]);
|
||||
s_workers.reset(new Worker[workerCount]);
|
||||
s_workerThreads.reset(new HANDLE[workerCount]);
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
{
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
|
||||
std::unique_ptr<unsigned int[]> workerIDs(new unsigned int[workerCount]);
|
||||
s_workerCount = workerCount;
|
||||
s_doneEvents.reset(new HANDLE[workerCount]);
|
||||
s_workers.reset(new Worker[workerCount]);
|
||||
s_workerThreads.reset(new HANDLE[workerCount]);
|
||||
|
||||
for (unsigned int i = 0; i < workerCount; ++i)
|
||||
{
|
||||
// On initialise les évènements, mutex et threads de chaque worker
|
||||
Worker& worker = s_workers[i];
|
||||
InitializeCriticalSection(&worker.queueMutex);
|
||||
worker.wakeEvent = CreateEventW(nullptr, false, false, nullptr);
|
||||
worker.running = true;
|
||||
worker.workCount = 0;
|
||||
// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
|
||||
std::unique_ptr<unsigned int[]> workerIDs(new unsigned int[workerCount]);
|
||||
|
||||
s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);
|
||||
for (unsigned int i = 0; i < workerCount; ++i)
|
||||
{
|
||||
// On initialise les évènements, mutex et threads de chaque worker
|
||||
Worker& worker = s_workers[i];
|
||||
InitializeCriticalSection(&worker.queueMutex);
|
||||
worker.wakeEvent = CreateEventW(nullptr, false, false, nullptr);
|
||||
worker.running = true;
|
||||
worker.workCount = 0;
|
||||
|
||||
// Le thread va se lancer, signaler qu'il est prêt à travailler (s_doneEvents) et attendre d'être réveillé
|
||||
workerIDs[i] = i;
|
||||
s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
|
||||
s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);
|
||||
|
||||
// Le thread va se lancer, signaler qu'il est prêt à travailler (s_doneEvents) et attendre d'être réveillé
|
||||
workerIDs[i] = i;
|
||||
s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
|
||||
}
|
||||
|
||||
// On attend que les workers se mettent en attente
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// On attend que les workers se mettent en attente
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzTaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count)
|
||||
{
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
bool TaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
// On va maintenant répartir les tâches entre chaque worker et les envoyer dans la queue de chacun
|
||||
Worker& worker = s_workers[i];
|
||||
unsigned int taskCount = (i == 0) ? div.quot + div.rem : div.quot;
|
||||
for (unsigned int j = 0; j < taskCount; ++j)
|
||||
worker.queue.push(*tasks++);
|
||||
|
||||
// On stocke le nombre de tâches à côté dans un entier atomique pour éviter d'entrer inutilement dans une section critique
|
||||
worker.workCount = taskCount;
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
void TaskSchedulerImpl::Run(Functor** tasks, unsigned int count)
|
||||
{
|
||||
ResetEvent(s_doneEvents[i]);
|
||||
SetEvent(s_workers[i].wakeEvent);
|
||||
}
|
||||
}
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
void NzTaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On commence par vider la queue de chaque worker pour s'assurer qu'ils s'arrêtent
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
worker.running = false;
|
||||
worker.workCount = 0;
|
||||
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
|
||||
std::queue<NzFunctor*> emptyQueue;
|
||||
std::swap(worker.queue, emptyQueue); // Et on vide la queue (merci std::swap)
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
|
||||
// On réveille le worker pour qu'il sorte de la boucle et termine le thread
|
||||
SetEvent(worker.wakeEvent);
|
||||
}
|
||||
|
||||
// On attend que chaque thread se termine
|
||||
WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);
|
||||
|
||||
// Et on libère les ressources
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
CloseHandle(s_doneEvents[i]);
|
||||
CloseHandle(s_workerThreads[i]);
|
||||
CloseHandle(worker.wakeEvent);
|
||||
DeleteCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
s_doneEvents.reset();
|
||||
s_workers.reset();
|
||||
s_workerThreads.reset();
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
}
|
||||
|
||||
NzFunctor* NzTaskSchedulerImpl::StealTask(unsigned int workerID)
|
||||
{
|
||||
bool shouldRetry;
|
||||
do
|
||||
{
|
||||
shouldRetry = false;
|
||||
std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On ne vole pas la famille, ni soi-même.
|
||||
if (i == workerID)
|
||||
continue;
|
||||
|
||||
// On va maintenant répartir les tâches entre chaque worker et les envoyer dans la queue de chacun
|
||||
Worker& worker = s_workers[i];
|
||||
unsigned int taskCount = (i == 0) ? div.quot + div.rem : div.quot;
|
||||
for (unsigned int j = 0; j < taskCount; ++j)
|
||||
worker.queue.push(*tasks++);
|
||||
|
||||
// Ce worker a-t-il encore des tâches dans sa file d'attente ?
|
||||
if (worker.workCount > 0)
|
||||
{
|
||||
NzFunctor* task = nullptr;
|
||||
// On stocke le nombre de tâches à côté dans un entier atomique pour éviter d'entrer inutilement dans une section critique
|
||||
worker.workCount = taskCount;
|
||||
}
|
||||
|
||||
// Est-ce qu'il utilise la queue maintenant ?
|
||||
if (TryEnterCriticalSection(&worker.queueMutex))
|
||||
{
|
||||
// Non, super ! Profitons-en pour essayer de lui voler un job
|
||||
if (!worker.queue.empty()) // On vérifie que la queue n'est pas vide (peut avoir changé avant le verrouillage)
|
||||
{
|
||||
// Et hop, on vole la tâche
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
else
|
||||
shouldRetry = true; // Il est encore possible d'avoir un job
|
||||
|
||||
// Avons-nous notre tâche ?
|
||||
if (task)
|
||||
return task; // Parfait, sortons de là !
|
||||
}
|
||||
// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
ResetEvent(s_doneEvents[i]);
|
||||
SetEvent(s_workers[i].wakeEvent);
|
||||
}
|
||||
}
|
||||
while (shouldRetry);
|
||||
|
||||
// Bon à priori plus aucun worker n'a de tâche
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int __stdcall NzTaskSchedulerImpl::WorkerProc(void* userdata)
|
||||
{
|
||||
unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
Worker& worker = s_workers[workerID];
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
|
||||
while (worker.running)
|
||||
void TaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
NzFunctor* task = nullptr;
|
||||
|
||||
if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On commence par vider la queue de chaque worker pour s'assurer qu'ils s'arrêtent
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
worker.running = false;
|
||||
worker.workCount = 0;
|
||||
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
|
||||
{
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
std::queue<Functor*> emptyQueue;
|
||||
std::swap(worker.queue, emptyQueue); // Et on vide la queue (merci std::swap)
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
|
||||
// On réveille le worker pour qu'il sorte de la boucle et termine le thread
|
||||
SetEvent(worker.wakeEvent);
|
||||
}
|
||||
|
||||
// Que faire quand vous n'avez plus de travail ?
|
||||
if (!task)
|
||||
task = StealTask(workerID); // Voler le travail des autres !
|
||||
// On attend que chaque thread se termine
|
||||
WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);
|
||||
|
||||
if (task)
|
||||
// Et on libère les ressources
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
Worker& worker = s_workers[i];
|
||||
CloseHandle(s_doneEvents[i]);
|
||||
CloseHandle(s_workerThreads[i]);
|
||||
CloseHandle(worker.wakeEvent);
|
||||
DeleteCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
s_doneEvents.reset();
|
||||
s_workers.reset();
|
||||
s_workerThreads.reset();
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
// Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()
|
||||
// Ça ne devrait pas arriver, mais comme ça ne coûte pas grand chose..
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
void TaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
}
|
||||
|
||||
Functor* TaskSchedulerImpl::StealTask(unsigned int workerID)
|
||||
{
|
||||
bool shouldRetry;
|
||||
do
|
||||
{
|
||||
shouldRetry = false;
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On ne vole pas la famille, ni soi-même.
|
||||
if (i == workerID)
|
||||
continue;
|
||||
|
||||
Worker& worker = s_workers[i];
|
||||
|
||||
// Ce worker a-t-il encore des tâches dans sa file d'attente ?
|
||||
if (worker.workCount > 0)
|
||||
{
|
||||
Functor* task = nullptr;
|
||||
|
||||
// Est-ce qu'il utilise la queue maintenant ?
|
||||
if (TryEnterCriticalSection(&worker.queueMutex))
|
||||
{
|
||||
// Non, super ! Profitons-en pour essayer de lui voler un job
|
||||
if (!worker.queue.empty()) // On vérifie que la queue n'est pas vide (peut avoir changé avant le verrouillage)
|
||||
{
|
||||
// Et hop, on vole la tâche
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
else
|
||||
shouldRetry = true; // Il est encore possible d'avoir un job
|
||||
|
||||
// Avons-nous notre tâche ?
|
||||
if (task)
|
||||
return task; // Parfait, sortons de là !
|
||||
}
|
||||
}
|
||||
}
|
||||
while (shouldRetry);
|
||||
|
||||
// Bon à priori plus aucun worker n'a de tâche
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int __stdcall TaskSchedulerImpl::WorkerProc(void* userdata)
|
||||
{
|
||||
unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
Worker& worker = s_workers[workerID];
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
|
||||
while (worker.running)
|
||||
{
|
||||
Functor* task = nullptr;
|
||||
|
||||
if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
|
||||
{
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
|
||||
{
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
// Que faire quand vous n'avez plus de travail ?
|
||||
if (!task)
|
||||
task = StealTask(workerID); // Voler le travail des autres !
|
||||
|
||||
if (task)
|
||||
{
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()
|
||||
// Ça ne devrait pas arriver, mais comme ça ne coûte pas grand chose..
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<HANDLE[]> TaskSchedulerImpl::s_doneEvents; // Doivent être contigus
|
||||
std::unique_ptr<TaskSchedulerImpl::Worker[]> TaskSchedulerImpl::s_workers;
|
||||
std::unique_ptr<HANDLE[]> TaskSchedulerImpl::s_workerThreads; // Doivent être contigus
|
||||
unsigned int TaskSchedulerImpl::s_workerCount;
|
||||
}
|
||||
|
||||
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_doneEvents; // Doivent être contigus
|
||||
std::unique_ptr<NzTaskSchedulerImpl::Worker[]> NzTaskSchedulerImpl::s_workers;
|
||||
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_workerThreads; // Doivent être contigus
|
||||
unsigned int NzTaskSchedulerImpl::s_workerCount;
|
||||
|
||||
@@ -14,35 +14,38 @@
|
||||
#include <queue>
|
||||
#include <windows.h>
|
||||
|
||||
class NzTaskSchedulerImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzTaskSchedulerImpl() = delete;
|
||||
~NzTaskSchedulerImpl() = delete;
|
||||
class TaskSchedulerImpl
|
||||
{
|
||||
public:
|
||||
TaskSchedulerImpl() = delete;
|
||||
~TaskSchedulerImpl() = delete;
|
||||
|
||||
static bool Initialize(unsigned int workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(NzFunctor** tasks, unsigned int count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
static bool Initialize(unsigned int workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(Functor** tasks, unsigned int count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
|
||||
private:
|
||||
static NzFunctor* StealTask(unsigned int workerID);
|
||||
static unsigned int __stdcall WorkerProc(void* userdata);
|
||||
private:
|
||||
static Functor* StealTask(unsigned int workerID);
|
||||
static unsigned int __stdcall WorkerProc(void* userdata);
|
||||
|
||||
struct Worker
|
||||
{
|
||||
std::atomic_uint workCount;
|
||||
std::queue<NzFunctor*> queue;
|
||||
CRITICAL_SECTION queueMutex;
|
||||
HANDLE wakeEvent;
|
||||
volatile bool running;
|
||||
};
|
||||
struct Worker
|
||||
{
|
||||
std::atomic_uint workCount;
|
||||
std::queue<Functor*> queue;
|
||||
CRITICAL_SECTION queueMutex;
|
||||
HANDLE wakeEvent;
|
||||
volatile bool running;
|
||||
};
|
||||
|
||||
static std::unique_ptr<HANDLE[]> s_doneEvents; // Doivent être contigus
|
||||
static std::unique_ptr<Worker[]> s_workers;
|
||||
static std::unique_ptr<HANDLE[]> s_workerThreads; // Doivent être contigus
|
||||
static unsigned int s_workerCount;
|
||||
static std::unique_ptr<HANDLE[]> s_doneEvents; // Doivent être contigus
|
||||
static std::unique_ptr<Worker[]> s_workers;
|
||||
static std::unique_ptr<HANDLE[]> s_workerThreads; // Doivent être contigus
|
||||
static unsigned int s_workerCount;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_TASKSCHEDULERIMPL_HPP
|
||||
|
||||
@@ -8,40 +8,43 @@
|
||||
#include <process.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzThreadImpl::NzThreadImpl(NzFunctor* functor)
|
||||
namespace Nz
|
||||
{
|
||||
m_handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &NzThreadImpl::ThreadProc, functor, 0, nullptr));
|
||||
if (!m_handle)
|
||||
NazaraInternalError("Failed to create thread: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
void NzThreadImpl::Detach()
|
||||
{
|
||||
// http://stackoverflow.com/questions/418742/is-it-reasonable-to-call-closehandle-on-a-thread-before-it-terminates
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
void NzThreadImpl::Join()
|
||||
{
|
||||
WaitForSingleObject(m_handle, INFINITE);
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
unsigned int __stdcall NzThreadImpl::ThreadProc(void* userdata)
|
||||
{
|
||||
NzFunctor* func = static_cast<NzFunctor*>(userdata);
|
||||
func->Run();
|
||||
delete func;
|
||||
|
||||
/*
|
||||
En C++, il vaut mieux retourner depuis la fonction que de quitter le thread explicitement
|
||||
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NzThreadImpl::Sleep(nzUInt32 time)
|
||||
{
|
||||
::Sleep(time);
|
||||
ThreadImpl::ThreadImpl(Functor* functor)
|
||||
{
|
||||
m_handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, nullptr));
|
||||
if (!m_handle)
|
||||
NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
void ThreadImpl::Detach()
|
||||
{
|
||||
// http://stackoverflow.com/questions/418742/is-it-reasonable-to-call-closehandle-on-a-thread-before-it-terminates
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
void ThreadImpl::Join()
|
||||
{
|
||||
WaitForSingleObject(m_handle, INFINITE);
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
unsigned int __stdcall ThreadImpl::ThreadProc(void* userdata)
|
||||
{
|
||||
Functor* func = static_cast<Functor*>(userdata);
|
||||
func->Run();
|
||||
delete func;
|
||||
|
||||
/*
|
||||
En C++, il vaut mieux retourner depuis la fonction que de quitter le thread explicitement
|
||||
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ThreadImpl::Sleep(UInt32 time)
|
||||
{
|
||||
::Sleep(time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,22 +12,25 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
struct NzFunctor;
|
||||
|
||||
class NzThreadImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzThreadImpl(NzFunctor* threadFunc);
|
||||
struct Functor;
|
||||
|
||||
void Detach();
|
||||
void Join();
|
||||
class ThreadImpl
|
||||
{
|
||||
public:
|
||||
ThreadImpl(Functor* threadFunc);
|
||||
|
||||
static void Sleep(nzUInt32 time);
|
||||
void Detach();
|
||||
void Join();
|
||||
|
||||
private:
|
||||
static unsigned int __stdcall ThreadProc(void* userdata);
|
||||
static void Sleep(UInt32 time);
|
||||
|
||||
HANDLE m_handle;
|
||||
};
|
||||
private:
|
||||
static unsigned int __stdcall ThreadProc(void* userdata);
|
||||
|
||||
HANDLE m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_THREADIMPL_HPP
|
||||
|
||||
@@ -5,21 +5,24 @@
|
||||
#include <Nazara/Core/Win32/Time.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
time_t NzFileTimeToTime(FILETIME* time)
|
||||
namespace Nz
|
||||
{
|
||||
SYSTEMTIME stUTC, stLocal;
|
||||
time_t FileTimeToTime(FILETIME* time)
|
||||
{
|
||||
SYSTEMTIME stUTC, stLocal;
|
||||
|
||||
FileTimeToSystemTime(time, &stUTC);
|
||||
SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
|
||||
FileTimeToSystemTime(time, &stUTC);
|
||||
SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
|
||||
|
||||
std::tm timeinfo;
|
||||
timeinfo.tm_sec = stLocal.wSecond;
|
||||
timeinfo.tm_min = stLocal.wMinute;
|
||||
timeinfo.tm_hour = stLocal.wHour;
|
||||
timeinfo.tm_mday = stLocal.wDay;
|
||||
timeinfo.tm_mon = stLocal.wMonth-1;
|
||||
timeinfo.tm_year = stLocal.wYear-1900;
|
||||
timeinfo.tm_isdst = -1;
|
||||
std::tm timeinfo;
|
||||
timeinfo.tm_sec = stLocal.wSecond;
|
||||
timeinfo.tm_min = stLocal.wMinute;
|
||||
timeinfo.tm_hour = stLocal.wHour;
|
||||
timeinfo.tm_mday = stLocal.wDay;
|
||||
timeinfo.tm_mon = stLocal.wMonth-1;
|
||||
timeinfo.tm_year = stLocal.wYear-1900;
|
||||
timeinfo.tm_isdst = -1;
|
||||
|
||||
return std::mktime(&timeinfo);
|
||||
return std::mktime(&timeinfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include <ctime>
|
||||
#include <windows.h>
|
||||
|
||||
time_t NzFileTimeToTime(FILETIME* time);
|
||||
namespace Nz
|
||||
{
|
||||
time_t FileTimeToTime(FILETIME* time);
|
||||
}
|
||||
|
||||
#endif // NAZARA_WINDOWS_TIME_HPP
|
||||
|
||||
Reference in New Issue
Block a user