This commit is contained in:
kaetemi 2012-04-12 00:28:10 +02:00
commit 4ac6c26dfd
10 changed files with 124 additions and 35 deletions

View file

@ -36,6 +36,12 @@ namespace NLMISC {
class CPThread : public IThread class CPThread : public IThread
{ {
public: public:
enum TThreadState
{
ThreadStateNone,
ThreadStateRunning,
ThreadStateFinished,
};
/// Constructor /// Constructor
CPThread( IRunnable *runnable, uint32 stackSize); CPThread( IRunnable *runnable, uint32 stackSize);
@ -59,10 +65,11 @@ public:
/// Internal use /// Internal use
IRunnable *Runnable; IRunnable *Runnable;
private: TThreadState _State;
uint8 _State; // 0=not created, 1=started, 2=finished
uint32 _StackSize;
pthread_t _ThreadHandle; pthread_t _ThreadHandle;
private:
uint32 _StackSize;
}; };
/** /**

View file

@ -52,7 +52,7 @@ namespace NLSOUND {
class CGroupController : public UGroupController class CGroupController : public UGroupController
{ {
public: public:
friend CGroupControllerRoot; friend class CGroupControllerRoot;
private: private:
CGroupController *m_Parent; CGroupController *m_Parent;

View file

@ -48,7 +48,7 @@ namespace NLSOUND {
class CStreamFileSound : public CStreamSound class CStreamFileSound : public CStreamSound
{ {
public: public:
friend CSourceMusicChannel; friend class CSourceMusicChannel;
public: public:
CStreamFileSound(); CStreamFileSound();

View file

@ -18,7 +18,11 @@
// STL includes // STL includes
#include <stdio.h> #include <stdio.h>
#include <conio.h> #ifdef NL_OS_WINDOWS
# include <conio.h>
#else
# include <curses.h>
#endif
// NeL includes // NeL includes
#include <nel/misc/app_context.h> #include <nel/misc/app_context.h>
@ -110,9 +114,16 @@ static void runSample()
printf("Press ANY other key to exit\n"); printf("Press ANY other key to exit\n");
for (; ; ) for (; ; )
{ {
#ifdef NL_OS_WINDOWS
if (_kbhit()) if (_kbhit())
{ {
switch (_getch()) switch (_getch())
#else
char ch;
if (read(0, &ch, 1))
{
switch (ch)
#endif
{ {
case '+': case '+':
s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f);

View file

@ -18,7 +18,11 @@
// STL includes // STL includes
#include <stdio.h> #include <stdio.h>
#include <conio.h> #ifdef NL_OS_WINDOWS
# include <conio.h>
#else
# include <curses.h>
#endif
// NeL includes // NeL includes
#include <nel/misc/app_context.h> #include <nel/misc/app_context.h>
@ -138,9 +142,16 @@ static void runSample()
printf("Press ANY other key to exit\n"); printf("Press ANY other key to exit\n");
while (!s_AudioDecoder->isMusicEnded()) while (!s_AudioDecoder->isMusicEnded())
{ {
#ifdef NL_OS_WINDOWS
if (_kbhit()) if (_kbhit())
{ {
switch (_getch()) switch (_getch())
#else
char ch;
if (read(0, &ch, 1))
{
switch (ch)
#endif
{ {
case '+': case '+':
s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f);
@ -172,7 +183,13 @@ static void runSample()
printf("End of song\n"); printf("End of song\n");
printf("Press ANY key to exit\n"); printf("Press ANY key to exit\n");
while (!_kbhit()) { s_AudioMixer->update(); nlSleep(10); } _getch(); #ifdef NL_OS_WINDOWS
while (!_kbhit())
#else
char ch;
while (!read(0, &ch, 1))
#endif
{ s_AudioMixer->update(); nlSleep(10); }
return; return;
} }

View file

@ -84,6 +84,17 @@ static void *ProxyFunc( void *arg )
// Run the code of the thread // Run the code of the thread
parent->Runnable->run(); 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 // Allow some clean
// pthread_exit(0); // pthread_exit(0);
return NULL; return NULL;
@ -96,7 +107,7 @@ static void *ProxyFunc( void *arg )
*/ */
CPThread::CPThread(IRunnable *runnable, uint32 stackSize) CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
: Runnable(runnable), : Runnable(runnable),
_State(0), _State(ThreadStateNone),
_StackSize(stackSize) _StackSize(stackSize)
{} {}
@ -106,10 +117,9 @@ CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
*/ */
CPThread::~CPThread() CPThread::~CPThread()
{ {
if(_State == 1) terminate(); // force the end of the thread if not already ended
terminate(); // force the end of the thread if not already ended
if(_State > 0) if (_State != ThreadStateNone)
pthread_detach(_ThreadHandle); // free allocated resources only if it was created pthread_detach(_ThreadHandle); // free allocated resources only if it was created
} }
@ -119,26 +129,51 @@ CPThread::~CPThread()
void CPThread::start() void CPThread::start()
{ {
pthread_attr_t tattr; pthread_attr_t tattr;
pthread_t tid;
int ret; int ret;
/* initialized with default attributes */ if (_StackSize != 0)
ret = pthread_attr_init(&tattr); {
/* initialized with default attributes */
ret = pthread_attr_init(&tattr);
/* setting the size of the stack also */ /* setting the size of the stack also */
ret = pthread_attr_setstacksize(&tattr, _StackSize); ret = pthread_attr_setstacksize(&tattr, _StackSize);
}
if(pthread_create(&_ThreadHandle, _StackSize != 0 ? &tattr : 0, ProxyFunc, this) != 0) 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"); throw EThread("Cannot start new thread");
} }
_State = 1; _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() bool CPThread::isRunning()
{ {
// TODO : need a real implementation here that check thread status return _State == ThreadStateRunning;
return _State == 1;
} }
/* /*
@ -146,11 +181,11 @@ bool CPThread::isRunning()
*/ */
void CPThread::terminate() void CPThread::terminate()
{ {
if(_State == 1) if (_State == ThreadStateRunning)
{ {
// cancel only if started // cancel only if started
pthread_cancel(_ThreadHandle); pthread_cancel(_ThreadHandle);
_State = 2; // set to finished _State = ThreadStateFinished; // set to finished
} }
} }
@ -159,13 +194,24 @@ void CPThread::terminate()
*/ */
void CPThread::wait () void CPThread::wait ()
{ {
if(_State == 1) if (_State == ThreadStateRunning)
{ {
if(pthread_join(_ThreadHandle, 0) != 0) int error = pthread_join(_ThreadHandle, 0);
switch (error)
{ {
throw EThread( "Cannot join with thread" ); 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");
} }
_State = 2; // set to finished if(_State != ThreadStateFinished)
throw EThread("Thread did not finish, this should not happen");
} }
} }
@ -209,27 +255,29 @@ uint64 CPThread::getCPUMask()
void CPThread::setPriority(TThreadPriority priority) void CPThread::setPriority(TThreadPriority priority)
{ {
// TODO: Verify and test this // TODO: Test this
sched_param sp;
switch (priority) switch (priority)
{ {
case ThreadPriorityHigh: case ThreadPriorityHigh:
{ {
int minPrio = sched_get_priority_min(SCHED_FIFO); int minPrio = sched_get_priority_min(SCHED_FIFO);
int maxPrio = sched_get_priority_max(SCHED_FIFO); int maxPrio = sched_get_priority_max(SCHED_FIFO);
int prio = ((maxPrio - minPrio) / 4) + minPrio; sp.sched_priority = ((maxPrio - minPrio) / 4) + minPrio;
pthread_setschedparam(_ThreadHandle, SCHED_FIFO, prio); pthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);
break; break;
} }
case ThreadPriorityHighest: case ThreadPriorityHighest:
{ {
int minPrio = sched_get_priority_min(SCHED_FIFO); int minPrio = sched_get_priority_min(SCHED_FIFO);
int maxPrio = sched_get_priority_max(SCHED_FIFO); int maxPrio = sched_get_priority_max(SCHED_FIFO);
int prio = ((maxPrio - minPrio) / 2) + minPrio; sp.sched_priority = ((maxPrio - minPrio) / 2) + minPrio;
pthread_setschedparam(_ThreadHandle, SCHED_FIFO, prio); pthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);
break; break;
} }
default: default:
pthread_setschedparam(_ThreadHandle, SCHED_OTHER, 0); sp.sched_priority = 0;
pthread_setschedparam(_ThreadHandle, SCHED_OTHER, &sp);
} }
} }

View file

@ -190,6 +190,9 @@ CWinThread::~CWinThread ()
void CWinThread::start () 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, _StackSize, ProxyFunc, this, 0, (DWORD *)&ThreadId);
ThreadHandle = (void *) ::CreateThread (NULL, 0, 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()); // nldebug("NLMISC: thread %x started for runnable '%x'", typeid( Runnable ).name());

View file

@ -102,7 +102,7 @@ static ov_callbacks OV_CALLBACKS_NLMISC_STREAM = {
}; };
CAudioDecoderVorbis::CAudioDecoderVorbis(NLMISC::IStream *stream, bool loop) CAudioDecoderVorbis::CAudioDecoderVorbis(NLMISC::IStream *stream, bool loop)
: _Stream(stream), _Loop(loop), _StreamSize(0), _IsMusicEnded(false) : _Stream(stream), _Loop(loop), _IsMusicEnded(false), _StreamSize(0)
{ {
_StreamOffset = stream->getPos(); _StreamOffset = stream->getPos();
stream->seek(0, NLMISC::IStream::end); stream->seek(0, NLMISC::IStream::end);

View file

@ -3,6 +3,8 @@ FILE(GLOB HEADERS ../../../include/nel/sound/driver/*.h)
NL_TARGET_LIB(nelsnd_lowlevel ${HEADERS} ${SRC}) NL_TARGET_LIB(nelsnd_lowlevel ${HEADERS} ${SRC})
TARGET_LINK_LIBRARIES(nelsnd_lowlevel nelmisc)
SET_TARGET_PROPERTIES(nelsnd_lowlevel PROPERTIES LINK_INTERFACE_LIBRARIES "") SET_TARGET_PROPERTIES(nelsnd_lowlevel PROPERTIES LINK_INTERFACE_LIBRARIES "")
NL_DEFAULT_PROPS(nelsnd_lowlevel "NeL, Library: Sound Lowlevel") NL_DEFAULT_PROPS(nelsnd_lowlevel "NeL, Library: Sound Lowlevel")
NL_ADD_RUNTIME_FLAGS(nelsnd_lowlevel) NL_ADD_RUNTIME_FLAGS(nelsnd_lowlevel)

View file

@ -87,7 +87,8 @@ std::string CGroupController::getPath() // overridden by root
return returnPath; return returnPath;
} }
} }
nlerror("Group Controller not child of parent");
return "";
} }
void CGroupController::calculateFinalGain() // overridden by root void CGroupController::calculateFinalGain() // overridden by root