diff --git a/code/nel/include/nel/misc/p_thread.h b/code/nel/include/nel/misc/p_thread.h index 82f6a4ee3..7e6a4d5a5 100644 --- a/code/nel/include/nel/misc/p_thread.h +++ b/code/nel/include/nel/misc/p_thread.h @@ -36,6 +36,12 @@ namespace NLMISC { class CPThread : public IThread { public: + enum TThreadState + { + ThreadStateNone, + ThreadStateRunning, + ThreadStateFinished, + }; /// Constructor CPThread( IRunnable *runnable, uint32 stackSize); @@ -59,10 +65,11 @@ public: /// Internal use IRunnable *Runnable; -private: - uint8 _State; // 0=not created, 1=started, 2=finished - uint32 _StackSize; + TThreadState _State; pthread_t _ThreadHandle; + +private: + uint32 _StackSize; }; /** diff --git a/code/nel/include/nel/sound/group_controller.h b/code/nel/include/nel/sound/group_controller.h index c3ac4838f..08d474129 100644 --- a/code/nel/include/nel/sound/group_controller.h +++ b/code/nel/include/nel/sound/group_controller.h @@ -52,7 +52,7 @@ namespace NLSOUND { class CGroupController : public UGroupController { public: - friend CGroupControllerRoot; + friend class CGroupControllerRoot; private: CGroupController *m_Parent; diff --git a/code/nel/include/nel/sound/stream_file_sound.h b/code/nel/include/nel/sound/stream_file_sound.h index 2429c3382..8c1cc1634 100644 --- a/code/nel/include/nel/sound/stream_file_sound.h +++ b/code/nel/include/nel/sound/stream_file_sound.h @@ -48,7 +48,7 @@ namespace NLSOUND { class CStreamFileSound : public CStreamSound { public: - friend CSourceMusicChannel; + friend class CSourceMusicChannel; public: CStreamFileSound(); diff --git a/code/nel/samples/sound/stream_file/stream_file.cpp b/code/nel/samples/sound/stream_file/stream_file.cpp index 6ded512eb..14314c16d 100644 --- a/code/nel/samples/sound/stream_file/stream_file.cpp +++ b/code/nel/samples/sound/stream_file/stream_file.cpp @@ -18,7 +18,11 @@ // STL includes #include -#include +#ifdef NL_OS_WINDOWS +# include +#else +# include +#endif // NeL includes #include @@ -110,9 +114,16 @@ static void runSample() printf("Press ANY other key to exit\n"); for (; ; ) { +#ifdef NL_OS_WINDOWS if (_kbhit()) { switch (_getch()) +#else + char ch; + if (read(0, &ch, 1)) + { + switch (ch) +#endif { case '+': s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); diff --git a/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp b/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp index 2709a0b81..b3645913c 100644 --- a/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp +++ b/code/nel/samples/sound/stream_ogg_vorbis/stream_ogg_vorbis.cpp @@ -18,7 +18,11 @@ // STL includes #include -#include +#ifdef NL_OS_WINDOWS +# include +#else +# include +#endif // NeL includes #include @@ -138,9 +142,16 @@ static void runSample() printf("Press ANY other key to exit\n"); while (!s_AudioDecoder->isMusicEnded()) { +#ifdef NL_OS_WINDOWS if (_kbhit()) { switch (_getch()) +#else + char ch; + if (read(0, &ch, 1)) + { + switch (ch) +#endif { case '+': s_GroupController->setUserGain(s_GroupController->getUserGain() + 0.1f); @@ -172,7 +183,13 @@ static void runSample() printf("End of song\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; } diff --git a/code/nel/src/misc/p_thread.cpp b/code/nel/src/misc/p_thread.cpp index e20981c98..f752f4bdf 100644 --- a/code/nel/src/misc/p_thread.cpp +++ b/code/nel/src/misc/p_thread.cpp @@ -84,6 +84,17 @@ static void *ProxyFunc( void *arg ) // 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; @@ -96,7 +107,7 @@ static void *ProxyFunc( void *arg ) */ CPThread::CPThread(IRunnable *runnable, uint32 stackSize) : Runnable(runnable), - _State(0), + _State(ThreadStateNone), _StackSize(stackSize) {} @@ -106,10 +117,9 @@ CPThread::CPThread(IRunnable *runnable, uint32 stackSize) */ 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 } @@ -119,26 +129,51 @@ CPThread::~CPThread() void CPThread::start() { pthread_attr_t tattr; - pthread_t tid; int ret; - /* initialized with default attributes */ - ret = pthread_attr_init(&tattr); + 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); + /* 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 : 0, ProxyFunc, this) != 0) + if (pthread_create(&_ThreadHandle, _StackSize != 0 ? &tattr : NULL, ProxyFunc, this) != 0) { 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() { - // TODO : need a real implementation here that check thread status - return _State == 1; + return _State == ThreadStateRunning; } /* @@ -146,11 +181,11 @@ bool CPThread::isRunning() */ void CPThread::terminate() { - if(_State == 1) + if (_State == ThreadStateRunning) { // cancel only if started pthread_cancel(_ThreadHandle); - _State = 2; // set to finished + _State = ThreadStateFinished; // set to finished } } @@ -159,13 +194,24 @@ void CPThread::terminate() */ 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) { - // TODO: Verify and test this + // 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); - int prio = ((maxPrio - minPrio) / 4) + minPrio; - pthread_setschedparam(_ThreadHandle, SCHED_FIFO, prio); + 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); - int prio = ((maxPrio - minPrio) / 2) + minPrio; - pthread_setschedparam(_ThreadHandle, SCHED_FIFO, prio); + sp.sched_priority = ((maxPrio - minPrio) / 2) + minPrio; + pthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp); break; } default: - pthread_setschedparam(_ThreadHandle, SCHED_OTHER, 0); + sp.sched_priority = 0; + pthread_setschedparam(_ThreadHandle, SCHED_OTHER, &sp); } } diff --git a/code/nel/src/misc/win_thread.cpp b/code/nel/src/misc/win_thread.cpp index f8a961a74..c9bfc90a1 100644 --- a/code/nel/src/misc/win_thread.cpp +++ b/code/nel/src/misc/win_thread.cpp @@ -190,6 +190,9 @@ CWinThread::~CWinThread () 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()); diff --git a/code/nel/src/sound/audio_decoder_vorbis.cpp b/code/nel/src/sound/audio_decoder_vorbis.cpp index c54ce0ade..e0b950fc4 100644 --- a/code/nel/src/sound/audio_decoder_vorbis.cpp +++ b/code/nel/src/sound/audio_decoder_vorbis.cpp @@ -102,7 +102,7 @@ static ov_callbacks OV_CALLBACKS_NLMISC_STREAM = { }; 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(); stream->seek(0, NLMISC::IStream::end); diff --git a/code/nel/src/sound/driver/CMakeLists.txt b/code/nel/src/sound/driver/CMakeLists.txt index d1d82169c..90fbbb562 100644 --- a/code/nel/src/sound/driver/CMakeLists.txt +++ b/code/nel/src/sound/driver/CMakeLists.txt @@ -3,6 +3,8 @@ FILE(GLOB HEADERS ../../../include/nel/sound/driver/*.h) NL_TARGET_LIB(nelsnd_lowlevel ${HEADERS} ${SRC}) +TARGET_LINK_LIBRARIES(nelsnd_lowlevel nelmisc) + SET_TARGET_PROPERTIES(nelsnd_lowlevel PROPERTIES LINK_INTERFACE_LIBRARIES "") NL_DEFAULT_PROPS(nelsnd_lowlevel "NeL, Library: Sound Lowlevel") NL_ADD_RUNTIME_FLAGS(nelsnd_lowlevel) diff --git a/code/nel/src/sound/group_controller.cpp b/code/nel/src/sound/group_controller.cpp index 1cce28bf0..fef67a01b 100644 --- a/code/nel/src/sound/group_controller.cpp +++ b/code/nel/src/sound/group_controller.cpp @@ -87,7 +87,8 @@ std::string CGroupController::getPath() // overridden by root return returnPath; } } - + nlerror("Group Controller not child of parent"); + return ""; } void CGroupController::calculateFinalGain() // overridden by root