SDL2: Replace thread implementation

--HG--
branch : sdl2
hg/feature/sdl2
kaetemi 11 years ago
parent 2f302e93a9
commit b74c3cc9fa

@ -177,7 +177,7 @@ private:
CProtagonist _LocalWindow;
CProtagonist _ForeignWindow;
CSendTask *_SendTask;
IThread *_SendThread;
CThread *_SendThread;
static const uint _CurrentVersion; // for messages serialisation

@ -1,97 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_P_THREAD_H
#define NL_P_THREAD_H
#include "types_nl.h"
#ifdef NL_OS_UNIX
#include "thread.h"
#include <pthread.h>
namespace NLMISC {
/**
* Posix Thread
* \author Olivier Cado
* \author Nevrax France
* \date 2001
*/
class CPThread : public IThread
{
public:
enum TThreadState
{
ThreadStateNone,
ThreadStateRunning,
ThreadStateFinished,
};
/// Constructor
CPThread( IRunnable *runnable, uint32 stackSize);
virtual ~CPThread();
virtual void start();
virtual bool isRunning();
virtual void terminate();
virtual void wait();
virtual bool setCPUMask(uint64 cpuMask);
virtual uint64 getCPUMask();
virtual void setPriority(TThreadPriority priority);
virtual std::string getUserName();
virtual IRunnable *getRunnable()
{
return Runnable;
}
/// Internal use
IRunnable *Runnable;
TThreadState _State;
pthread_t _ThreadHandle;
private:
uint32 _StackSize;
};
/**
* Posix Process
* \author Cyril 'Hulud' Corvazier
* \author Nevrax France
* \date 2001
*/
class CPProcess : public IProcess
{
public:
virtual ~CPProcess() {}
virtual uint64 getCPUMask();
virtual bool setCPUMask(uint64 mask);
};
} // NLMISC
#endif // NL_OS_UNIX
#endif // NL_P_THREAD_H
/* End of p_thread.h */

@ -65,6 +65,10 @@ public:
*/
static bool isNT();
/** Return number of CPU cores
*/
static uint getCPUCount();
/** Returns the space left on the hard drive that contains the filename
*/
static std::string availableHDSpace (const std::string &filename);

@ -144,7 +144,7 @@ protected:
CSynchronized<std::deque<std::string> > _DoneTaskQueue;
/// thread pointer
IThread *_Thread;
CThread *_Thread;
/// flag indicate thread loop, if false cause thread exit
volatile bool _ThreadRunning;

@ -19,11 +19,12 @@
#include "types_nl.h"
#include "common.h"
#include "mutex.h"
struct SDL_Thread;
namespace NLMISC {
/**
* Thread callback interface.
* When a thread is created, it will call run() in its attached IRunnable interface.
@ -41,7 +42,7 @@ namespace NLMISC {
};
IThread *thread = IThread::create (new HelloLoopThread);
CThread *thread = new CThread (new HelloLoopThread);
thread->start ();
*\endcode
@ -62,7 +63,7 @@ public:
{
}
// Return the runnable name
virtual void getName (std::string &result) const
virtual void getName(std::string &result) const
{
result = "NoName";
}
@ -71,74 +72,48 @@ public:
/// Thread priorities, numbering follows Win32 for now
enum TThreadPriority
{
ThreadPriorityLowest = -2,
ThreadPriorityLow = -1,
ThreadPriorityNormal = 0,
ThreadPriorityHigh = 1,
ThreadPriorityHighest = 2,
ThreadPriorityLow,
ThreadPriorityNormal,
ThreadPriorityHigh
};
/**
* Thread base interface, must be implemented for all OS
* \author Vianney Lecroart
* \author Nevrax France
* \date 2000
* Interface to SDL2 threads
* \date 2014
*/
class IThread
class CThread
{
public:
CThread(IRunnable *runnable);
/**
* Create a new thread.
* Implemented in the derived class.
*/
static IThread *create(IRunnable *runnable, uint32 stackSize = 0);
/**
* Return a pointer on the current thread.
* Implemented in the derived class.
*/
static IThread *getCurrentThread ();
virtual ~IThread () { }
// Thread will be detached immediately and remain running.
~CThread();
// Starts the thread.
virtual void start()=0;
void start();
// Check if the thread is still running
virtual bool isRunning() =0;
bool isRunning();
// Terminate the thread (risky method, use only in extreme cases)
virtual void terminate()=0;
// In the calling program, wait until the specified thread has exited. After wait() has returned, you can delete the thread object.
virtual void wait()=0;
/// In the calling program, wait until the specified thread has exited.
int wait();
/// Return a pointer to the runnable object
virtual IRunnable *getRunnable()=0;
/**
* Set the CPU mask of this thread. Thread must have been started before.
* The mask must be a subset of the CPU mask returned by IProcess::getCPUMask() thread process.
*/
virtual bool setCPUMask(uint64 cpuMask)=0;
/**
* Get the CPU mask of this thread. Thread must have been started before.
* The mask should be a subset of the CPU mask returned by IProcess::getCPUMask() thread process.
*/
virtual uint64 getCPUMask()=0;
/// Set the thread priority. Thread must have been started before.
virtual void setPriority(TThreadPriority priority) = 0;
/**
* Get the thread user name.
* Under Linux return thread owner, under windows return the name of the logon user.
*/
virtual std::string getUserName()=0;
};
IRunnable *getRunnable();
/// Set the priority for the current thread.
static void setPriority(TThreadPriority priority);
private:
static int run(void *ptr);
volatile bool m_IsRunning;
SDL_Thread *m_SDLThread;
IRunnable *m_Runnable;
CMutex m_WaitMutex; // Mutex to allow multiple threads to wait for one thread
int m_ThreadResult; // Result from last thread run
};
/*
* Thread exception
@ -148,39 +123,8 @@ struct EThread : public Exception
EThread (const char* message) : Exception (message) {}
};
/**
* Process base interface, must be implemented for all OS
* \author Cyril 'Hulud' Corvazier
* \author Nevrax France
* \date 2000
*/
class IProcess
{
public:
virtual ~IProcess() {}
/**
* Return a pointer on the current process.
* Implemented in the derived class.
*/
static IProcess *getCurrentProcess ();
/**
* Return process CPU mask. Each bit stand for a CPU usable by the process threads.
*/
virtual uint64 getCPUMask()=0;
/**
* Set the process CPU mask. Each bit stand for a CPU usable by the process threads.
*/
virtual bool setCPUMask(uint64 mask)=0;
};
} // NLMISC
#endif // NL_THREAD_H
/* End of thread.h */

@ -52,8 +52,6 @@ public:
{
/// Returns if there is a high precision timer that can be used.
bool IsHighPrecisionAvailable;
/// If a CPU specific timer is used and the values are not consistent accross threads.
bool RequiresSingleCore;
/// The resolution of the high resolution timer.
TTicks HighPrecisionResolution;
};

@ -28,7 +28,7 @@
// in init
CTimeoutAssertionThread *myTAT = new CTimeoutAssertionThread(1000);
IThread::create(myTAT)->start();
new CThread(myTAT)->start();
...

@ -1,145 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_WIN_THREAD_H
#define NL_WIN_THREAD_H
#include "types_nl.h"
#include "thread.h"
#ifdef NL_OS_WINDOWS
namespace NLMISC {
/**
* Windows implementation of CThread class (look thread.h)
* \author Vianney Lecroart
* \author Nevrax France
* \date 2000
*/
class CWinThread : public IThread
{
public:
/// Constructor
CWinThread(IRunnable *runnable, uint32 stackSize);
/// Don't use this constructor, only used to initialise the main thread class
CWinThread (void* threadHandle, uint32 threadId);
virtual ~CWinThread();
virtual void start();
virtual bool isRunning();
virtual void terminate();
virtual void wait();
virtual bool setCPUMask(uint64 cpuMask);
virtual uint64 getCPUMask();
virtual void setPriority(TThreadPriority priority);
virtual std::string getUserName();
virtual IRunnable *getRunnable()
{
return Runnable;
}
// Win32 specific
// Get the suspend count. Will be -1 is the thread hasn't been started yet
int getSuspendCount() const { return _SuspendCount; }
// Increment the suspend count, a suspend count >= 1 means the thread is suspended
void incSuspendCount();
/** Descrement the suspend count. Reaching 0 will resume the thread
* An assertion is raised is the suspend count is already 0
*/
void decSuspendCount();
// Suspend the thread. No-op if already suspended
void suspend();
// Resume the thread. No-op if already resumed
void resume();
// Priority boost
void enablePriorityBoost(bool enabled);
/// private use
IRunnable *Runnable;
private:
int _SuspendCount;
uint32 _StackSize;
void *ThreadHandle; // HANDLE don't put it to avoid including windows.h
uint32 ThreadId; // DWORD don't put it to avoid including windows.h
bool _MainThread; // true if ths thread is the main thread, else false
};
/**
* Windows Process
* \author Cyril 'Hulud' Corvazier
* \author Nicolas Vizerie
* \author Nevrax France
* \date 2001, 2007
*/
class CWinProcess : public IProcess
{
public:
CWinProcess (void *handle);
virtual ~CWinProcess() {} // TODO do something with _ProcessHandle?
virtual uint64 getCPUMask();
virtual bool setCPUMask(uint64 mask);
// processes helpers
static bool enumProcessesId(std::vector<uint32> &processesId);
// get fully qualified path for all modules used by a given process
static bool enumProcessModules(uint32 processId, std::vector<std::string> &moduleNames);
static uint32 getProcessIdFromModuleFilename(const std::string &moduleFileName);
static bool terminateProcess(uint32 processId, uint exitCode = 0);
static bool terminateProcessFromModuleName(const std::string &moduleName, uint exitCode = 0);
private:
void *_ProcessHandle;
};
/*
// I didn't use and test that code, enventually, but maybe useful in the future
//
// Utility class to launch a process and check if it is still running.
// Implemented under windows only for now
//
class CProcessWatch
{
public:
CProcessWatch();
~CProcessWatch();
// launch a process with the given name and arguments, return true on success
bool launch(const std::string &programName, const std::string &arguments);
// return true if the process is still runing
bool isRunning() const;
private:
class CProcessWatchImpl *_PImpl;
};
*/
} // NLMISC
#endif // NL_OS_WINDOWS
#endif // NL_WIN_THREAD_H
/* End of win_thread.h */

@ -103,7 +103,7 @@ protected:
sint _InputEditHeight;
// the thread used to update the display
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
CLog *Log;

@ -235,7 +235,7 @@ private:
CClientReceiveTask *_RecvTask;
/// Receive thread
NLMISC::IThread *_RecvThread;
NLMISC::CThread *_RecvThread;
};

@ -105,7 +105,7 @@ private:
};
typedef std::vector<NLMISC::IThread*> CThreadPool;
typedef std::vector<NLMISC::CThread*> CThreadPool;
// Mode: Small server
@ -290,7 +290,7 @@ protected:
void dispatchNewSocket( CServerBufSock *bufsock );
/// Returns the receive task corresponding to a particular thread
CServerReceiveTask *receiveTask( std::vector<NLMISC::IThread*>::iterator ipt )
CServerReceiveTask *receiveTask( std::vector<NLMISC::CThread*>::iterator ipt )
{
return ((CServerReceiveTask*)((*ipt)->getRunnable()));
}
@ -346,7 +346,7 @@ private:
CListenTask *_ListenTask;
/// Listen thread
NLMISC::IThread *_ListenThread;
NLMISC::CThread *_ListenThread;
/* Vector of receiving threads.
* Thread: thread control

@ -95,7 +95,7 @@ private:
private:
inline CStreamFileSound *getStreamFileSound() { return static_cast<CStreamFileSound *>(m_StreamSound); }
NLMISC::IThread *m_Thread;
NLMISC::CThread *m_Thread;
IAudioDecoder *m_AudioDecoder;

@ -33,6 +33,7 @@
#include "nel/misc/file.h"
#include "nel/misc/aabbox.h"
#include "nel/misc/algo.h"
#include "nel/misc/system_info.h"
#ifdef NL_OS_WINDOWS
@ -315,38 +316,6 @@ void NEL3DCalcBase (CVector &direction, CMatrix& matrix)
// ***************************************************************************
void setCPUMask (IThread *thread, uint process)
{
// Set the processor mask
uint64 mask = IProcess::getCurrentProcess()->getCPUMask ();
// Mask must not be NULL
nlassert (mask != 0);
if (mask != 0)
{
uint i=0;
uint count = 0;
for(;;)
{
if (mask & (UINT64_CONSTANT(1)<<i))
{
if (count == process)
break;
count++;
}
i++;
if (i==64)
i = 0;
}
// Set the CPU mask
thread->setCPUMask (1<<i);
}
}
// ***************************************************************************
class NL3D::CLightRunnable : public IRunnable
{
// Members
@ -355,7 +324,7 @@ class NL3D::CLightRunnable : public IRunnable
const CZoneLighter::CLightDesc *_Description;
public:
IThread *Thread;
CThread *Thread;
public:
// Ctor
@ -369,9 +338,6 @@ public:
// Run method
void run()
{
// Set the CPU mask
setCPUMask (Thread, _Process);
_ZoneLighter->processCalc (_Process, *_Description);
_ZoneLighter->_ProcessExitedMutex.enter();
_ZoneLighter->_ProcessExited++;
@ -397,7 +363,7 @@ class NL3D::CRenderZBuffer : public IRunnable
const vector<CZoneLighter::CTriangle> *_Triangles;
public:
IThread *Thread;
CThread *Thread;
public:
// Ctor
@ -614,9 +580,6 @@ void RenderTriangle (const CZoneLighter::CTriangle &triangle, const CZoneLighter
void NL3D::CRenderZBuffer::run()
{
// Set the CPU mask
setCPUMask (Thread, _Process);
// Span array
CPolygon2D::TRasterVect borders;
@ -915,11 +878,6 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight
* -
*/
// Backup thread mask
IThread *currentThread = IThread::getCurrentThread ();
uint64 threadMask = currentThread->getCPUMask();
currentThread->setCPUMask (1);
// Calc the ray basis
_SunDirection=description.SunDirection;
NEL3DCalcBase (_SunDirection, _RayBasis);
@ -934,16 +892,7 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight
_ProcessCount=description.NumCPU;
if (_ProcessCount==0)
{
// Create a doomy thread
IProcess *pProcess=IProcess::getCurrentProcess ();
_CPUMask = pProcess->getCPUMask();
_ProcessCount = 0;
uint64 i;
for (i=0; i<64; i++)
{
if (_CPUMask&((uint64)1<<i))
_ProcessCount++;
}
_ProcessCount = CSystemInfo::getCPUCount();
}
if (_ProcessCount>MAX_CPU_PROCESS)
_ProcessCount=MAX_CPU_PROCESS;
@ -1027,7 +976,7 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight
// Create a thread
CRenderZBuffer *runnable = new CRenderZBuffer (process, this, &description, firstTriangle, lastTriangle - firstTriangle, &obstacles);
IThread *pThread=IThread::create (runnable);
CThread *pThread=new CThread (runnable);
runnable->Thread = pThread;
// New first patch
@ -1183,7 +1132,7 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight
// Create a thread
CLightRunnable *runnable = new CLightRunnable (process, this, &description);
IThread *pThread=IThread::create (runnable);
CThread *pThread=new CThread (runnable);
runnable->Thread = pThread;
// New first patch
@ -1202,9 +1151,6 @@ void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight
progress ("Lighting patches", (float)_NumberOfPatchComputed/(float)_PatchInfo.size());
}
// Reset old thread mask
currentThread->setCPUMask (threadMask);
// overflow ?
if (_ZBufferOverflow)
nlwarning ("Error : zbuffer overflow");
@ -2861,7 +2807,7 @@ void CZoneLighter::lightShapes(uint zoneID, const CLightDesc& description)
{
uint lastShapeIndex = currShapeIndex + numShapePerThread;
lastShapeIndex = std::min((uint)_LightableShapes.size(), lastShapeIndex);
IThread *pThread = IThread::create (new CCalcLightableShapeRunnable(process, this, &description, &_LightableShapes, currShapeIndex, lastShapeIndex));
CThread *pThread = new CThread (new CCalcLightableShapeRunnable(process, this, &description, &_LightableShapes, currShapeIndex, lastShapeIndex));
pThread->start();
currShapeIndex = lastShapeIndex;
}

@ -85,7 +85,7 @@ void CFileHeader::addLog (const char *log)
Log += ctime(&t);
Log.resize (Log.size()-1);
Log += " (";
Log += IThread::getCurrentThread ()->getUserName ();
// Log += CThread::getCurrentThread ()->getUserName (); // FIXME: USERNAME
Log += ") ";
Log += log;
}

@ -84,7 +84,7 @@ namespace NLMISC
// TThreadId *_ParentThreadId;
// the thread of the task
IThread *_TaskThread;
CThread *_TaskThread;
/// The mutex of the task task
CFastMutex _TaskMutex;
@ -300,7 +300,7 @@ namespace NLMISC
#if defined(NL_USE_THREAD_COTASK)
// create the thread
_PImpl->_TaskThread = IThread::create(_PImpl);
_PImpl->_TaskThread = new CThread(_PImpl);
NL_CT_DEBUG("CoTask : start() task %p entering mutex", this);
// get the mutex

@ -296,7 +296,7 @@ namespace NLMISC
//
messageQueueMap->value()[msgQueueIdent] = this;
_SendTask = new CSendTask(this);
_SendThread = IThread::create(_SendTask);
_SendThread = new CThread(_SendTask);
_SendThread->start();
// init the window handle in shared memory last,
// this way we are sure that the new win proc has been installed, and can start received messages

@ -1,387 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdmisc.h"
#include <nel/misc/types_nl.h>
#include <nel/misc/debug.h>
#ifdef NL_OS_UNIX
#include "nel/misc/p_thread.h"
#include <sched.h>
#include <pwd.h>
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
namespace NLMISC {
/* Key for thread specific storage holding IThread pointer. */
static pthread_key_t threadSpecificKey;
/* Special thread type representing the main thread. */
struct CPMainThread : public CPThread
{
CPMainThread() : CPThread(NULL, 0)
{
if(pthread_key_create(&threadSpecificKey, NULL) != 0)
throw EThread("cannot create thread specific storage key.");
if(pthread_setspecific(threadSpecificKey, this) != 0)
throw EThread("cannot set main thread ptr in thread specific storage.");
}
~CPMainThread()
{
if(pthread_key_delete(threadSpecificKey) != 0)
throw EThread("cannot delete thread specific storage key.");
}
};
/* Holds the thread instance representing the main thread. */
static CPMainThread mainThread = CPMainThread();
/*
* The IThread static creator
*/
IThread *IThread::create( IRunnable *runnable, uint32 stackSize)
{
return new CPThread( runnable, stackSize );
}
/*
* Get the current thread
*/
IThread *IThread::getCurrentThread ()
{
return (IThread *)pthread_getspecific(threadSpecificKey);
}
/*
* Thread beginning
*/
static void *ProxyFunc( void *arg )
{
CPThread *parent = (CPThread*)arg;
// Set this thread's thread specific storage to IThread instance pointer
if(pthread_setspecific(threadSpecificKey, parent) != 0)
throw EThread("cannot set thread ptr in thread specific storage.");
// Allow to terminate the thread without cancellation point
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
// Run the code of the thread
parent->Runnable->run();
{
pthread_t thread_self = pthread_self();
// Make sure the parent still cares
// If this thread was replaced with a new thread (which should not happen),
// and the IThread object has been deleted, this will likely crash.
if (parent->_ThreadHandle == thread_self)
parent->_State = CPThread::ThreadStateFinished;
else
throw EThread("Thread ended after being detached, this should not happen");
}
// Allow some clean
// pthread_exit(0);
return NULL;
}
/*
* Constructor
*/
CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
: Runnable(runnable),
_State(ThreadStateNone),
_StackSize(stackSize)
{}
/*
* Destructor
*/
CPThread::~CPThread()
{
terminate(); // force the end of the thread if not already ended
if (_State != ThreadStateNone)
pthread_detach(_ThreadHandle); // free allocated resources only if it was created
}
/*
* start
*/
void CPThread::start()
{
pthread_attr_t tattr;
int ret;
if (_StackSize != 0)
{
/* initialized with default attributes */
ret = pthread_attr_init(&tattr);
/* setting the size of the stack also */
ret = pthread_attr_setstacksize(&tattr, _StackSize);
}
bool detach_old_thread = false;
pthread_t old_thread_handle;
if (_State != ThreadStateNone)
{
if (_State == ThreadStateRunning)
{
// I don't know if this behaviour is allowed, but neither thread implementations
// check the start function, and both simply let the existing running thread for what it is...
// From now on, this is not allowed.
throw EThread("Starting a thread that is already started, existing thread will continue running, this should not happen");
}
detach_old_thread = true;
old_thread_handle = _ThreadHandle;
}
if (pthread_create(&_ThreadHandle, _StackSize != 0 ? &tattr : NULL, ProxyFunc, this) != 0)
{
throw EThread("Cannot start new thread");
}
_State = ThreadStateRunning;
if (detach_old_thread)
{
// Docs don't say anything about what happens when pthread_create is called with existing handle referenced.
if (old_thread_handle == _ThreadHandle)
throw EThread("Thread handle did not change, this should not happen");
// Don't care about old thread, free resources when it terminates.
pthread_detach(old_thread_handle);
}
}
bool CPThread::isRunning()
{
return _State == ThreadStateRunning;
}
/*
* terminate
*/
void CPThread::terminate()
{
if (_State == ThreadStateRunning)
{
// cancel only if started
pthread_cancel(_ThreadHandle);
_State = ThreadStateFinished; // set to finished
}
}
/*
* wait
*/
void CPThread::wait ()
{
if (_State == ThreadStateRunning)
{
int error = pthread_join(_ThreadHandle, 0);
switch (error)
{
case 0:
break;
case EINVAL:
throw EThread("Thread is not joinable");
case ESRCH:
throw EThread("No thread found with this id");
case EDEADLK:
throw EThread("Deadlock detected or calling thread waits for itself");
default:
throw EThread("Unknown thread join error");
}
if(_State != ThreadStateFinished)
throw EThread("Thread did not finish, this should not happen");
}
}
/*
* setCPUMask
*/
bool CPThread::setCPUMask(uint64 cpuMask)
{
#ifdef __USE_GNU
nlwarning("This code does not work. May cause a segmentation fault...");
sint res = pthread_setaffinity_np(_ThreadHandle, sizeof(uint64), (const cpu_set_t*)&cpuMask);
if (res)
{
nlwarning("pthread_setaffinity_np() returned %d", res);
return false;
}
return true;
#else // __USE_GNU
return false;
#endif // __USE_GNU
}
/*
* getCPUMask
*/
uint64 CPThread::getCPUMask()
{
#ifdef __USE_GNU
nlwarning("This code does not work. May cause a segmentation fault...");
uint64 cpuMask = 0;
sint res = pthread_getaffinity_np(_ThreadHandle, sizeof(uint64), (cpu_set_t*)&cpuMask);
if (res)
{
nlwarning("pthread_getaffinity_np() returned %d", res);
return 0;
}
return cpuMask;
#else // __USE_GNU
return 0;
#endif // __USE_GNU
}
void CPThread::setPriority(TThreadPriority priority)
{
// TODO: Test this
sched_param sp;
switch (priority)
{
case ThreadPriorityHigh:
{
int minPrio = sched_get_priority_min(SCHED_FIFO);
int maxPrio = sched_get_priority_max(SCHED_FIFO);
sp.sched_priority = ((maxPrio - minPrio) / 4) + minPrio;
pthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);
break;
}
case ThreadPriorityHighest:
{
int minPrio = sched_get_priority_min(SCHED_FIFO);
int maxPrio = sched_get_priority_max(SCHED_FIFO);
sp.sched_priority = ((maxPrio - minPrio) / 2) + minPrio;
pthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);
break;
}
default:
sp.sched_priority = 0;
pthread_setschedparam(_ThreadHandle, SCHED_OTHER, &sp);
}
}
/*
* getUserName
*/
std::string CPThread::getUserName()
{
struct passwd *pw = getpwuid(getuid());
if (!pw)
return "";
return pw->pw_name;
}
// **** Process
// The current process
CPProcess CurrentProcess;
// Get the current process
IProcess *IProcess::getCurrentProcess ()
{
return &CurrentProcess;
}
/*
* getCPUMask
*/
uint64 CPProcess::getCPUMask()
{
#ifdef __USE_GNU
uint64 cpuMask = 0;
sint res = sched_getaffinity(getpid(), sizeof(uint64), (cpu_set_t*)&cpuMask);
if (res)
{
nlwarning("sched_getaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
return 0;
}
return cpuMask;
#else // __USE_GNU
return 0;
#endif // __USE_GNU
}
/// set the CPU mask
bool CPProcess::setCPUMask(uint64 cpuMask)
{
#ifdef __USE_GNU
sint res = sched_setaffinity(getpid(), sizeof(uint64), (const cpu_set_t*)&cpuMask);
if (res)
{
nlwarning("sched_setaffinity() returned %d, errno = %d: %s", res, errno, strerror(errno));
return false;
}
return true;
#else // __USE_GNU
return false;
#endif // __USE_GNU
}
} // NLMISC
#else // NL_OS_UNIX
// remove stupid VC6 warnings
void foo_p_thread_cpp() {}
#endif // NL_OS_UNIX

@ -918,6 +918,11 @@ bool CSystemInfo::hasSSE2()
return SDL_HasSSE2();
}
uint CSystemInfo::getCPUCount()
{
return SDL_GetCPUCount();
}
bool CSystemInfo::isNT()
{
#ifdef NL_OS_WINDOWS

@ -38,7 +38,7 @@ CTaskManager::CTaskManager() : _RunningTask (""), _TaskQueue (""), _DoneTaskQueu
_ThreadRunning = true;
CSynchronized<string>::CAccessor currentTask(&_RunningTask);
currentTask.value () = "";
_Thread = IThread::create(this);
_Thread = new CThread(this);
_Thread->start();
_ChangePriorityCallback = NULL;
}

@ -0,0 +1,105 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdmisc.h"
#include "nel/misc/thread.h"
#include "nel/misc/debug.h"
#include <SDL_thread.h>
namespace NLMISC {
CThread::CThread(IRunnable *runnable) : m_IsRunning(false), m_SDLThread(NULL), m_Runnable(runnable)
{
}
CThread::~CThread ()
{
/*
NOTE: Detach not supported, due to m_IsRunning which is referenced by the running thread
FIX: Use a thread-safe reference counted object for the m_IsRunning flag
if (m_SDLThread)
{
SDL_DetachThread(m_SDLThread);
}
NOTE: Currently use wait, which is much saner behaviour.
*/
wait();
}
void CThread::start()
{
nlassert(!m_SDLThread);
nlassert(!m_IsRunning);
std::string name;
m_Runnable->getName(name);
m_IsRunning = true;
m_SDLThread = SDL_CreateThread(run, name.c_str(), (void *)this);
}
int CThread::run(void *ptr)
{
NLMISC::CThread *thread = static_cast<NLMISC::CThread *>(ptr);
thread->m_Runnable->run();
thread->m_IsRunning = false;
return 0;
}
void CThread::setPriority(TThreadPriority priority)
{
switch (priority)
{
case ThreadPriorityLow:
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
break;
case ThreadPriorityNormal:
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_NORMAL);
break;
case ThreadPriorityHigh:
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
break;
default:
nlerror("Invalid thread priority");
break;
}
}
bool CThread::isRunning()
{
return m_IsRunning;
}
int CThread::wait()
{
m_WaitMutex.enter();
if (m_SDLThread)
{
SDL_WaitThread(m_SDLThread, &m_ThreadResult);
m_SDLThread = NULL;
nlassert(!m_IsRunning);
}
m_WaitMutex.leave();
return m_ThreadResult;
}
IRunnable *CThread::getRunnable()
{
return m_Runnable;
}
} // NLMISC

@ -153,135 +153,6 @@ void CTime::probeTimerInfo(CTime::CTimerInfo &result)
#endif
uint64 cpuMask = IProcess::getCurrentProcess()->getCPUMask();
#ifdef NL_OS_WINDOWS
uint64 threadMask = IThread::getCurrentThread()->getCPUMask(); // broken on linux, don't expect it to work anywhere
#else
uint64 threadMask = cpuMask;
#endif
uint identical = 0; // Identical stamps may indicate the os handling backwards glitches.
uint backwards = 0; // Happens when the timers are not always in sync and the implementation is faulty.
uint regular = 0; // How many times the number advanced normally.
uint skipping = 0; // Does not really mean anything necessarily.
uint frequencybug = 0; // Should never happen.
// uint badcore = 0; // Affinity does not work.
// Cycle 32 times trough all cores, and verify if the timing remains consistent.
for (uint i = 32; i; --i)
{
uint64 currentBit = 1;
for (uint j = 64; j; --j)
{
if (cpuMask & currentBit)
{
#ifdef NL_OS_WINDOWS
if (!IThread::getCurrentThread()->setCPUMask(currentBit))
#else
if (!IProcess::getCurrentProcess()->setCPUMask(currentBit))
#endif
break; // Thread was set to last cpu.
#ifdef NL_OS_WINDOWS
// Make sure the thread is rescheduled.
SwitchToThread();
Sleep(0);
// Verify the core
/* Can only verify on 2003, Vista and higher.
if (1 << GetCurrentProcessorNumber() != currentBit)
++badcore;
*/
// Check if the timer is still sane.
if (result.IsHighPrecisionAvailable)
{
LARGE_INTEGER winPerfFreqN;
LARGE_INTEGER winPerfCountN;
QueryPerformanceFrequency(&winPerfFreqN);
if (winPerfFreqN.QuadPart != winPerfFreq.QuadPart)
++frequencybug;
QueryPerformanceCounter(&winPerfCountN);
if (winPerfCountN.QuadPart == winPerfCount.QuadPart)
++identical;
if (winPerfCountN.QuadPart < winPerfCount.QuadPart || winPerfCountN.QuadPart - winPerfCount.QuadPart < 0)
++backwards;
if (winPerfCountN.QuadPart - winPerfCount.QuadPart > winPerfFreq.QuadPart / 20) // 50ms skipping check
++skipping;
else if (winPerfCountN.QuadPart > winPerfCount.QuadPart)
++regular;
winPerfCount.QuadPart = winPerfCountN.QuadPart;
}
else
{
DWORD lowResTimeN;
lowResTimeN = timeGetTime();
if (lowResTimeN == lowResTime)
++identical;
if (lowResTimeN < lowResTime || lowResTimeN - lowResTime < 0)
++backwards;
if (lowResTimeN - lowResTime > 50)
++skipping;
else if (lowResTimeN > lowResTime)
++regular;
lowResTime = lowResTimeN;
}
#else
#ifdef NL_OS_UNIX
sched_yield();
#else
nlSleep(0);
#endif
# ifdef NL_MONOTONIC_CLOCK
if (hasMonotonicClock())
{
timespec monoClockN;
clock_gettime(CLOCK_MONOTONIC, &monoClockN);
if (monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec == monoClockN.tv_nsec)
++identical;
if (monoClockN.tv_sec < monoClock.tv_sec || (monoClock.tv_sec == monoClockN.tv_sec && monoClockN.tv_nsec < monoClock.tv_nsec))
++backwards;
if (monoClock.tv_sec == monoClockN.tv_sec && (monoClockN.tv_nsec - monoClock.tv_nsec > 50000000L))
++skipping;
else if ((monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec < monoClockN.tv_nsec) || monoClock.tv_sec < monoClockN.tv_sec)
++regular;
monoClock.tv_sec = monoClockN.tv_sec;
monoClock.tv_nsec = monoClockN.tv_nsec;
}
else
# endif
{
TTime localTimeN = getLocalTime();
if (localTimeN == localTime)
++identical;
if (localTimeN < localTime || localTimeN - localTime < 0)
++backwards;
if (localTimeN - localTime > 50)
++skipping;
else if (localTimeN > localTime)
++regular;
localTime = localTimeN;
}
#endif
}
currentBit <<= 1;
}
}
#ifdef NL_OS_WINDOWS
IThread::getCurrentThread()->setCPUMask(threadMask);
#else
IProcess::getCurrentProcess()->setCPUMask(threadMask);
#endif
nldebug("Timer resolution: %i Hz", (int)(result.HighPrecisionResolution));
nldebug("Time identical: %i, backwards: %i, regular: %i, skipping: %i, frequency bug: %i", identical, backwards, regular, skipping, frequencybug);
if (identical > regular)
nlwarning("The system timer is of relatively low resolution, you may experience issues");
if (backwards > 0 || frequencybug > 0)
{
nlwarning("The current system timer is not reliable across multiple cpu cores");
result.RequiresSingleCore = true;
}
else result.RequiresSingleCore = false;
if (result.HighPrecisionResolution == 14318180)
{
nldebug("Detected known HPET era timer frequency");

@ -1,609 +0,0 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdmisc.h"
#include "nel/misc/win_thread.h"
#ifdef NL_OS_WINDOWS
#include "nel/misc/path.h"
#define NOMINMAX
#include <windows.h>
#include <typeinfo>
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
namespace NLMISC {
CWinThread MainThread ((void*)GetCurrentThread (), GetCurrentThreadId());
DWORD TLSThreadPointer = 0xFFFFFFFF;
// the IThread static creator
IThread *IThread::create (IRunnable *runnable, uint32 stackSize)
{
return new CWinThread (runnable, stackSize);
}
IThread *IThread::getCurrentThread ()
{
// TLS alloc must have been done
nlassert (TLSThreadPointer != 0xffffffff);
// Get the thread pointer
IThread *thread = (IThread*)TlsGetValue (TLSThreadPointer);
// Return current thread
return thread;
}
static unsigned long __stdcall ProxyFunc (void *arg)
{
CWinThread *parent = (CWinThread *) arg;
// TLS alloc must have been done
nlassert (TLSThreadPointer != 0xffffffff);
// Set the thread pointer in TLS memory
nlverify (TlsSetValue (TLSThreadPointer, (void*)parent) != 0);
// Run the thread
parent->Runnable->run();
return 0;
}
CWinThread::CWinThread (IRunnable *runnable, uint32 stackSize)
{
_StackSize = stackSize;
this->Runnable = runnable;
ThreadHandle = NULL;
_SuspendCount = -1;
_MainThread = false;
}
namespace {
class CWinCriticalSection
{
private:
CRITICAL_SECTION cs;
public:
CWinCriticalSection() { InitializeCriticalSection(&cs); }
~CWinCriticalSection() { DeleteCriticalSection(&cs); }
inline void enter() { EnterCriticalSection(&cs); }
inline void leave() { LeaveCriticalSection(&cs); }
};
CWinCriticalSection s_CS;
}/* anonymous namespace */
CWinThread::CWinThread (void* threadHandle, uint32 threadId)
{
// Main thread
_MainThread = true;
this->Runnable = NULL;
ThreadHandle = threadHandle;
ThreadId = threadId;
// TLS alloc must have been done
TLSThreadPointer = TlsAlloc ();
nlassert (TLSThreadPointer!=0xffffffff);
// Set the thread pointer in TLS memory
nlverify (TlsSetValue (TLSThreadPointer, (void*)this) != 0);
if (GetCurrentThreadId() == threadId)
{
_SuspendCount = 0; // is calling thread call this itself, well, if we reach this place
// there are chances that it is not suspended ...
}
else
{
// initialized from another thread (very unlikely ...)
nlassert(0); // WARNING: following code has not tested! don't know if it work fo real ...
// This is just a suggestion of a possible solution, should this situation one day occur ...
// Ensure that this thread don't get deleted, or we could suspend the main thread
s_CS.enter();
// the 2 following statement must be executed atomicaly among the threads of the current process !
SuspendThread(threadHandle);
_SuspendCount = ResumeThread(threadHandle);
s_CS.leave();
}
}
void CWinThread::incSuspendCount()
{
nlassert(ThreadHandle); // start was not called !!
int newSuspendCount = ::SuspendThread(ThreadHandle) + 1;
nlassert(newSuspendCount != 0xffffffff); // more infos with 'GetLastError'
nlassert(newSuspendCount == _SuspendCount + 1); // is this assert fire , then 'SuspendThread' or 'ResumeThread'
// have been called outside of this object interface! (on this thread handle ...)
_SuspendCount = newSuspendCount;
}
void CWinThread::decSuspendCount()
{
nlassert(ThreadHandle); // 'start' was not called !!
nlassert(_SuspendCount > 0);
int newSuspendCount = ::ResumeThread(ThreadHandle) - 1;
nlassert(newSuspendCount != 0xffffffff); // more infos with 'GetLastError'
nlassert(newSuspendCount == _SuspendCount - 1); // is this assert fire , then 'SuspendThread' or 'ResumeThread'
// have been called outside of this object interface! (on this thread handle ...)
_SuspendCount = newSuspendCount;
}
void CWinThread::suspend()
{
if (getSuspendCount() == 0)
{
incSuspendCount();
}
}
void CWinThread::resume()
{
while (getSuspendCount() != 0)
{
decSuspendCount();
}
}
void CWinThread::setPriority(TThreadPriority priority)
{
nlassert(ThreadHandle); // 'start' was not called !!
BOOL result = SetThreadPriority(ThreadHandle, (int)priority);
nlassert(result);
}
void CWinThread::enablePriorityBoost(bool enabled)
{
nlassert(ThreadHandle); // 'start' was not called !!
SetThreadPriorityBoost(ThreadHandle, enabled ? TRUE : FALSE);
}
CWinThread::~CWinThread ()
{
// If not the main thread
if (_MainThread)
{
// Free TLS memory
nlassert (TLSThreadPointer!=0xffffffff);
TlsFree (TLSThreadPointer);
}
else
{
if (ThreadHandle != NULL) terminate();
}
}
void CWinThread::start ()
{
if (isRunning())
throw EThread("Starting a thread that is already started, existing thread will continue running, this should not happen");
// ThreadHandle = (void *) ::CreateThread (NULL, _StackSize, ProxyFunc, this, 0, (DWORD *)&ThreadId);
ThreadHandle = (void *) ::CreateThread (NULL, 0, ProxyFunc, this, 0, (DWORD *)&ThreadId);
// nldebug("NLMISC: thread %x started for runnable '%x'", typeid( Runnable ).name());
// OutputDebugString(toString(NL_LOC_MSG " NLMISC: thread %x started for runnable '%s'\n", ThreadId, typeid( *Runnable ).name()).c_str());
SetThreadPriorityBoost (ThreadHandle, TRUE); // FALSE == Enable Priority Boost
if (ThreadHandle == NULL)
{
throw EThread ( "Cannot create new thread" );
}
_SuspendCount = 0;
}
bool CWinThread::isRunning()
{
if (ThreadHandle == NULL)
return false;
DWORD exitCode;
if (!GetExitCodeThread(ThreadHandle, &exitCode))
return false;
return exitCode == STILL_ACTIVE;
}
void CWinThread::terminate ()
{
TerminateThread((HANDLE)ThreadHandle, 0);
CloseHandle((HANDLE)ThreadHandle);
ThreadHandle = NULL;
_SuspendCount = -1;
}
void CWinThread::wait ()
{
if (ThreadHandle == NULL) return;
WaitForSingleObject(ThreadHandle, INFINITE);
CloseHandle(ThreadHandle);
ThreadHandle = NULL;
_SuspendCount = -1;
}
bool CWinThread::setCPUMask(uint64 cpuMask)
{
// Thread must exist
if (ThreadHandle == NULL)
return false;
// Ask the system for number of processor available for this process
return SetThreadAffinityMask ((HANDLE)ThreadHandle, (DWORD_PTR)cpuMask) != 0;
}
uint64 CWinThread::getCPUMask()
{
// Thread must exist
if (ThreadHandle == NULL)
return 1;
// Get the current process mask
uint64 mask=IProcess::getCurrentProcess ()->getCPUMask ();
// Get thread affinity mask
DWORD_PTR old = SetThreadAffinityMask ((HANDLE)ThreadHandle, (DWORD_PTR)mask);
nlassert (old != 0);
if (old == 0)
return 1;
// Reset it
SetThreadAffinityMask ((HANDLE)ThreadHandle, old);
// Return the mask
return (uint64)old;
}
std::string CWinThread::getUserName()
{
char userName[512];
DWORD size = 512;
GetUserName (userName, &size);
return (const char*)userName;
}
// **** Process
// The current process
CWinProcess CurrentProcess ((void*)GetCurrentProcess());
// Get the current process
IProcess *IProcess::getCurrentProcess ()
{
return &CurrentProcess;
}
CWinProcess::CWinProcess (void *handle)
{
// Get the current process handle
_ProcessHandle = handle;
}
uint64 CWinProcess::getCPUMask()
{
// Ask the system for number of processor available for this process
DWORD_PTR processAffinityMask;
DWORD_PTR systemAffinityMask;
if (GetProcessAffinityMask((HANDLE)_ProcessHandle, &processAffinityMask, &systemAffinityMask))
{
// Return the CPU mask
return (uint64)processAffinityMask;
}
else
return 1;
}
bool CWinProcess::setCPUMask(uint64 mask)
{
// Ask the system for number of processor available for this process
DWORD_PTR processAffinityMask= (DWORD_PTR)mask;
return SetProcessAffinityMask((HANDLE)_ProcessHandle, processAffinityMask)!=0;
}
// ****************************************************************************************************************
/**
* Simple wrapper around the PSAPI library
* \author Nicolas Vizerie
* \author GameForge
* \date 2007
*/
class CPSAPILib
{
public:
typedef BOOL (WINAPI *EnumProcessesFunPtr)(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded);
typedef DWORD (WINAPI *GetModuleFileNameExAFunPtr)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
typedef BOOL (WINAPI *EnumProcessModulesFunPtr)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);
EnumProcessesFunPtr EnumProcesses;
GetModuleFileNameExAFunPtr GetModuleFileNameExA;
EnumProcessModulesFunPtr EnumProcessModules;
public:
CPSAPILib();
~CPSAPILib();
bool init();
private:
HINSTANCE _PSAPILibHandle;
bool _LoadFailed;
};
// ****************************************************************************************************************
CPSAPILib::CPSAPILib()
{
_LoadFailed = false;
_PSAPILibHandle = NULL;
EnumProcesses = NULL;
GetModuleFileNameExA = NULL;
EnumProcessModules = NULL;
}
// ****************************************************************************************************************
CPSAPILib::~CPSAPILib()
{
if (_PSAPILibHandle)
{
FreeLibrary(_PSAPILibHandle);
}
}
// ****************************************************************************************************************
bool CPSAPILib::init()
{
//
if (_LoadFailed) return false;
if (!_PSAPILibHandle)
{
_PSAPILibHandle = LoadLibrary("psapi.dll");
if (!_PSAPILibHandle)
{
nlwarning("couldn't load psapi.dll, possibly not supported by os");
_LoadFailed = true;
return false;
}
EnumProcesses = (EnumProcessesFunPtr) GetProcAddress(_PSAPILibHandle, "EnumProcesses");
GetModuleFileNameExA = (GetModuleFileNameExAFunPtr) GetProcAddress(_PSAPILibHandle, "GetModuleFileNameExA");
EnumProcessModules = (EnumProcessModulesFunPtr) GetProcAddress(_PSAPILibHandle, "EnumProcessModules");
if (!EnumProcesses ||
!GetModuleFileNameExA ||
!EnumProcessModules
)
{
nlwarning("Failed to import functions from psapi.dll!");
_LoadFailed = true;
return false;
}
}
return true;
}
static CPSAPILib PSAPILib;
// ****************************************************************************************************************
bool CWinProcess::enumProcessesId(std::vector<uint32> &processesId)
{
if (!PSAPILib.init()) return false;
// list of processes
std::vector<uint32> prcIds(16);
for (;;)
{
DWORD cbNeeded;
if (!PSAPILib.EnumProcesses((DWORD *) &prcIds[0], (DWORD)(prcIds.size() * sizeof(DWORD)), &cbNeeded))
{
nlwarning("Processes enumeration failed!");
return false;
}
if (cbNeeded < prcIds.size() * sizeof(DWORD))
{
prcIds.resize(cbNeeded / sizeof(DWORD));
break;
}
// make some more room
prcIds.resize(prcIds.size() * 2);
}
processesId.swap(prcIds);
return true;
}
// ****************************************************************************************************************
bool CWinProcess::enumProcessModules(uint32 processId, std::vector<std::string> &moduleNames)
{
if (!PSAPILib.init()) return false;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, (DWORD) processId);
if (!hProcess) return false;
// list of modules
std::vector<HMODULE> prcModules(2);
for (;;)
{
DWORD cbNeeded;
if (!PSAPILib.EnumProcessModules(hProcess, (HMODULE *) &prcModules[0], (DWORD)(prcModules.size() * sizeof(HMODULE)), &cbNeeded))
{
//nlwarning("Processe modules enumeration failed!");
return false;
}
if (cbNeeded < prcModules.size() * sizeof(HMODULE))
{
prcModules.resize(cbNeeded / sizeof(HMODULE));
break;
}
// make some more room
prcModules.resize(prcModules.size() * 2);
}
moduleNames.clear();
std::vector<std::string> resultModuleNames;
char moduleName[MAX_PATH + 1];
for (uint m = 0; m < prcModules.size(); ++m)
{
if (PSAPILib.GetModuleFileNameExA(hProcess, prcModules[m], moduleName, MAX_PATH))
{
moduleNames.push_back(moduleName);
}
}
CloseHandle(hProcess);
return true;
}
// ****************************************************************************************************************
uint32 CWinProcess::getProcessIdFromModuleFilename(const std::string &moduleFileName)
{
std::vector<uint32> processesId;
if (!enumProcessesId(processesId)) return false;
std::vector<std::string> moduleNames;
for (uint prc = 0; prc < processesId.size(); ++prc)
{
if (enumProcessModules(processesId[prc], moduleNames))
{
for (uint m = 0; m < moduleNames.size(); ++m)
{
if (nlstricmp(CFile::getFilename(moduleNames[m]), moduleFileName) == 0)
{
return processesId[prc];
}
}
}
}
return 0;
}
// ****************************************************************************************************************
bool CWinProcess::terminateProcess(uint32 processId, uint exitCode)
{
if (!processId) return false;
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD) processId);
if (!hProcess) return false;
BOOL ok = TerminateProcess(hProcess, (UINT) exitCode);
CloseHandle(hProcess);
return ok != FALSE;
}
// ****************************************************************************************************************
bool CWinProcess::terminateProcessFromModuleName(const std::string &moduleName, uint exitCode)
{
return terminateProcess(getProcessIdFromModuleFilename(moduleName), exitCode);
}
///////////////////
// CProcessWatch //
///////////////////
/*
// I didn't use and test that code, eventually, but maybe useful in the future
class CProcessWatchTask : public IRunnable
{
public:
HANDLE HProcess;
public:
CProcessWatchTask(HANDLE hProcess) : HProcess(hProcess)
{
}
virtual void run()
{
WaitForSingleObject(HProcess, INFINITE);
}
};
class CProcessWatchImpl
{
public:
bool Launched;
IThread *WatchThread;
CProcessWatchTask *WatchTask;
public:
CProcessWatchImpl() : Launched(false), WatchThread(NULL), WatchTask(NULL)
{
}
~CProcessWatchImpl()
{
reset();
}
void reset()
{
if (WatchThread)
{
if (WatchThread->isRunning())
{
WatchThread->terminate();
}
delete WatchTask;
delete WatchThread;
WatchTask = NULL;
WatchThread = NULL;
Launched = false;
}
}
bool launch(const std::string &programName, const std::string &arguments)
{
if (isRunning()) return false;
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo = {0};
startupInfo.cb = sizeof(STARTUPINFO);
if (CreateProcess(programName.c_str(), const_cast<LPTSTR>(arguments.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))
{
WatchTask = new CProcessWatchTask(processInfo.hProcess);
WatchThread = IThread::create(WatchTask);
WatchThread->start();
Launched = true;
return true;
}
return false;
}
bool isRunning()
{
if (!Launched) return false;
nlassert(WatchThread);
nlassert(WatchTask);
if (WatchThread->isRunning()) return true;
reset();
return false;
}
};
CProcessWatch::CProcessWatch()
{
_PImpl = new CProcessWatchImpl;
}
CProcessWatch::~CProcessWatch()
{
delete _PImpl;
}
bool CProcessWatch::launch(const std::string &programName, const std::string &arguments)
{
return _PImpl->launch(programName, arguments);
}
bool CProcessWatch::isRunning() const
{
return _PImpl->isRunning();
}
*/
} // NLMISC
#endif // NL_OS_WINDOWS

@ -109,7 +109,7 @@ void CWindowDisplayer::setLabel (uint label, const string &value)
void CWindowDisplayer::create (string windowNameEx, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log)
{
nlassert (_Thread == NULL);
_Thread = IThread::create (new CUpdateThread(this, windowNameEx, iconified, x, y, w, h, hs, fs, fn, ww, log));
_Thread = new CThread (new CUpdateThread(this, windowNameEx, iconified, x, y, w, h, hs, fs, fn, ww, log));
Log = log;

@ -99,7 +99,7 @@ void CBufClient::connect( const CInetAddress& addr )
delete _RecvThread;
}
_RecvThread = IThread::create( _RecvTask, 1024*4*4 );
_RecvThread = new CThread( _RecvTask );
_RecvThread->start();
}

@ -77,7 +77,7 @@ CBufServer::CBufServer( TThreadStategy strategy,
if ( ! _ReplayMode )
{
_ListenTask = new CListenTask( this );
_ListenThread = IThread::create( _ListenTask, 1024*4*4 );
_ListenThread = new CThread( _ListenTask );
}
/*{
CSynchronized<uint32>::CAccessor syncbpi ( &_BytesPushedIn );
@ -949,7 +949,7 @@ void CBufServer::addNewThread( CThreadPool& threadpool, CServerBufSock *bufsock
task->addNewSocket( bufsock );
// Add a new thread to the pool, with this task
IThread *thr = IThread::create( task, 1024*4*4 );
CThread *thr = new CThread( task );
{
threadpool.push_back( thr );
thr->start();

@ -560,7 +560,7 @@ sint IService::main (const char *serviceShortName, const char *serviceLongName,
bool userInitCalled = false;
CConfigFile::CVar *var = NULL;
IThread *timeoutThread = NULL;
CThread *timeoutThread = NULL;
// a short name service can't be a number
uint tmp;
@ -1266,7 +1266,7 @@ sint IService::main (const char *serviceShortName, const char *serviceLongName,
// Activate the timeout assertion thread
//
timeoutThread = IThread::create(&MyTAT, 1024*4);
timeoutThread = new CThread(&MyTAT);
timeoutThread->start();
//

@ -162,7 +162,7 @@ namespace NLNET
private:
// data for the singleton instance
CStdinMonitorThread* _StdinMonitorThreadInstance;
NLMISC::IThread* _StdinMonitorThreadHandle;
NLMISC::CThread* _StdinMonitorThreadHandle;
};
@ -191,7 +191,7 @@ namespace NLNET
void CStdinMonitorSingleton::init()
{
_StdinMonitorThreadInstance= new CStdinMonitorThread;
_StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance, 1024*4*4);
_StdinMonitorThreadHandle = new NLMISC::CThread (_StdinMonitorThreadInstance);
_StdinMonitorThreadHandle->start();
}
@ -219,7 +219,7 @@ namespace NLNET
return;
// terminate the thread and wait for it to finish
_StdinMonitorThreadHandle->terminate();
// _StdinMonitorThreadHandle->terminate(); // FIXME: TERMINATE...
_StdinMonitorThreadHandle->wait();
// destroy the thread object instance and reset the pointer to NULL to mark as 'uninitialised'

@ -450,7 +450,7 @@ public:
};
CAliveCheck* CAliveCheck::Thread = NULL;
IThread* AliveThread = NULL;
CThread* AliveThread = NULL;
void CAliveCheck::run()
@ -631,7 +631,7 @@ bool CUnifiedNetwork::init(const CInetAddress *addr, CCallbackNetBase::TRecordin
nlinfo ("HNETL5: Server '%s' added, registered and listen to port %hu", _Name.c_str (), _ServerPort);
}
AliveThread = IThread::create(new CAliveCheck(), 1024*4);
AliveThread = new CThread(new CAliveCheck());
AliveThread->start();
_Initialised = true;

@ -47,7 +47,7 @@ namespace NLSOUND {
CStreamFileSource::CStreamFileSource(CStreamFileSound *streamFileSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CStreamSource(streamFileSound, spawn, cb, cbUserParam, cluster, groupController), m_AudioDecoder(NULL), m_Paused(false)
{
m_Thread = NLMISC::IThread::create(this);
m_Thread = new NLMISC::CThread(this);
}
CStreamFileSource::~CStreamFileSource()
@ -121,7 +121,7 @@ void CStreamFileSource::play()
// else load audiodecoder in thread
m_WaitingForPlay = true;
m_Thread->start();
m_Thread->setPriority(NLMISC::ThreadPriorityHighest);
m_Thread->setPriority(NLMISC::ThreadPriorityHigh);
if (!getStreamFileSound()->getAsync())
{
// wait until at least one buffer is ready
@ -304,6 +304,8 @@ inline bool CStreamFileSource::bufferMore(uint bytes) // buffer from bytes (mini
void CStreamFileSource::run()
{
NLMISC::CThread::setPriority(NLMISC::ThreadPriorityHigh);
#ifdef NLSOUND_STREAM_FILE_DEBUG
nldebug("run %s", getStreamFileSound()->getFilePath().c_str());
uint dumpI = 0;

@ -127,7 +127,7 @@ void CMakeLogTask::start()
}
_Stopping = false;
_Complete = false;
_Thread = NLMISC::IThread::create( this );
_Thread = new NLMISC::CThread( this );
_OutputLogReport = new CLogReport();
_Thread->start();
}

@ -92,7 +92,7 @@ private:
std::string _LogTarget;
std::vector<std::string> _LogPaths;
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
CLogReport *_OutputLogReport;
};

@ -21,15 +21,12 @@
//
#include "nel/misc/shared_memory.h"
#include "nel/misc/i18n.h"
#include "nel/misc/win_thread.h"
#include "nel/misc/big_file.h"
//
#include "game_share/bg_downloader_msg.h"
#ifdef NL_OS_WINDOWS
#include "nel/misc/win_thread.h"
#if 0
using namespace BGDownloader;
using namespace NLMISC;

@ -378,37 +378,11 @@ void outOfMemory()
nlstopex (("OUT OF MEMORY"));
}
// For multi cpu, active only one CPU for the main thread
uint64 Debug_OldCPUMask= 0;
uint64 Debug_NewCPUMask= 0;
void setCPUMask ()
{
uint64 cpuMask = IProcess::getCurrentProcess ()->getCPUMask();
Debug_OldCPUMask= cpuMask;
// get the processor to allow process
uint i = 0;
while ((i<64) && ((cpuMask&(SINT64_CONSTANT(1)<<i)) == 0))
i++;
// Set the CPU mask
if (i<64)
{
IProcess::getCurrentProcess ()->setCPUMask(1<<i);
//IThread::getCurrentThread ()->setCPUMask (1<<i);
}
// check
cpuMask = IProcess::getCurrentProcess ()->getCPUMask();
Debug_NewCPUMask= cpuMask;
}
string getVersionString (uint64 version)
{
return toString ("%u.%u.%u.%u", (unsigned int) (version >> 48), (unsigned int) ((version >> 32) & 0xffff), (unsigned int) ((version >> 16) & 0xffff), (unsigned int) (version & 0xffff));
}
string getSystemInformation()
{
string s;
@ -742,8 +716,6 @@ void prelogInit()
CTime::CTimerInfo timerInfo;
NLMISC::CTime::probeTimerInfo(timerInfo);
if (timerInfo.RequiresSingleCore) // TODO: Also have a FV configuration value to force single core.
setCPUMask();
FPU_CHECKER_ONCE
@ -963,9 +935,11 @@ void prelogInit()
CLoginProgressPostThread::getInstance().step(CLoginStep(LoginStep_VideoModeSetupHighColor, "login_step_video_mode_setup_high_color"));
#ifdef NL_OS_WINDOWS
#if 0
CBGDownloaderAccess::getInstance().init();
#endif
#ifdef NL_OS_WINDOWS
if (SlashScreen)
DestroyWindow (SlashScreen);

@ -299,7 +299,7 @@ void startStatThread()
curl_global_init(CURL_GLOBAL_ALL);
//nlinfo("startStatThread");
CStatThread *statThread = new CStatThread();
IThread *thread = IThread::create (statThread);
CThread *thread = new CThread (statThread);
nlassert (thread != NULL);
thread->start ();
}

@ -274,7 +274,7 @@ void startWebigNotificationThread()
curl_global_init(CURL_GLOBAL_ALL);
//nlinfo("startStatThread");
CWebigNotificationThread *webigThread = new CWebigNotificationThread();
IThread *thread = IThread::create (webigThread);
CThread *thread = new CThread (webigThread);
nlassert (thread != NULL);
thread->start ();
startedWebigNotificationThread = true;

@ -467,7 +467,7 @@ void loginMainLoop()
if (isBGDownloadEnabled())
{
AvailablePatchs = bgDownloader.getAvailablePatchs();
#ifdef NL_OS_WINDOWS
#if 0
{
// Get the window
HWND hWnd = Driver->getDisplay();

@ -404,7 +404,7 @@ void CPatchManager::startCheckThread(bool includeBackgroundPatch)
CheckThread = new CCheckThread(includeBackgroundPatch);
nlassert (CheckThread != NULL);
thread = IThread::create (CheckThread);
thread = new CThread (CheckThread);
nlassert (thread != NULL);
thread->start ();
}
@ -651,7 +651,7 @@ void CPatchManager::startPatchThread(const vector<string> &CategoriesSelected, b
}
// Launch the thread
thread = IThread::create (PatchThread);
thread = new CThread (PatchThread);
nlassert (thread != NULL);
thread->start ();
}
@ -1986,7 +1986,7 @@ void CPatchManager::startScanDataThread()
ScanDataThread = new CScanDataThread();
nlassert (ScanDataThread != NULL);
thread = IThread::create (ScanDataThread);
thread = new CThread (ScanDataThread);
nlassert (thread != NULL);
thread->start ();
}
@ -3259,7 +3259,7 @@ IAsyncDownloader* CPatchManager::getAsyncDownloader() const
void CPatchManager::startInstallThread(const std::vector<CInstallThreadEntry>& entries)
{
CInstallThread* installThread = new CInstallThread(entries);
thread = IThread::create (installThread);
thread = new CThread (installThread);
nlassert (thread != NULL);
thread->start ();
}
@ -3267,7 +3267,7 @@ void CPatchManager::startInstallThread(const std::vector<CInstallThreadEntry>& e
void CPatchManager::startDownloadThread(const std::vector<CInstallThreadEntry>& entries)
{
CDownloadThread* downloadThread = new CDownloadThread(entries);
thread = IThread::create (downloadThread);
thread = new CThread (downloadThread);
nlassert (thread != NULL);
thread->start ();
}

@ -245,7 +245,7 @@ public:
CProductDescriptionForClient &getDescFile() { return DescFile; }
NLMISC::IThread *getCurrThread() const { return thread; }
NLMISC::CThread *getCurrThread() const { return thread; }
// set an external state listener (enable to log) infos
void setStateListener(IPatchManagerStateListener* stateListener);
@ -422,7 +422,7 @@ private:
CCheckThread *CheckThread;
CScanDataThread *ScanDataThread;
CInstallThread *InstallThread;
NLMISC::IThread *thread;
NLMISC::CThread *thread;
// State
struct CState

@ -296,7 +296,7 @@ void CLoginProgressPostThread::init(const std::string &startupHost, const std::s
lpt->StartupHost = startupHost;
lpt->StartupPage = startupPage;
_Task = lpt;
_Thread = IThread::create(lpt);
_Thread = new CThread(lpt);
if (!_Thread)
{
release();

@ -69,7 +69,7 @@ public:
// Send the msg (wait until the message is send) return the answer string
std::string forceStep(const CLoginStep &ls);
private:
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
NLMISC::IRunnable *_Task;
};

@ -107,7 +107,7 @@ CSessionBrowser::CSessionBrowser()
_WaitingForMessage(false)
{
// start the comm thread
_CommThread = IThread::create(this);
_CommThread = new CThread(this);
_CommThread->start();
}

@ -47,7 +47,7 @@ class CSessionBrowser : public RSMGR::CSessionBrowserServerWebClientItf,
friend class CCallbackClientAdaptor;
// the comm thread object
NLMISC::IThread *_CommThread;
NLMISC::CThread *_CommThread;
// the thread termination flag
bool _TerminateComm;

@ -3027,7 +3027,7 @@ void audit(const CAdminCommand *cmd, const string &rawCommand, const CEntityId &
char params[1024];
sprintf(params, "action=audit&cmd=%s&raw=%s&name=(%s,%s)&target=%s", cmd->Name.c_str(), rawCommand.c_str(), eid.toString().c_str(), name.c_str(), targetName.c_str());
IThread *thread = IThread::create(new CHttpPostTask(host, page, params));
CThread *thread = new CThread(new CHttpPostTask(host, page, params));
thread->start();
}

@ -1806,7 +1806,7 @@ public:
return;
_Stopping = false;
_Complete = false;
_Thread = NLMISC::IThread::create( this );
_Thread = new NLMISC::CThread( this );
_Thread->start();
}
@ -1842,7 +1842,7 @@ private:
volatile bool _Stopping;
volatile bool _Complete;
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
};

@ -129,7 +129,7 @@ void CFeReceiveSub::init( uint16 firstAcceptableFrontendPort, uint16 lastAccepta
_CurrentReadQueue = &_Queue2;
_ReceiveTask->setWriteQueue( &_Queue1 );
nlassert( _ReceiveTask != NULL );
_ReceiveThread = IThread::create( _ReceiveTask );
_ReceiveThread = new CThread( _ReceiveTask );
nlassert( _ReceiveThread != NULL );
_ReceiveThread->start();

@ -212,7 +212,7 @@ private:
CFEReceiveTask *_ReceiveTask;
/// Receive thread
NLMISC::IThread *_ReceiveThread;
NLMISC::CThread *_ReceiveThread;
/// Client map by address
THostMap _ClientMap;

@ -257,7 +257,7 @@ public:
};
CSendRunnable SendTask;
IThread* SendThread = NULL;
CThread* SendThread = NULL;
/*
* Receive task
@ -1323,7 +1323,7 @@ void CFrontEndService::init()
{
// Init send thread
nlinfo("UseSendThread on, initialise send thread");
SendThread = IThread::create(&SendTask);
SendThread = new CThread(&SendTask);
SendThread->start();
}

@ -59,7 +59,7 @@ CModuleManager::~CModuleManager()
if (_Thread != NULL)
{
nlwarning("FEMMAN: [%s] Execution is not finished yet. Brutal thread killing", _StackName.c_str());
_Thread->terminate();
_Thread->wait(); // _Thread->terminate(); // FIXME: THREAD: Have a proper way to kill this thread
delete _Thread;
}
}
@ -207,7 +207,7 @@ void CModuleManager::addWait(uint id)
void CModuleManager::start()
{
_Thread = IThread::create(this);
_Thread = new CThread(this);
_StopThread = false;
_ThreadStopped = false;
@ -284,7 +284,7 @@ void CModuleManager::stop(bool blockingMode, TTime timeout)
if (!_ThreadStopped)
{
nlwarning("FEMMAN: [%s] Can't stop. Brutal thread killing", _StackName.c_str());
_Thread->terminate();
_Thread->wait(); // _Thread->terminate(); // FIXME: THREAD: Have a proper way to kill this thread
}
delete _Thread;

@ -90,7 +90,7 @@ private:
/// The thread associated to this manager
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
/// @name The stop flags
//@{

@ -133,7 +133,7 @@ public:
private:
CStdinMonitorThread* _StdinMonitorThreadInstance;
NLMISC::IThread* _StdinMonitorThreadHandle;
NLMISC::CThread* _StdinMonitorThreadHandle;
};
CStdinMonitorSingleton StdinMonitorSingleton;
@ -146,7 +146,7 @@ CStdinMonitorSingleton StdinMonitorSingleton;
void CStdinMonitorSingleton::init()
{
_StdinMonitorThreadInstance= new CStdinMonitorThread;
_StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance);
_StdinMonitorThreadHandle = new NLMISC::CThread (_StdinMonitorThreadInstance);
_StdinMonitorThreadHandle->start();
}
@ -161,6 +161,6 @@ void CStdinMonitorSingleton::serviceUpdate()
void CStdinMonitorSingleton::release()
{
_StdinMonitorThreadHandle->terminate();
_StdinMonitorThreadHandle->wait(); // _StdinMonitorThreadHandle->terminate(); // FIXME: THREAD: Have a proper way to kill this thread
}

@ -215,7 +215,7 @@ bool CLogAnalyserService::update()
LogTask.Query = _Current;
_Thread = IThread::create(&LogTask);
_Thread = new CThread(&LogTask);
_Thread->start();
}
_Mutex.leave();

@ -105,7 +105,7 @@ private:
NLMISC::CMutex _Mutex;
NLMISC::IThread* _Thread;
NLMISC::CThread* _Thread;
CQuery* _Current;

@ -390,7 +390,7 @@ class CLoggerServiceMod
friend class CLoggerServiceMod::CQueryThread;
/// the query thread
IThread *_QueryThread;
CThread *_QueryThread;
@ -430,7 +430,7 @@ public:
consolidatePreviousFiles();
// start the query thread
_QueryThread = IThread::create(new CQueryThread(this));
_QueryThread = new CThread(new CQueryThread(this));
_QueryThread->start();
return true;

@ -338,7 +338,7 @@ void CReferenceBuilderService::killTasks(TServiceId serviceId)
void IRefTask::start()
{
_Thread = IThread::create(this);
_Thread = new CThread(this);
_Thread->start();
}

@ -75,7 +75,7 @@ public:
private:
NLMISC::IThread *_Thread;
NLMISC::CThread *_Thread;
};

Loading…
Cancel
Save