SDL2: Replace mutex implementation

--HG--
branch : sdl2
hg/feature/sdl2
kaetemi 11 years ago
parent 15dc492690
commit 788ac7b9e0

@ -104,6 +104,7 @@ IF(WIN32)
ENDIF(WITH_MFC) ENDIF(WITH_MFC)
ENDIF(WIN32) ENDIF(WIN32)
FIND_PACKAGE(SDL2 REQUIRED)
FIND_PACKAGE(LibXml2 REQUIRED) FIND_PACKAGE(LibXml2 REQUIRED)
FIND_PACKAGE(PNG REQUIRED) FIND_PACKAGE(PNG REQUIRED)
FIND_PACKAGE(Jpeg) FIND_PACKAGE(Jpeg)

@ -0,0 +1,193 @@
# Locate SDL2 library
# This module defines
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL2
# SDL2_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
# Don't forget to include SDL2main.h and SDL2main.m your project for the
# OS X framework based version. (Other versions link to -lSDL2main which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_LIBRARY
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
#
#
# $SDL2DIR is an environment variable that would
# correspond to the ./configure --prefix=$SDL2DIR
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL2 guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL2 convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
# was not created for redistribution, and exists temporarily pending official
# SDL2 CMake modules.
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include/SDL2 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL2
/usr/include/SDL2
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
FIND_LIBRARY(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
SET(SDL2_FOUND "NO")
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
IF(WIN32)
SET(SDL2_LIBRARY_TEMP winmm imm32 version msimg32 ${SDL2_LIBRARY_TEMP})
ENDIF(WIN32)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_FOUND "YES")
ENDIF(SDL2_LIBRARY_TEMP)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
IF(SDL2_STATIC)
if (UNIX AND NOT APPLE)
EXECUTE_PROCESS(COMMAND sdl2-config --static-libs OUTPUT_VARIABLE SDL2_LINK_FLAGS)
STRING(REGEX REPLACE "(\r?\n)+$" "" SDL2_LINK_FLAGS "${SDL2_LINK_FLAGS}")
SET(SDL2_LIBRARY ${SDL2_LINK_FLAGS})
ENDIF()
ENDIF(SDL2_STATIC)

@ -22,582 +22,70 @@
#include "common.h" #include "common.h"
#include <map> #include <map>
#ifdef NL_OS_WINDOWS struct SDL_mutex;
# ifdef NL_NO_ASM typedef int SDL_SpinLock;
# include <intrin.h>
# endif
#elif defined(NL_OS_UNIX)
# include <pthread.h> // PThread
# include <semaphore.h> // PThread POSIX semaphores
# include <unistd.h>
# define __forceinline
# ifdef NL_OS_MAC
# include <libkern/OSAtomic.h>
# endif
#endif // NL_OS_WINDOWS
#undef MUTEX_DEBUG
namespace NLMISC { namespace NLMISC {
#define CFastMutex CAtomicLock
#define CFairMutex CMutex
#define CUnfairMutex CMutex
/* class CMutex
* This define must be disabled when sharing a mutex between several processes that can
* have a different debug mode (because when __STL_DEBUG is on, sizeof(string) is twice
* the common string size).
*/
#define STORE_MUTEX_NAME
#ifdef NL_OS_WINDOWS
// By default on Windows, all mutex/synchronization use the CFair* class to avoid freeze problem.
# define CMutex CFairMutex
# define CSynchronized CFairSynchronized
#else
// On GNU/Linux and Mac, we use CUnfair* everwise it creates some strange deadlock during loading and after
# define CMutex CUnfairMutex
# define CSynchronized CUnfairSynchronized
#endif
/**
* Classic mutex implementation (not necessarly fair)
* Don't assume the mutex are recursive (ie don't call enter() several times
* on the same mutex from the same thread without having called leave()) ;
* and don't assume either the threads are woken-up in the same order as they
* were put to sleep !
*
* Windows: uses Mutex, cannot be shared among processes.
* Linux: uses PThread POSIX Mutex, cannot be shared among processes.
*
*\code
CUnfairMutex m;
m.enter ();
// do critical stuffs
m.leave ();
*\endcode
* \author Vianney Lecroart, Olivier Cado
* \author Nevrax France
* \date 2000
*/
class CUnfairMutex
{ {
public: public:
/// Constructor /// Constructor
CUnfairMutex(); CMutex();
CUnfairMutex( const std::string &name ); CMutex(const std::string &name);
/// Destructor /// Destructor
~CUnfairMutex(); ~CMutex();
/// Enter the critical section /// Enter
void enter (); void enter();
/// Leave the critical section /// Leave
void leave (); void leave();
private: private:
SDL_mutex *m_SDLMutex;
#ifdef NL_OS_WINDOWS
void *_Mutex;
#elif defined NL_OS_UNIX
pthread_mutex_t mutex;
#else
# error "No unfair mutex implementation for this OS"
#endif
}; };
class CAtomicLock
// Inline assembler for gcc tutorial:
// AT&T syntax:
// - operands reversed,
// - l after opcode replaces dword ptr,
// - () instead of [],
// - immediate values prefixed by $
/*
// Tested: works on multi-processor
#ifdef HAVE_X86_64
# define ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \
"mov %1, %%rcx;" \
"mov $1, %%eax;" \
"xchg %%eax, (%%rcx);" \
"mov %%eax, %0" \
: "=m" (result) \
: "m" (lockPtr) \
: "eax", "rcx", "memory" ); // force to use registers and memory
#else
# define ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \
"mov %1, %%ecx;" \
"mov $1, %%eax;" \
"xchg %%eax, (%%ecx);" \
"mov %%eax, %0" \
: "=m" (result) \
: "m" (lockPtr) \
: "eax", "ecx", "memory" ); // force to use registers and memory
#endif
*/
/*
// Tested: does not work (at least on multi-processor)! (with or without 'lock' prefix)
#define ASM_ASWAP_FOR_GCC_CMPXCHG __asm__ volatile( \
"mov $1, %%edx;" \
"mov %1, %%ecx;" \
"mov (%%ecx), %%eax;" \
"1:nop;" \
"lock cmpxchgl %%edx, (%%ecx);" \
"jne 1b;" \
"mov %%eax, %0" \
: "=m" (result) \
: "m" (lockPtr) \
: "eax", "ecx", "edx", "memory" ); // force to use registers and memory
*/
// Tested: does not work on hyper-threading processors!
/*ASM_ASWAP_FOR_MSVC_CMPXCHG
{
__asm
{
mov edx,1
mov ecx,l
mov eax,[ecx]
test_again:
nop
cmpxchg dword ptr [ecx],edx
jne test_again
mov [result],eax
}
}*/
/**
* Fast mutex implementation (not fairly)
* The mutex ARE NOT recursive (ie don't call enter() several times
* on the same mutex from the same thread without having called leave()) ;
* The threads ARE NOT woken-up in the same order as they were put to sleep.
* The threads ARE NOT woken-up using signals but using Sleep().
* This mutex works but is not optimal for multiprocessors because if the mutex is locked,
* next enter will be sleeped without waiting a little.
*
* Implementation notes:
* - Implementated under WIN32
* - Other OS use CMutex
*
* Tested: OK on Windows and Linux single & multi-processor
*
*\code
CFastMutex m;
m.enter ();
// do critical stuffs
m.leave ();
*\endcode
* \author Cyril 'Hulud' Corvazier
* \author Olivier Cado
* \author Nevrax France
* \date 2002, 2003
*/
#if defined(__ppc__) && !defined(NL_OS_MAC) && (GCC_VERSION <= 40100)
# error "no CFastMutex implementation available, try to use GCC >4.0.1"
#endif
#ifdef NL_OS_WINDOWS
#pragma managed(push, off)
#endif
class CFastMutex
{ {
public: public:
/// Constructor /// Constructor
CFastMutex() : _Lock(0) {} CAtomicLock();
/// Same as constructor, useful for init in a shared memory block
void init() volatile { _Lock = 0; }
/// Atomic swap
__forceinline static bool atomic_swap (volatile uint32 *lockPtr)
{
uint32 result;
#ifdef NL_OS_WINDOWS
# ifdef NL_NO_ASM
result = _InterlockedExchange(reinterpret_cast<volatile long *>(lockPtr), 1);
# else
# ifdef NL_DEBUG
// Workaround for dumb inlining bug (returning of function goes into the choux): push/pop registers
__asm
{
push eax
push ecx
mov ecx,lockPtr
mov eax,1
xchg [ecx],eax
mov [result],eax
pop ecx
pop eax
}
# else
__asm
{
mov ecx,lockPtr
mov eax,1
xchg [ecx],eax
mov [result],eax
}
# endif // NL_DEBUG
# endif // NL_NO_ASM
#elif defined(NL_OS_MAC)
return OSAtomicCompareAndSwap32(0, 1, reinterpret_cast<volatile sint32 *>(lockPtr));
#elif defined(NL_OS_UNIX)
// GCC implements the same functionality using a builtin function
// http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html
// the macro below crashed on Mac OS X 10.6 in a 64bit build
# if (GCC_VERSION > 40100)
// return __sync_bool_compare_and_swap(lockPtr, 0, 1);
result = __sync_val_compare_and_swap(lockPtr, 0, 1);
# else
ASM_ASWAP_FOR_GCC_XCHG
# endif
#endif // NL_OS_WINDOWS
return result != 0;
}
// Enter critical section /// Destructor
__forceinline void enter () volatile ~CAtomicLock();
{
//std::cout << "Entering, Lock=" << _Lock << std::endl;
if (atomic_swap (&_Lock))
{
// First test
uint i;
for (i = 0 ;; ++i)
{
uint wait_time = i + 6;
// Increment wait time with a log function
if (wait_time > 27)
wait_time = 27;
// Sleep
if (wait_time <= 20)
wait_time = 0;
else
wait_time = 1 << (wait_time - 20);
if (!atomic_swap (&_Lock))
break;
#ifdef NL_OS_WINDOWS
nlSleep (wait_time);
#else
//std::cout << "Sleeping i=" << i << std::endl;
usleep( wait_time*1000 );
#endif
}
}
}
// Leave critical section
__forceinline void leave () volatile
{
_Lock = 0;
//std::cout << "Leave" << std::endl;
}
private:
volatile uint32 _Lock;
};
/**
* Fast mutex for multiprocessor implementation (not fairly).
* Used for multiprocessor critical section synchronisation.
* The mutex ARE NOT recursive (ie don't call enter() several times
* on the same mutex from the same thread without having called leave()) ;
* The threads use a spin system to wait a little time before be put to sleep.
* It waits using CPU time.
*
* Implementation notes:
* - Implementated under WIN32
* - Other OS use CMutex
*
*\code
CFastMutexMP m;
m.enter ();
// do critical stuffs
m.leave ();
*\endcode
* \author Cyril 'Hulud' Corvazier
* \author Olivier Cado
* \author Nevrax France
* \date 2002, 2003
*/
#ifndef __ppc__
class CFastMutexMP
{
public:
/// Constructor
CFastMutexMP() : _Lock(0) {}
/// Same as constructor, useful for init in a shared memory block /// Same as constructor, useful for init in a shared memory block
void init() volatile { _Lock = 0; } void init();
// Enter critical section /// Enter
__forceinline void enter () volatile void enter();
{
//std::cout << "Entering, Lock=" << _Lock << std::endl;
while (CFastMutex::atomic_swap (&_Lock))
{
static uint last = 0;
static uint _max = 30;
uint spinMax = _max;
uint lastSpins = last;
volatile uint temp = 17;
uint i;
for (i = 0; i < spinMax; ++i)
{
if (i < lastSpins/2 || _Lock)
{
temp *= temp;
temp *= temp;
temp *= temp;
temp *= temp;
}
else
{
if (!CFastMutex::atomic_swap(&_Lock))
{
last = i;
_max = 1000;
return;
}
}
}
_max = 30; /// Leave
void leave();
// First test
for (i = 0 ;; ++i)
{
uint wait_time = i + 6;
// Increment wait time with a log function
if (wait_time > 27)
wait_time = 27;
// Sleep
if (wait_time <= 20)
wait_time = 0;
else
wait_time = 1 << (wait_time - 20);
if (!CFastMutex::atomic_swap (&_Lock))
break;
#ifdef NL_OS_WINDOWS
nlSleep (wait_time);
#else
//std::cout << "Sleeping i=" << i << std::endl;
usleep( wait_time*1000 );
#endif
}
}
}
// Leave critical section
__forceinline void leave () volatile
{
_Lock = 0;
//std::cout << "Leave" << std::endl;
}
private: private:
volatile uint32 _Lock; SDL_SpinLock m_SDLSpinLock;
};
#endif
/**
* Windows: uses Mutex, the handle can't be shared among processes, but
* the mutex still can be be shared by passing a common object name to
* createByName() / createByKey(). Note: the mutex must be explicitely
* destroyed by calling destroy().
*
* \author Olivier Cado
* \author Nevrax France
* \date 2002
*/
class CSharedMutex
{
public:
/// Constructor (does not create the mutex, see createByName()/createByKey())
CSharedMutex();
#ifdef NL_OS_WINDOWS
/// Create or access an existing mutex (created by another process) with a specific object name. Returns false if it failed.
bool createByName( const char *objectName );
#else
/// Create (with createNew to true) or access an existing mutex (created by another process) with a specific key. Returns false if it failed.
bool createByKey( int key, bool createNew );
#endif
/// Destroy the mutex
void destroy();
/// Enter the critical section
void enter ();
/// Leave the critical section
void leave ();
private:
#ifdef NL_OS_WINDOWS
/// The mutex handle
void *_Mutex;
#else
/// The semaphore id
int _SemId;
#endif
};
#ifdef NL_OS_WINDOWS
/**
* Trick to avoid including <windows.h> !
* winbase.h: typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
* The original RTL_CRITICAL_SECTION is in winnt.h.
*/
struct TNelRtlCriticalSection {
void *DebugInfo;
long LockCount;
long RecursionCount;
void *OwningThread; // from the thread's ClientId->UniqueThread
void *LockSemaphore;
uint32 SpinCount;
};
#endif // NL_OS_WINDOWS
/**
* Kind of "fair" mutex
*
* Windows: uses Critical Section, cannot be shared among processes
* Linux: uses PThread (POSIX) semaphore, cannot be shared among processes
*
*\code
CUnfairMutex m;
m.enter ();
// do critical stuffs
m.leave ();
*\endcode
* \author Olivier Cado
* \author Nevrax France
* \date 2000
*
*\code
CFairMutex m;
m.enter ();
// do critical stuffs
m.leave ();
*\endcode
* \author Olivier Cado
* \author Nevrax France
* \date 2001
*/
class CFairMutex
{
public:
/// Constructor
CFairMutex();
CFairMutex(const std::string &name);
/// Destructor
~CFairMutex();
void enter ();
void leave ();
#ifdef STORE_MUTEX_NAME
std::string Name;
#endif
private:
#ifdef NL_OS_WINDOWS
TNelRtlCriticalSection _Cs;
#elif defined NL_OS_UNIX
sem_t _Sem;
#else
# error "No fair mutex implementation for this OS"
#endif
#ifdef MUTEX_DEBUG
// debug stuffs
void debugCreateMutex();
void debugBeginEnter();
void debugEndEnter();
void debugLeave();
void debugDeleteMutex();
#endif // MUTEX_DEBUG
};
/*
* Debug info
*/
#ifdef MUTEX_DEBUG
struct TMutexLocks
{
TMutexLocks(uint32 m=0) : TimeToEnter(0), TimeInMutex(0), Nb(0), WaitingMutex(0), MutexNum(m), ThreadHavingTheMutex(0xFFFFFFFF), Dead(false) {}
uint32 TimeToEnter; // cumulated time blocking on enter
uint32 TimeInMutex; // cumulated time between enter and leave
uint32 Nb; // number of calls of enter
uint32 WaitingMutex; // number of thread that waiting this mutex
sint32 MutexNum; // identifying a mutex
uint ThreadHavingTheMutex; // thread id of the thread that is in this mutex (0xFFFFFFFF if no thread)
bool Dead; // True if the mutex is dead (deleted)
std::string MutexName; // Name of the mutex
NLMISC::TTicks BeginEnter;
NLMISC::TTicks EndEnter;
}; };
/// Inits the "mutex debugging info system"
void initAcquireTimeMap();
/// Gets the debugging info for all mutexes (call it evenly)
std::map<CMutex*,TMutexLocks> getNewAcquireTimes();
/// The number of created mutexes (does not take in account the destroyed mutexes)
extern uint32 NbMutexes;
#endif // MUTEX_DEBUG
/** /**
* This class ensure that the Value is accessed by only one thread. First you have to create a CSynchronized class with your type. * This class ensure that the Value is accessed by only one thread. First you have to create a CSynchronized class with your type.
* Then, if a thread want to modify or do anything on it, you create a CAccessor in a \b sub \b scope. You can modify the value * Then, if a thread want to modify or do anything on it, you create a CAccessor in a \b sub \b scope. You can modify the value
* of the CUnfairSynchronized using the value() function \b until the end of the scope. So you have to put the smaller scope as you can. * of the CSynchronized using the value() function \b until the end of the scope. So you have to put the smaller scope as you can.
*
* Internally, this class uses a CUnfairMutex object (see CUnfairMutex for programming considerations).
* *
*\code *\code
// the value that you want to be thread safe. // the value that you want to be thread safe.
CUnfairSynchronized<int> val; CSynchronized<int> val;
{ // create a new scope for the access { // create a new scope for the access
// get an access to the value // get an access to the value
CUnfairSynchronized<int>::CAccessor acces(&val); CSynchronized<int>::CAccessor acces(&val);
// now, you have a thread safe access until the end of the scope, so you can do whatever you want. for example, change the value // now, you have a thread safe access until the end of the scope, so you can do whatever you want. for example, change the value
acces.value () = 10; acces.value () = 10;
} // end of the access } // end of the access
@ -606,112 +94,65 @@ extern uint32 NbMutexes;
* \author Nevrax France * \author Nevrax France
* \date 2000 * \date 2000
*/ */
template <class T> template <class T, class TMutex = CMutex>
class CUnfairSynchronized class CSynchronized
{ {
public: public:
CUnfairSynchronized (const std::string &name) : _Mutex(name) { } CSynchronized(const std::string &name) : m_Mutex(name) { }
/** /**
* This class give you a thread safe access to the CSynchronized Value. Look at the example in the CSynchronized. * This class give you a thread safe access to the CSynchronized Value. Look at the example in the CSynchronized.
*/ */
class CAccessor class CAccessor
{ {
CUnfairSynchronized<T> *Synchronized; CSynchronized<T> *Synchronized;
public: public:
/// get the mutex or wait /// get the mutex or wait
CAccessor(CUnfairSynchronized<T> *cs) CAccessor(CSynchronized<T> *cs)
{ {
Synchronized = cs; Synchronized = cs;
const_cast<CMutex&>(Synchronized->_Mutex).enter(); const_cast<CMutex &>(Synchronized->m_Mutex).enter();
} }
/// release the mutex /// release the mutex
~CAccessor() ~CAccessor()
{ {
const_cast<CMutex&>(Synchronized->_Mutex).leave(); const_cast<CMutex &>(Synchronized->m_Mutex).leave();
} }
/// access to the Value /// access to the Value
T &value() T &value()
{ {
return const_cast<T&>(Synchronized->_Value); return const_cast<T &>(Synchronized->m_Value);
} }
}; };
private: private:
friend class CUnfairSynchronized::CAccessor; friend class CSynchronized::CAccessor;
/// The mutex of the synchronized value. /// The mutex of the synchronized value.
volatile CUnfairMutex _Mutex; volatile TMutex m_Mutex;
/// The synchronized value. /// The synchronized value.
volatile T _Value; volatile T m_Value;
}; };
/**
* This class is similar to CUnfairSynchronized, but it ensures that the threads
* are woken-up in the same order as they were put to sleep.
* Internally, it uses a CFairMutex object instead of a CUnfairMutex object.
* \author Olivier Cado
* \author Nevrax France
* \date 2001
*/
template <class T> template <class T>
class CFairSynchronized class CUnfairSynchronized : public CSynchronized<T, CUnfairMutex> { };
{
public:
CFairSynchronized (const std::string &name) : _Cs(name) { }
/**
* This class give you a thread safe access to the CFairSynchronized Value. Look at the example in CSynchronized.
*/
class CAccessor
{
CFairSynchronized<T> *Synchronized;
public:
/// get the mutex or wait template <class T>
CAccessor(CFairSynchronized<T> *cs) class CFairSynchronized : public CSynchronized<T, CFairMutex> { };
{
Synchronized = cs;
const_cast<CFairMutex&>(Synchronized->_Cs).enter();
}
/// release the mutex
~CAccessor()
{
const_cast<CFairMutex&>(Synchronized->_Cs).leave();
}
/// access to the Value
T &value()
{
return const_cast<T&>(Synchronized->_Value);
}
};
private:
friend class CFairSynchronized::CAccessor;
/// The mutex of the synchronized value.
volatile CFairMutex _Cs;
/// The synchronized value.
volatile T _Value;
};
template <class T>
class CFastSynchronized : public CSynchronized<T, CFastMutex> { };
/** Helper class that allow easy usage of mutex to protect /** Helper class that allow easy usage of mutex to protect
* a local block of code with an existing mutex. * a local block of code with an existing mutex.
*/ */
template <class TMutex=CMutex> template <class TMutex = CMutex>
class CAutoMutex class CAutoMutex
{ {
TMutex &_Mutex; TMutex &_Mutex;
@ -742,7 +183,6 @@ public:
} // NLMISC } // NLMISC
#endif // NL_MUTEX_H #endif // NL_MUTEX_H
/* End of mutex.h */ /* End of mutex.h */

@ -33,8 +33,8 @@ class CReaderWriter
{ {
private: private:
volatile CMutex _Fairness; volatile CAtomicLock _Fairness;
volatile CMutex _ReadersMutex; volatile CAtomicLock _ReadersMutex;
volatile CMutex _RWMutex; volatile CMutex _RWMutex;
volatile sint _ReadersLevel; volatile sint _ReadersLevel;
@ -45,29 +45,29 @@ public:
void enterReader() void enterReader()
{ {
const_cast<CMutex&>(_Fairness).enter(); const_cast<CAtomicLock&>(_Fairness).enter();
const_cast<CMutex&>(_ReadersMutex).enter(); const_cast<CAtomicLock&>(_ReadersMutex).enter();
++_ReadersLevel; ++_ReadersLevel;
if (_ReadersLevel == 1) if (_ReadersLevel == 1)
const_cast<CMutex&>(_RWMutex).enter(); const_cast<CMutex&>(_RWMutex).enter();
const_cast<CMutex&>(_ReadersMutex).leave(); const_cast<CAtomicLock&>(_ReadersMutex).leave();
const_cast<CMutex&>(_Fairness).leave(); const_cast<CAtomicLock&>(_Fairness).leave();
} }
void leaveReader() void leaveReader()
{ {
const_cast<CMutex&>(_ReadersMutex).enter(); const_cast<CAtomicLock&>(_ReadersMutex).enter();
--_ReadersLevel; --_ReadersLevel;
if (_ReadersLevel == 0) if (_ReadersLevel == 0)
const_cast<CMutex&>(_RWMutex).leave(); const_cast<CMutex&>(_RWMutex).leave();
const_cast<CMutex&>(_ReadersMutex).leave(); const_cast<CAtomicLock&>(_ReadersMutex).leave();
} }
void enterWriter() void enterWriter()
{ {
const_cast<CMutex&>(_Fairness).enter(); const_cast<CAtomicLock&>(_Fairness).enter();
const_cast<CMutex&>(_RWMutex).enter(); const_cast<CMutex&>(_RWMutex).enter();
const_cast<CMutex&>(_Fairness).leave(); const_cast<CAtomicLock&>(_Fairness).leave();
} }
void leaveWriter() void leaveWriter()

@ -164,7 +164,7 @@ protected:
IBuffer *m_Buffers[3]; // an array of two pointers IBuffer *m_Buffers[3]; // an array of two pointers
/// Mutex for buffer ops. /// Mutex for buffer ops.
NLMISC::CMutex m_BufferMutex; NLMISC::CFastMutex m_BufferMutex;
/// The bytes per second according to the buffer format /// The bytes per second according to the buffer format
uint m_BytesPerSecond; uint m_BytesPerSecond;

@ -37,9 +37,9 @@ IF(UNIX)
ENDIF(NOT APPLE) ENDIF(NOT APPLE)
ENDIF(UNIX) ENDIF(UNIX)
INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${PNG_INCLUDE_DIR} config_file) INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR} ${PNG_INCLUDE_DIR} config_file)
TARGET_LINK_LIBRARIES(nelmisc ${CMAKE_THREAD_LIBS_INIT} ${LIBXML2_LIBRARIES}) TARGET_LINK_LIBRARIES(nelmisc ${SDL2_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${LIBXML2_LIBRARIES})
SET_TARGET_PROPERTIES(nelmisc PROPERTIES LINK_INTERFACE_LIBRARIES "") SET_TARGET_PROPERTIES(nelmisc PROPERTIES LINK_INTERFACE_LIBRARIES "")
NL_DEFAULT_PROPS(nelmisc "NeL, Library: NeL Misc") NL_DEFAULT_PROPS(nelmisc "NeL, Library: NeL Misc")
NL_ADD_RUNTIME_FLAGS(nelmisc) NL_ADD_RUNTIME_FLAGS(nelmisc)

@ -19,6 +19,8 @@
#include "nel/misc/dynloadlib.h" #include "nel/misc/dynloadlib.h"
#include "nel/misc/command.h" #include "nel/misc/command.h"
#include <SDL.h>
#ifdef DEBUG_NEW #ifdef DEBUG_NEW
#define new DEBUG_NEW #define new DEBUG_NEW
#endif #endif
@ -114,6 +116,13 @@ CApplicationContext::CApplicationContext()
DebugNeedAssert = false; DebugNeedAssert = false;
NoAssert = false; NoAssert = false;
AlreadyCreateSharedAmongThreads = false; AlreadyCreateSharedAmongThreads = false;
SDL_Init(
SDL_INIT_TIMER
| SDL_INIT_JOYSTICK
| SDL_INIT_HAPTIC
| SDL_INIT_GAMECONTROLLER
| SDL_INIT_EVENTS);
atexit(SDL_Quit);
contextReady(); contextReady();
} }

@ -24,692 +24,64 @@
#include "nel/misc/time_nl.h" #include "nel/misc/time_nl.h"
#include "nel/misc/debug.h" #include "nel/misc/debug.h"
using namespace std; #include <SDL.h>
#ifndef MUTEX_DEBUG
#define debugCreateMutex() ;
#define debugBeginEnter() ;
#define debugEndEnter() ;
#define debugLeave() ;
#define debugDeleteMutex() ;
#endif
/****************
* Windows code *
****************/
#ifdef NL_OS_WINDOWS
// these defines are for IsDebuggerPresent(). It'll not compile on windows 95
// just comment this and the IsDebuggerPresent to compile on windows 95
#define _WIN32_WINDOWS 0x0410
#define WINVER 0x0400
#define NOMINMAX
#include <windows.h>
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
namespace NLMISC {
inline void EnterMutex( void *handle )
{
#ifdef NL_DEBUG
DWORD timeout;
if ( IsDebuggerPresent() )
timeout = INFINITE;
else
timeout = 10000;
// Request ownership of mutex
DWORD dwWaitResult = WaitForSingleObject (handle, timeout);
#else
// Request ownership of mutex during 10s
DWORD dwWaitResult = WaitForSingleObject (handle, 10000);
#endif // NL_DEBUG
switch (dwWaitResult)
{
// The thread got mutex ownership.
case WAIT_OBJECT_0: break;
// Cannot get mutex ownership due to time-out.
case WAIT_TIMEOUT: nlerror ("Dead lock in a mutex (or more that 10s for the critical section");
// Got ownership of the abandoned mutex object.
case WAIT_ABANDONED: nlerror ("A thread forgot to release the mutex");
default: nlerror ("EnterMutex failed");
}
}
inline void LeaveMutex( void *handle )
{
if (ReleaseMutex(handle) == 0)
{
//LPVOID lpMsgBuf;
//FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
// NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );*/
nlerror ("error while releasing the mutex (0x%x %d), %p", GetLastError(), GetLastError(), handle);
//LocalFree( lpMsgBuf );
}
}
/////////////////////////// CUnfairMutex
/*
* Windows version
*/
CUnfairMutex::CUnfairMutex()
{
// Create a mutex with no initial owner.
_Mutex = (void *) CreateMutex( NULL, FALSE, NULL );
nlassert( _Mutex != NULL );
}
CUnfairMutex::CUnfairMutex( const std::string & /* name */ )
{
// Create a mutex with no initial owner.
_Mutex = (void *) CreateMutex( NULL, FALSE, NULL );
nlassert( _Mutex != NULL );
// (Does not use name, only provided for debug compatibility with CFairMutex)
}
/*
* Windows version
*/
CUnfairMutex::~CUnfairMutex()
{
CloseHandle( _Mutex );
}
/*
* Windows version
*/
void CUnfairMutex::enter()
{
EnterMutex( _Mutex );
}
/*
* Windows version
*/
void CUnfairMutex::leave()
{
LeaveMutex( _Mutex );
}
/////////////////////////// CSharedMutexW
/*
*
*/
CSharedMutex::CSharedMutex()
{
_Mutex = NULL;
}
/*
* Create or use an existing mutex (created by another process) with a specific object name (createNow must be false in the constructor)
* Returns false if it failed.
*/
bool CSharedMutex::createByName( const char *objectName )
{
#ifdef NL_DEBUG
nlassert( _Mutex == NULL );
#endif
_Mutex = (void *) CreateMutex( NULL, FALSE, objectName );
//nldebug( "Creating mutex %s: handle %p", objectName, _Mutex );
return ( _Mutex != NULL );
}
/*
*
*/
void CSharedMutex::destroy()
{
CloseHandle( _Mutex );
_Mutex = NULL;
}
/*
*
*/
void CSharedMutex::enter()
{
EnterMutex( _Mutex );
}
/*
*
*/
void CSharedMutex::leave()
{
LeaveMutex( _Mutex );
}
/////////////////////////// CFairMutex
/*
* Windows version
*/
CFairMutex::CFairMutex()
{
#ifdef STORE_MUTEX_NAME
Name = "unset mutex name";
#endif
debugCreateMutex();
// Check that the CRITICAL_SECTION structure has not changed
nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
#if (_WIN32_WINNT >= 0x0500)
DWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation
if ( ! InitializeCriticalSectionAndSpinCount( (CRITICAL_SECTION*)&_Cs, dwSpinCount ) )
{
nlerror( "Error entering critical section" );
}
#else
InitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );
#endif
}
CFairMutex::CFairMutex(const string &name)
{
#ifdef STORE_MUTEX_NAME
Name = name;
#endif
#ifdef MUTEX_DEBUG
debugCreateMutex();
#endif
// Check that the CRITICAL_SECTION structure has not changed
nlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );
#if (_WIN32_WINNT >= 0x0500)
DWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation
if ( ! InitializeCriticalSectionAndSpinCount( (CRITICAL_SECTION*)&_Cs, dwSpinCount ) )
{
nlerror( "Error entering critical section" );
}
#else
InitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );
#endif
}
/*
* Windows version
*/
CFairMutex::~CFairMutex()
{
DeleteCriticalSection( (CRITICAL_SECTION*)&_Cs );
debugDeleteMutex();
}
/*
* Windows version
*/
void CFairMutex::enter()
{
debugBeginEnter();
EnterCriticalSection( (CRITICAL_SECTION*)&_Cs );
debugEndEnter();
}
/*
* Windows version
*/
void CFairMutex::leave()
{
LeaveCriticalSection( (CRITICAL_SECTION*)&_Cs );
debugLeave();
}
/*************
* Unix code *
*************/
#elif defined NL_OS_UNIX
#include <pthread.h>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> // System V semaphores
/*
* Clanlib authors say: "We need to do this because the posix threads library
* under linux obviously suck:"
*/
extern "C"
{
int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
}
namespace NLMISC { namespace NLMISC {
// ***************************************************************************
CUnfairMutex::CUnfairMutex() CMutex::CMutex()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
// Fast mutex. Note: on Windows all mutexes are recursive
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &mutex, &attr );
pthread_mutexattr_destroy( &attr );
}
/*
* Unix version
*/
CUnfairMutex::CUnfairMutex(const std::string &name)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
// Fast mutex. Note: on Windows all mutexes are recursive
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &mutex, &attr );
pthread_mutexattr_destroy( &attr );
}
/*
* Unix version
*/
CUnfairMutex::~CUnfairMutex()
{
pthread_mutex_destroy( &mutex );
}
/*
* Unix version
*/
void CUnfairMutex::enter()
{
//cout << getpid() << ": Locking " << &mutex << endl;
if ( pthread_mutex_lock( &mutex ) != 0 )
{
//cout << "Error locking a mutex " << endl;
nlerror( "Error locking a mutex" );
}
/*else
{
cout << getpid() << ": Owning " << &mutex << endl;
}*/
}
/*
* Unix version
*/
void CUnfairMutex::leave()
{
//int errcode;
//cout << getpid() << ": Unlocking " << &mutex << endl;
if ( (/*errcode=*/pthread_mutex_unlock( &mutex )) != 0 )
{
/* switch ( errcode )
{
case EINVAL: cout << "INVAL" << endl; break;
case EPERM: cout << "PERM" << endl; break;
default: cout << "OTHER" << endl;
}
*/
//cout << "Error unlocking a mutex " /*<< &mutex*/ << endl;
nlerror( "Error unlocking a mutex" );
}
/*else
{
cout << getpid() << ": Released " << &mutex << endl;
}*/
}
/*
* Unix version
*/
CFairMutex::CFairMutex()
{
sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
}
CFairMutex::CFairMutex( const std::string &name )
{
sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
}
/*
* Unix version
*/
CFairMutex::~CFairMutex()
{
sem_destroy( const_cast<sem_t*>(&_Sem) ); // needs that no thread is waiting on the semaphore
}
/*
* Unix version
*/
void CFairMutex::enter()
{ {
sem_wait( const_cast<sem_t*>(&_Sem) ); m_SDLMutex = SDL_CreateMutex();
} }
CMutex::CMutex(const std::string &name)
/*
* Unix version
*/
void CFairMutex::leave()
{ {
sem_post( const_cast<sem_t*>(&_Sem) ); m_SDLMutex = SDL_CreateMutex();
} }
CMutex::~CMutex()
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
*
*/
CSharedMutex::CSharedMutex() : _SemId(-1)
{}
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short int *array; /* array for GETALL, SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
/*
*
*/
bool CSharedMutex::createByKey( int key, bool createNew )
{ {
// Create a semaphore set containing one semaphore SDL_DestroyMutex(m_SDLMutex);
/*key_t mykey = ftok(".", 'n');
_SemId = semget( mykey, 1, IPC_CREAT | IPC_EXCL | 0666 );*/
if ( createNew )
_SemId = semget( key, 1, IPC_CREAT | IPC_EXCL | 0666 );
else
_SemId = semget( key, 1, 0666 );
nldebug( "Got semid %d", _SemId );
if( _SemId == -1 )
return false;
// Initialise the semaphore to 1
union semun arg;
arg.val = 1;
if ( semctl( _SemId, 0, SETVAL, arg ) == -1 )
{
nlwarning( "semid=%d, err=%s", _SemId, strerror(errno) );
return false;
}
return true;
} }
void CMutex::enter()
/*
*
*/
void CSharedMutex::destroy()
{ {
// Destroy the semaphore SDL_LockMutex(m_SDLMutex);
union semun arg;
nlverifyex( semctl( _SemId, 0, IPC_RMID, arg ) != -1, ("semid=%d, err=%s", _SemId, strerror(errno) ) );
_SemId = -1;
} }
void CMutex::leave()
/*
*
*/
void CSharedMutex::enter()
{ {
// Decrement the semaphore SDL_UnlockMutex(m_SDLMutex);
sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
nlverify( semop( _SemId, &buf, 1 ) != -1);
} }
// ***************************************************************************
/* CAtomicLock::CAtomicLock() : m_SDLSpinLock(0)
*
*/
void CSharedMutex::leave()
{ {
// Increment the semaphore
sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
nlverify( semop( _SemId, &buf, 1 ) != -1);
}
#endif // NL_OS_WINDOWS/NL_OS_UNIX
/******************
* Debugging code *
******************/
#ifdef MUTEX_DEBUG
map<CFairMutex*,TMutexLocks> *AcquireTime = NULL;
uint32 NbMutexes = 0;
CFairMutex *ATMutex = NULL;
bool InitAT = true;
/// Inits the "mutex debugging info system"
void initAcquireTimeMap()
{
if ( InitAT )
{
ATMutex = new CFairMutex("ATMutex");
AcquireTime = new map<CFairMutex*,TMutexLocks>;
InitAT = false;
}
}
/// Gets the debugging info for all mutexes (call it evenly, e.g. once per second)
map<CFairMutex*,TMutexLocks> getNewAcquireTimes()
{
map<CMutex*,TMutexLocks> m;
ATMutex->enter();
// Copy map
m = *AcquireTime;
// Reset map
/* map<CMutex*,TMutexLocks>::iterator im;
for ( im=AcquireTime->begin(); im!=AcquireTime->end(); ++im )
{
(*im).second.Time = 0;
(*im).second.Nb = 0;
(*im).second.Locked = false;
}
*/
ATMutex->leave();
return m;
} }
CAtomicLock::~CAtomicLock()
////////////////////////
////////////////////////
void CFairMutex::debugCreateMutex()
{ {
/* if ( ! InitAT )
{
ATMutex->enter();
AcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes) ) );
NbMutexes++;
ATMutex->leave();
char dbgstr [256];
#ifdef STORE_MUTEX_NAME
smprintf( dbgstr, 256, "MUTEX: Creating mutex %p %s (number %u)\n", this, Name.c_str(), NbMutexes-1 );
#else
smprintf( dbgstr, 256, "MUTEX: Creating mutex %p (number %u)\n", this, NbMutexes-1 );
#endif
#ifdef NL_OS_WINDOWS
if ( IsDebuggerPresent() )
OutputDebugString( dbgstr );
#endif
cout << dbgstr << endl;
}
*/}
void CFairMutex::debugDeleteMutex()
{
if ( (this!=ATMutex ) && (ATMutex!=NULL) )
{
ATMutex->enter();
(*AcquireTime)[this].Dead = true;
ATMutex->leave();
}
} }
void CFairMutex::debugBeginEnter() void CAtomicLock::init()
{ {
if ( (this!=ATMutex ) && (ATMutex!=NULL) ) m_SDLSpinLock = 0;
{
TTicks t = CTime::getPerformanceTime();
ATMutex->enter();
std::map<CMutex*,TMutexLocks>::iterator it = (*AcquireTime).find (this);
if (it == (*AcquireTime).end())
{
AcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes++) ) );
char dbgstr [256];
#ifdef STORE_MUTEX_NAME
smprintf( dbgstr, 256, "MUTEX: Creating mutex %p %s (number %u)\n", this, Name.c_str(), NbMutexes-1 );
#else
smprintf( dbgstr, 256, "MUTEX: Creating mutex %p (number %u)\n", this, NbMutexes-1 );
#endif
#ifdef NL_OS_WINDOWS
if ( IsDebuggerPresent() ) OutputDebugString( dbgstr );
#endif
cout << dbgstr << endl;
it = (*AcquireTime).find (this);
#ifdef STORE_MUTEX_NAME
(*it).second.MutexName = Name;
#endif
}
(*it).second.WaitingMutex++;
(*it).second.BeginEnter = t;
ATMutex->leave();
}
} }
void CAtomicLock::enter()
void CFairMutex::debugEndEnter()
{ {
// printf("1"); SDL_AtomicLock(&m_SDLSpinLock);
/* char str[1024];
sprintf(str, "enter %8p %8p %8p\n", this, _Mutex, getThreadId ());
if (_Mutex == (void*)0x88)
{
OutputDebugString (str);
if (entered) __asm int 3;
entered = true;
}
*/
if ( ( this != ATMutex ) && ( ATMutex != NULL ) )
{
TTicks t = CTime::getPerformanceTime();
ATMutex->enter();
if ((uint32)(t-(*AcquireTime)[this].BeginEnter) > (*AcquireTime)[this].TimeToEnter)
(*AcquireTime)[this].TimeToEnter = (uint32)(t-(*AcquireTime)[this].BeginEnter);
(*AcquireTime)[this].Nb += 1;
(*AcquireTime)[this].WaitingMutex--;
(*AcquireTime)[this].ThreadHavingTheMutex = getThreadId();
(*AcquireTime)[this].EndEnter = t;
ATMutex->leave();
}
} }
void CAtomicLock::leave()
void CFairMutex::debugLeave()
{ {
// printf( "0" ); SDL_AtomicUnlock(&m_SDLSpinLock);
/* char str[1024];
sprintf(str, "leave %8p %8p %8p\n", this, _Mutex, getThreadId ());
if (_Mutex == (void*)0x88)
{
OutputDebugString (str);
if (!entered) __asm int 3;
entered = false;
}
*/
if ( ( this != ATMutex ) && ( ATMutex != NULL ) )
{
TTicks Leave = CTime::getPerformanceTime();
ATMutex->enter();
if ((uint32)(Leave-(*AcquireTime)[this].EndEnter) > (*AcquireTime)[this].TimeInMutex)
(*AcquireTime)[this].TimeInMutex = (uint32)(Leave-(*AcquireTime)[this].EndEnter);
(*AcquireTime)[this].Nb += 1;
(*AcquireTime)[this].WaitingMutex = false;
(*AcquireTime)[this].ThreadHavingTheMutex = 0xFFFFFFFF;
ATMutex->leave();
}
} }
#endif // MUTEX_DEBUG // ***************************************************************************
} // NLMISC } // NLMISC

@ -99,7 +99,7 @@ void CStreamSource::releasePhysicalSource()
uint32 CStreamSource::getTime() uint32 CStreamSource::getTime()
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
if (hasPhysicalSource()) if (hasPhysicalSource())
return getPhysicalSource()->getTime(); return getPhysicalSource()->getTime();
@ -117,7 +117,7 @@ void CStreamSource::setLooping(bool l)
{ {
CSourceCommon::setLooping(l); CSourceCommon::setLooping(l);
//CAutoMutex<CMutex> autoMutex(m_BufferMutex); //CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
// //
//CSourceCommon::setLooping(l); //CSourceCommon::setLooping(l);
//if (hasPhysicalSource()) //if (hasPhysicalSource())
@ -150,7 +150,7 @@ void CStreamSource::play()
CAudioMixerUser *mixer = CAudioMixerUser::instance(); CAudioMixerUser *mixer = CAudioMixerUser::instance();
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
//if ((mixer->getListenPosVector() - _Position).sqrnorm() > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance()) //if ((mixer->getListenPosVector() - _Position).sqrnorm() > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance())
if ((_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance()) if ((_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance())
@ -277,7 +277,7 @@ void CStreamSource::play()
void CStreamSource::stopInt() void CStreamSource::stopInt()
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
// nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this); // nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
// nlassert(_Playing); // nlassert(_Playing);
@ -321,7 +321,7 @@ void CStreamSource::stop()
void CStreamSource::setPos(const NLMISC::CVector& pos) void CStreamSource::setPos(const NLMISC::CVector& pos)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setPos(pos); CSourceCommon::setPos(pos);
if (hasPhysicalSource()) if (hasPhysicalSource())
@ -330,7 +330,7 @@ void CStreamSource::setPos(const NLMISC::CVector& pos)
void CStreamSource::setVelocity(const NLMISC::CVector& vel) void CStreamSource::setVelocity(const NLMISC::CVector& vel)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setVelocity(vel); CSourceCommon::setVelocity(vel);
if (hasPhysicalSource()) if (hasPhysicalSource())
@ -342,7 +342,7 @@ void CStreamSource::setVelocity(const NLMISC::CVector& vel)
*/ */
void CStreamSource::setDirection(const NLMISC::CVector& dir) void CStreamSource::setDirection(const NLMISC::CVector& dir)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setDirection(dir); CSourceCommon::setDirection(dir);
@ -373,7 +373,7 @@ void CStreamSource::setDirection(const NLMISC::CVector& dir)
void CStreamSource::updateFinalGain() void CStreamSource::updateFinalGain()
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
if (hasPhysicalSource()) if (hasPhysicalSource())
getPhysicalSource()->setGain(getFinalGain()); getPhysicalSource()->setGain(getFinalGain());
@ -381,7 +381,7 @@ void CStreamSource::updateFinalGain()
void CStreamSource::setPitch(float pitch) void CStreamSource::setPitch(float pitch)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
m_PitchInv = 1.0f / pitch; m_PitchInv = 1.0f / pitch;
CSourceCommon::setPitch(pitch); CSourceCommon::setPitch(pitch);
if (hasPhysicalSource()) if (hasPhysicalSource())
@ -390,7 +390,7 @@ void CStreamSource::setPitch(float pitch)
void CStreamSource::setSourceRelativeMode(bool mode) void CStreamSource::setSourceRelativeMode(bool mode)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setSourceRelativeMode(mode); CSourceCommon::setSourceRelativeMode(mode);
if (hasPhysicalSource()) if (hasPhysicalSource())
@ -428,7 +428,7 @@ void CStreamSource::updateAvailableBuffers()
/// Get a writable pointer to the buffer of specified size. Use capacity to specify the required bytes. Returns NULL when all the buffer space is already filled. Call setFormat() first. /// Get a writable pointer to the buffer of specified size. Use capacity to specify the required bytes. Returns NULL when all the buffer space is already filled. Call setFormat() first.
uint8 *CStreamSource::lock(uint capacity) uint8 *CStreamSource::lock(uint capacity)
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
updateAvailableBuffers(); updateAvailableBuffers();
if (m_FreeBuffers > 0) if (m_FreeBuffers > 0)
return m_Buffers[m_NextBuffer]->lock(capacity); return m_Buffers[m_NextBuffer]->lock(capacity);
@ -440,7 +440,7 @@ bool CStreamSource::unlock(uint size)
{ {
nlassert(m_FreeBuffers > 0); nlassert(m_FreeBuffers > 0);
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
IBuffer *buffer = m_Buffers[m_NextBuffer]; IBuffer *buffer = m_Buffers[m_NextBuffer];
bool result = buffer->unlock(size); bool result = buffer->unlock(size);

@ -52,7 +52,7 @@ struct TChangeTrackerHeader
#ifdef USE_FAST_MUTEX #ifdef USE_FAST_MUTEX
/// Fast mutex (TODO: use multi-processor version) /// Fast mutex (TODO: use multi-processor version)
volatile NLMISC::CFastMutex FastMutex; NLMISC::CFastMutex FastMutex;
#endif #endif
/* /*
* Number of values set (used in COUNT_MIRROR_CHANGES mode only, always allocated for mode interoperability) * Number of values set (used in COUNT_MIRROR_CHANGES mode only, always allocated for mode interoperability)
@ -161,7 +161,7 @@ public:
#ifdef USE_FAST_MUTEX #ifdef USE_FAST_MUTEX
/// Return the mutex /// Return the mutex
volatile NLMISC::CFastMutex& trackerMutex() { return _Header->FastMutex; } NLMISC::CFastMutex& trackerMutex() { return _Header->FastMutex; }
#else #else
/// Return the mutex /// Return the mutex
NLMISC::CSharedMutex& trackerMutex() { return _TrackerMutex; } NLMISC::CSharedMutex& trackerMutex() { return _TrackerMutex; }

Loading…
Cancel
Save