From c03655b0ba1574f27d0935b534e25bee9bf6253a Mon Sep 17 00:00:00 2001
From: kaetemi <none@none>
Date: Wed, 11 Apr 2012 20:20:02 +0200
Subject: [PATCH 1/5] Added: Some sort of implementation for
 CPThread::isRunning()

--HG--
branch : sound_dev
---
 code/nel/include/nel/misc/p_thread.h |  3 ++-
 code/nel/src/misc/p_thread.cpp       | 37 ++++++++++++++++------------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/code/nel/include/nel/misc/p_thread.h b/code/nel/include/nel/misc/p_thread.h
index 82f6a4ee3..a4db1f55f 100644
--- a/code/nel/include/nel/misc/p_thread.h
+++ b/code/nel/include/nel/misc/p_thread.h
@@ -59,8 +59,9 @@ public:
 	/// Internal use
 	IRunnable	*Runnable;
 
+	uint8		_StateV2; // 0=not created, 1=started, 2=ended, 3=finished
+
 private:
-	uint8		_State; // 0=not created, 1=started, 2=finished
 	uint32		_StackSize;
 	pthread_t	_ThreadHandle;
 };
diff --git a/code/nel/src/misc/p_thread.cpp b/code/nel/src/misc/p_thread.cpp
index e20981c98..77866471e 100644
--- a/code/nel/src/misc/p_thread.cpp
+++ b/code/nel/src/misc/p_thread.cpp
@@ -84,6 +84,8 @@ static void *ProxyFunc( void *arg )
 	// Run the code of the thread
 	parent->Runnable->run();
 
+	parent->_StateV2 = 2;
+
 	// Allow some clean
 //	pthread_exit(0);
 	return NULL;
@@ -96,7 +98,7 @@ static void *ProxyFunc( void *arg )
  */
 CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
 	:	Runnable(runnable),
-		_State(0),
+		_StateV2(0),
 		_StackSize(stackSize)
 {}
 
@@ -106,10 +108,10 @@ CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
  */
 CPThread::~CPThread()
 {
-	if(_State == 1)
+	if(_StateV2 == 1 || _StateV2 == 2)
 		terminate(); // force the end of the thread if not already ended
 
-	if(_State > 0)
+	if(_StateV2 > 0)
 		pthread_detach(_ThreadHandle); // free allocated resources only if it was created
 }
 
@@ -132,13 +134,14 @@ void CPThread::start()
 	{
 		throw EThread("Cannot start new thread");
 	}
-	_State = 1;
+	_StateV2 = 1;
 }
 
 bool CPThread::isRunning()
 {
-	// TODO : need a real implementation here that check thread status
-	return _State == 1;
+	// ExTODO : need a real implementation here that check thread status
+	// DONE : some sort of implementation
+	return _StateV2 == 1;
 }
 
 /*
@@ -146,11 +149,11 @@ bool CPThread::isRunning()
  */
 void CPThread::terminate()
 {
-	if(_State == 1)
+	if (_StateV2 == 1 || _StateV2 == 2)
 	{
 		// cancel only if started
 		pthread_cancel(_ThreadHandle);
-		_State = 2;	// set to finished
+		_StateV2 = 3;	// set to finished
 	}
 }
 
@@ -159,13 +162,13 @@ void CPThread::terminate()
  */
 void CPThread::wait ()
 {
-	if(_State == 1)
+	if (_StateV2 == 1 || _StateV2 == 2)
 	{
 		if(pthread_join(_ThreadHandle, 0) != 0)
 		{
 			throw EThread( "Cannot join with thread" );
 		}
-		_State = 2;	// set to finished
+		_StateV2 = 3;	// set to finished
 	}
 }
 
@@ -209,27 +212,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);
 	}
 }
 

From c0c5ee6d93cafe0208cf5fb41cf2ef58ee189413 Mon Sep 17 00:00:00 2001
From: kaetemi <none@none>
Date: Wed, 11 Apr 2012 21:55:33 +0200
Subject: [PATCH 2/5] Fixed: Implementation for CPThread::isRunning()

--HG--
branch : sound_dev
---
 code/nel/include/nel/misc/p_thread.h | 10 +++-
 code/nel/src/misc/p_thread.cpp       | 85 +++++++++++++++++++++-------
 2 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/code/nel/include/nel/misc/p_thread.h b/code/nel/include/nel/misc/p_thread.h
index a4db1f55f..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,11 +65,11 @@ public:
 	/// Internal use
 	IRunnable	*Runnable;
 
-	uint8		_StateV2; // 0=not created, 1=started, 2=ended, 3=finished
+	TThreadState	_State;
+	pthread_t	_ThreadHandle;
 
 private:
 	uint32		_StackSize;
-	pthread_t	_ThreadHandle;
 };
 
 /**
diff --git a/code/nel/src/misc/p_thread.cpp b/code/nel/src/misc/p_thread.cpp
index 77866471e..9524ca0bb 100644
--- a/code/nel/src/misc/p_thread.cpp
+++ b/code/nel/src/misc/p_thread.cpp
@@ -84,7 +84,16 @@ static void *ProxyFunc( void *arg )
 	// Run the code of the thread
 	parent->Runnable->run();
 
-	parent->_StateV2 = 2;
+	{
+		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);
@@ -98,7 +107,7 @@ static void *ProxyFunc( void *arg )
  */
 CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
 	:	Runnable(runnable),
-		_StateV2(0),
+		_State(ThreadStateNone),
 		_StackSize(stackSize)
 {}
 
@@ -108,10 +117,9 @@ CPThread::CPThread(IRunnable *runnable, uint32 stackSize)
  */
 CPThread::~CPThread()
 {
-	if(_StateV2 == 1 || _StateV2 == 2)
-		terminate(); // force the end of the thread if not already ended
+	terminate(); // force the end of the thread if not already ended
 
-	if(_StateV2 > 0)
+	if (_State != ThreadStateNone)
 		pthread_detach(_ThreadHandle); // free allocated resources only if it was created
 }
 
@@ -121,27 +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");
 	}
-	_StateV2 = 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()
 {
-	// ExTODO : need a real implementation here that check thread status
-	// DONE : some sort of implementation
-	return _StateV2 == 1;
+	return _State == ThreadStateRunning;
 }
 
 /*
@@ -149,11 +181,11 @@ bool CPThread::isRunning()
  */
 void CPThread::terminate()
 {
-	if (_StateV2 == 1 || _StateV2 == 2)
+	if (_State == ThreadStateRunning)
 	{
 		// cancel only if started
 		pthread_cancel(_ThreadHandle);
-		_StateV2 = 3;	// set to finished
+		_State = ThreadStateFinished; // set to finished
 	}
 }
 
@@ -162,13 +194,24 @@ void CPThread::terminate()
  */
 void CPThread::wait ()
 {
-	if (_StateV2 == 1 || _StateV2 == 2)
+	if (_State == ThreadStateRunning)
 	{
-		if(pthread_join(_ThreadHandle, 0) != 0)
+		int error = pthread_join(_ThreadHandle, 0) != 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");
 		}
-		_StateV2 = 3;	// set to finished
+		if(_State != ThreadStateFinished)
+			throw EThread("Thread did not finish, this should not happen");
 	}
 }
 

From 80bf70efbb2159658e02436239e94283a33cfe35 Mon Sep 17 00:00:00 2001
From: kaetemi <none@none>
Date: Wed, 11 Apr 2012 22:05:18 +0200
Subject: [PATCH 3/5] Changed: Make CWinThread::start more sane, and fixed a
 typo

--HG--
branch : sound_dev
---
 code/nel/src/misc/p_thread.cpp   | 2 +-
 code/nel/src/misc/win_thread.cpp | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/code/nel/src/misc/p_thread.cpp b/code/nel/src/misc/p_thread.cpp
index 9524ca0bb..f752f4bdf 100644
--- a/code/nel/src/misc/p_thread.cpp
+++ b/code/nel/src/misc/p_thread.cpp
@@ -196,7 +196,7 @@ void CPThread::wait ()
 {
 	if (_State == ThreadStateRunning)
 	{
-		int error = pthread_join(_ThreadHandle, 0) != 0;
+		int error = pthread_join(_ThreadHandle, 0);
 		switch (error)
 		{
 		case 0:
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());

From b486e22a96293d10fad3c92fabdce27f241193c4 Mon Sep 17 00:00:00 2001
From: kaetemi <none@none>
Date: Wed, 11 Apr 2012 23:34:36 +0200
Subject: [PATCH 4/5] Fixed: Typos and warnings

--HG--
branch : sound_dev
---
 code/nel/include/nel/sound/group_controller.h  | 2 +-
 code/nel/include/nel/sound/stream_file_sound.h | 2 +-
 code/nel/src/sound/audio_decoder_vorbis.cpp    | 2 +-
 code/nel/src/sound/driver/CMakeLists.txt       | 2 ++
 code/nel/src/sound/group_controller.cpp        | 3 ++-
 5 files changed, 7 insertions(+), 4 deletions(-)

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/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

From 1b41357a434773d7ed5df30aa80b50c6ea92a50a Mon Sep 17 00:00:00 2001
From: kaetemi <none@none>
Date: Thu, 12 Apr 2012 00:27:03 +0200
Subject: [PATCH 5/5] Fixed: #795 #1460 Linux compile of new sound samples

--HG--
branch : sound_dev
---
 .../samples/sound/stream_file/stream_file.cpp | 13 +++++++++++-
 .../stream_ogg_vorbis/stream_ogg_vorbis.cpp   | 21 +++++++++++++++++--
 2 files changed, 31 insertions(+), 3 deletions(-)

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 <stdio.h>
-#include <conio.h>
+#ifdef NL_OS_WINDOWS
+#	include <conio.h>
+#else
+#	include <curses.h>
+#endif
 
 // NeL includes
 #include <nel/misc/app_context.h>
@@ -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 <stdio.h>
-#include <conio.h>
+#ifdef NL_OS_WINDOWS
+#	include <conio.h>
+#else
+#	include <curses.h>
+#endif
 
 // NeL includes
 #include <nel/misc/app_context.h>
@@ -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;
 }