Compare commits

...

21 Commits

Author SHA1 Message Date
kaetemi 3a99de667a Merge with game-device
--HG--
branch : sdl2
10 years ago
kaetemi 4e2ae9c5b0 SDL2: Replace screensaver
--HG--
branch : sdl2
10 years ago
kaetemi 5787bbe3b3 Backed out changeset: c7649f0bccae
--HG--
branch : sdl2
10 years ago
kaetemi 0b3d642870 Backed out changeset: 2811086e4a76
--HG--
branch : sdl2
10 years ago
kaetemi b4d5730363 SDL2: Add rough draft for event emitter
--HG--
branch : sdl2
10 years ago
kaetemi f779b34751 SDL2: Replace clipboard
--HG--
branch : sdl2
11 years ago
kaetemi 220d58442c SDL2: Replace time
--HG--
branch : sdl2
11 years ago
kaetemi bc449abb20 SDL2: Replace library loading
--HG--
branch : sdl2
11 years ago
kaetemi 87379f87a7 SDL2: Adjust free look mouse cursor handling
--HG--
branch : sdl2
11 years ago
kaetemi f33cbeb7de Merge with default
--HG--
branch : sdl2
11 years ago
kaetemi 733455b5fb Fix #162: Center ingame mouse cursor after login
--HG--
branch : sdl2
11 years ago
kaetemi a307c383f9 SDL2: Trash DirectInput
--HG--
branch : sdl2
11 years ago
kaetemi 7223a4d208 SDL2: Implement cross platform splash screen
--HG--
branch : sdl2
11 years ago
kaetemi 72655cd71b Build bin2c tool
--HG--
branch : sdl2
11 years ago
kaetemi 39d233f5eb SDL2: Pass SDL log into NeL log
--HG--
branch : sdl2
11 years ago
kaetemi 23cbacc0c9 SDL2: Compile fix
--HG--
branch : sdl2
11 years ago
kaetemi ff1059f735 Merge with default
--HG--
branch : sdl2
11 years ago
kaetemi b74c3cc9fa SDL2: Replace thread implementation
--HG--
branch : sdl2
11 years ago
kaetemi 2f302e93a9 SDL2: Replace some system info implementation
--HG--
branch : sdl2
11 years ago
kaetemi cd35d14374 SDL2: Revert a bad change
--HG--
branch : sdl2
11 years ago
kaetemi 788ac7b9e0 SDL2: Replace mutex implementation
--HG--
branch : sdl2
11 years ago

@ -104,6 +104,7 @@ IF(WIN32)
ENDIF(WITH_MFC)
ENDIF(WIN32)
FIND_PACKAGE(SDL2 REQUIRED)
FIND_PACKAGE(LibXml2 REQUIRED)
FIND_PACKAGE(PNG REQUIRED)
FIND_PACKAGE(Jpeg)
@ -296,9 +297,9 @@ IF(WIN32)
ENDIF(WITH_NEL_CEGUI)
# Only the tools require MFC.
IF(WITH_TOOLS)
SET(CMAKE_INSTALL_MFC_LIBRARIES TRUE)
ENDIF(WITH_TOOLS)
#IF(WITH_TOOLS)
# SET(CMAKE_INSTALL_MFC_LIBRARIES TRUE)
#ENDIF(WITH_TOOLS)
#INCLUDE(InstallRequiredSystemLibraries)
ENDIF(WIN32)

@ -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)

@ -315,6 +315,7 @@ MACRO(NL_SETUP_NEL_DEFAULT_OPTIONS)
###
# Optional support
###
OPTION(WITH_TOOLS "Build Tools" OFF)
OPTION(WITH_NEL_CEGUI "Build CEGUI Renderer" OFF)
OPTION(WITH_NEL_TOOLS "Build NeL Tools" ON )
OPTION(WITH_NEL_MAXPLUGIN "Build NeL 3dsMax Plugin" OFF)
@ -324,10 +325,10 @@ MACRO(NL_SETUP_NEL_DEFAULT_OPTIONS)
OPTION(WITH_LIBOVR "With LibOVR support" OFF)
OPTION(WITH_LIBVR "With LibVR support" OFF)
OPTION(WITH_PERFHUD "With NVIDIA PerfHUD support" OFF)
OPTION(WITH_SSE2 "With SSE2" ON )
OPTION(WITH_SSE3 "With SSE3" ON )
IF(NOT MSVC)
OPTION(WITH_GCC_FPMATH_BOTH "With GCC -mfpmath=both" OFF)
ENDIF(NOT MSVC)
@ -401,7 +402,7 @@ MACRO(NL_SETUP_BUILD)
ELSEIF(HOST_CPU MATCHES "i.86")
SET(HOST_CPU "x86")
ENDIF(HOST_CPU MATCHES "(amd|AMD)64")
# Determine target CPU
# If not specified, use the same CPU as host
@ -1111,7 +1112,7 @@ MACRO(SETUP_EXTERNAL)
ENDIF(APPLE)
ENDIF(WIN32)
# Android and iOS have pthread
# Android and iOS have pthread
IF(ANDROID OR IOS)
SET(CMAKE_USE_PTHREADS_INIT 1)
SET(Threads_FOUND TRUE)

@ -33,13 +33,7 @@ namespace NLMISC
{
/// Define the os specific type for dynamic library module handler
#if defined (NL_OS_WINDOWS)
typedef HMODULE NL_LIB_HANDLE;
#elif defined (NL_OS_UNIX)
typedef void* NL_LIB_HANDLE;
#else
# error "You must define the module type on this platform"
#endif
typedef void *NL_LIB_HANDLE;
#ifdef NL_OS_WINDOWS
// MSCV need explicit tag to export or import symbol for a code module

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

@ -22,582 +22,70 @@
#include "common.h"
#include <map>
#ifdef NL_OS_WINDOWS
# ifdef NL_NO_ASM
# 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
struct SDL_mutex;
typedef int SDL_SpinLock;
namespace NLMISC {
#define CFastMutex CAtomicLock
#define CFairMutex CMutex
#define CUnfairMutex 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
class CMutex
{
public:
/// Constructor
CUnfairMutex();
CUnfairMutex( const std::string &name );
CMutex();
CMutex(const std::string &name);
/// Destructor
~CUnfairMutex();
~CMutex();
/// Enter the critical section
void enter ();
/// Enter
void enter();
/// Leave the critical section
void leave ();
/// Leave
void leave();
private:
#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
SDL_mutex *m_SDLMutex;
};
// 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
class CAtomicLock
{
public:
/// Constructor
CFastMutex() : _Lock(0) {}
/// 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
__forceinline void enter () volatile
{
//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:
CAtomicLock();
/// Constructor
CFastMutexMP() : _Lock(0) {}
/// Destructor
~CAtomicLock();
/// Same as constructor, useful for init in a shared memory block
void init() volatile { _Lock = 0; }
// Enter critical section
__forceinline void enter () volatile
{
//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;
// 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:
volatile uint32 _Lock;
};
#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();
void init();
/// Enter the critical section
void enter ();
/// Enter
void enter();
/// Leave the critical section
void leave ();
/// Leave
void leave();
private:
SDL_SpinLock m_SDLSpinLock;
#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.
* 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.
*
* Internally, this class uses a CUnfairMutex object (see CUnfairMutex for programming considerations).
* 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.
*
*\code
// the value that you want to be thread safe.
CUnfairSynchronized<int> val;
CSynchronized<int> val;
{ // create a new scope for the access
// 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
acces.value () = 10;
} // end of the access
@ -606,112 +94,65 @@ extern uint32 NbMutexes;
* \author Nevrax France
* \date 2000
*/
template <class T>
class CUnfairSynchronized
template <class T, class TMutex = CMutex>
class CSynchronized
{
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.
*/
class CAccessor
{
CUnfairSynchronized<T> *Synchronized;
CSynchronized<T> *Synchronized;
public:
/// get the mutex or wait
CAccessor(CUnfairSynchronized<T> *cs)
CAccessor(CSynchronized<T> *cs)
{
Synchronized = cs;
const_cast<CMutex&>(Synchronized->_Mutex).enter();
const_cast<CMutex &>(Synchronized->m_Mutex).enter();
}
/// release the mutex
~CAccessor()
{
const_cast<CMutex&>(Synchronized->_Mutex).leave();
const_cast<CMutex &>(Synchronized->m_Mutex).leave();
}
/// access to the Value
T &value()
{
return const_cast<T&>(Synchronized->_Value);
return const_cast<T &>(Synchronized->m_Value);
}
};
private:
friend class CUnfairSynchronized::CAccessor;
friend class CSynchronized::CAccessor;
/// The mutex of the synchronized value.
volatile CUnfairMutex _Mutex;
volatile TMutex m_Mutex;
/// 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>
class CFairSynchronized
{
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
CAccessor(CFairSynchronized<T> *cs)
{
Synchronized = cs;
const_cast<CFairMutex&>(Synchronized->_Cs).enter();
}
class CUnfairSynchronized : public CSynchronized<T, CUnfairMutex> { };
/// 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 CFairSynchronized : public CSynchronized<T, CFairMutex> { };
template <class T>
class CFastSynchronized : public CSynchronized<T, CFastMutex> { };
/** Helper class that allow easy usage of mutex to protect
* a local block of code with an existing mutex.
*/
template <class TMutex=CMutex>
template <class TMutex = CMutex>
class CAutoMutex
{
TMutex &_Mutex;
@ -742,7 +183,6 @@ public:
} // NLMISC
#endif // NL_MUTEX_H
/* End of mutex.h */

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

@ -33,10 +33,10 @@ class CReaderWriter
{
private:
volatile CMutex _Fairness;
volatile CMutex _ReadersMutex;
volatile CMutex _RWMutex;
volatile sint _ReadersLevel;
volatile CMutex _Fairness;
volatile CMutex _ReadersMutex;
volatile CMutex _RWMutex;
volatile sint _ReadersLevel;
public:

@ -43,35 +43,32 @@ public:
*/
static uint64 getProcessorFrequency (bool quick = false);
/** Tests whether the CPUID instruction is supported
* (always false on non Intel architectures)
*/
static bool hasCPUID ();
/** Helps to know whether the processor features MMX instruction set
* This is initialized at started, so its fast
* (always false on non 0x86 architecture ...)
*/
static bool hasMMX () {return _HaveMMX;}
static bool hasMMX ();
/** Helps to know whether the processor has streaming SIMD instructions (the OS must supports it)
* This is initialized at started, so its fast
* (always false on non 0x86 architecture ...)
*/
static bool hasSSE () {return _HaveSSE;}
static bool hasSSE ();
/** Gets the CPUID (if available). Useful for debug info
*/
static uint32 getCPUID();
/** true if the Processor has HyperThreading
/** Helps to know whether the processor has SSE2 (the OS must supports it)
* This is initialized at started, so its fast
* (always false on non 0x86 architecture ...)
*/
static bool hasHyperThreading();
static bool hasSSE2 ();
/** true if running under NT
*/
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);
@ -95,10 +92,6 @@ public:
/** Returns the main video card name and the video driver version
*/
static bool getVideoInfo (std::string &deviceName, uint64 &driverVersion);
private:
static bool _HaveMMX;
static bool _HaveSSE;
};
} // NLMISC

@ -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,83 +63,57 @@ public:
{
}
// Return the runnable name
virtual void getName (std::string &result) const
virtual void getName(std::string &result) const
{
result = "NoName";
}
};
/// Thread priorities, numbering follows Win32 for now
/// Thread priorities
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;
};
@ -80,22 +78,13 @@ public:
/** Return the local time in milliseconds.
* Use it only to measure time difference, the absolute value does not mean anything.
* On Unix, getLocalTime() will try to use the Monotonic Clock if available, otherwise
* the value can jump backwards if the system time is changed by a user or a NTP time sync process.
* The value is different on 2 different computers; use the CUniTime class to get a universal
* time that is the same on all computers.
* \warning On Win32, the value is on 32 bits only, and uses the low-res timer unless probeTimerInfo was called and a high resolution timer can be used. It wraps around to 0 every about 49.71 days.
*/
static TTime getLocalTime();
/** Return the time in processor ticks. Use it for profile purpose.
* If the performance time is not supported on this hardware, it returns 0.
* \warning On a multiprocessor system, the value returned by each processor may
* be different. The only way to workaround this is to set a processor affinity
* to the measured thread.
* \warning The speed of tick increase can vary (especially on laptops or CPUs with
* power management), so profiling several times and computing the average could be
* a wise choice.
* If the performance time is not supported on this hardware, it returns getLocalTime().
*/
static TTicks getPerformanceTime ();

@ -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;

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

@ -180,7 +180,7 @@ public:
for (i=0; i<NumThreads; ++i)
{
IRunnable *runnable = (IRunnable *)(new CPinger());
IThread *thread = IThread::create(runnable);
CThread *thread = CThread::create(runnable);
thread->start();
}
}

@ -140,7 +140,7 @@ CBufFIFO *CurrentReadQueue = NULL;
TReceivedMessage *CurrentInMsg = NULL;
IThread *ReceiveThread = NULL;
CThread *ReceiveThread = NULL;
CReceiveTask *ReceiveTask = NULL;
list<CClient> Clients; // contains all clients
@ -259,7 +259,7 @@ void CClient::updatePong (sint64 pingTime, sint64 pongTime, uint32 pongNumber, u
// increase only for new pong
NbPong++;
MeanPongTime += (uint32)(pongTime-pingTime);
FullNbPong++;
FullMeanPongTime += (uint32)(pongTime-pingTime);
@ -276,7 +276,7 @@ void CClient::updatePong (sint64 pingTime, sint64 pongTime, uint32 pongNumber, u
ha = Address.ipAddress();
}
string fn = StatPathName + ConnectionName + "_" + ha + "_" + getDate() + ".pong";
FILE *fp = fopen (fn.c_str(), "rt");
if (fp == NULL)
{
@ -318,7 +318,7 @@ void CClient::updateFullStat ()
for (uint i = 0; i < LastPongReceived; i++)
{
if (PongReceived[i].first == 0) NbLost++;
else
else
{
NbPong++;
NbDup += PongReceived[i].first - 1;
@ -333,7 +333,7 @@ void CClient::updateFullStat ()
ha = Address.ipAddress();
}
string fn = StatPathName + ConnectionName + "_" + ha + "_" + getDate() + ".stat";
string line = "Full Summary: ";
line += "NbPing " + toString(LastPongReceived) + " ";
line += "NbPong " + toString(NbPong) + " ";
@ -375,7 +375,7 @@ void CClient::updateFullStat ()
ha = Address.ipAddress();
}
string fn = StatPathName + ConnectionName + "_" + ha + "_" + getDate() + ".ping";
FILE *fp = fopen (fn.c_str(), "rt");
if (fp == NULL)
{
@ -432,7 +432,7 @@ void CClient::updateStat ()
ha = Address.ipAddress();
}
string fn = StatPathName + ConnectionName + "_" + ha + "_" + getDate() + ".stat";
string line;
line += "NbPing " + toString(NbPing) + " ";
line += "NbPong " + toString(NbPong) + " ";
@ -455,7 +455,7 @@ void CClient::updateStat ()
fprintf (fp, "HostAddress: %s\n", Address.asString().c_str());
FirstWrite = false;
}
fprintf (fp, "%s\n", line.c_str());
fclose (fp);
}
@ -535,7 +535,7 @@ void handleReceivedPong (CClient *client, sint64 pongTime)
uint32 session = 0;
msgin.serial (session);
// Find a new udp connection, find the linked
// Find a new udp connection, find the linked
list<CClient>::iterator it;
for (it = Clients.begin(); it != Clients.end(); it++)
{
@ -630,7 +630,7 @@ void sendPing ()
class CBenchService : public IService
{
public:
void init()
{
nlassert( ReceiveTask==NULL && ReceiveThread==NULL );
@ -649,7 +649,7 @@ public:
CurrentReadQueue = &Queue2;
ReceiveTask->setWriteQueue( &Queue1 );
nlassert( ReceiveTask != NULL );
ReceiveThread = IThread::create( ReceiveTask );
ReceiveThread = CThread::create( ReceiveTask );
nlassert( ReceiveThread != NULL );
ReceiveThread->start();
@ -704,7 +704,7 @@ public:
// Handle the UDP message
// Retrieve client info or add one
// Retrieve client info or add one
TClientMap::iterator ihm = ClientMap.find( CurrentInMsg->AddrFrom );
if ( ihm == ClientMap.end() )
{
@ -757,7 +757,7 @@ public:
delete ReceiveThread;
ReceiveThread = NULL;
}
if (ReceiveTask != NULL)
{
delete ReceiveTask;
@ -779,5 +779,5 @@ public:
}
};
NLNET_SERVICE_MAIN (CBenchService, "BS", "bench_service", 45459, EmptyCallbackArray, UDP_DIR, "")

@ -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
@ -317,38 +318,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
@ -357,7 +326,7 @@ class NL3D::CLightRunnable : public IRunnable
const CZoneLighter::CLightDesc *_Description;
public:
IThread *Thread;
CThread *Thread;
public:
// Ctor
@ -371,9 +340,6 @@ public:
// Run method
void run()
{
// Set the CPU mask
setCPUMask (Thread, _Process);
_ZoneLighter->processCalc (_Process, *_Description);
_ZoneLighter->_ProcessExitedMutex.enter();
_ZoneLighter->_ProcessExited++;
@ -399,7 +365,7 @@ class NL3D::CRenderZBuffer : public IRunnable
const vector<CZoneLighter::CTriangle> *_Triangles;
public:
IThread *Thread;
CThread *Thread;
public:
// Ctor
@ -616,9 +582,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;
@ -917,11 +880,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);
@ -936,16 +894,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;
@ -1029,7 +978,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
@ -1185,7 +1134,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
@ -1204,9 +1153,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");
@ -2863,7 +2809,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;
}

@ -37,9 +37,9 @@ IF(UNIX)
ENDIF(NOT APPLE)
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} ${ZLIB_LIBRARY})
TARGET_LINK_LIBRARIES(nelmisc ${SDL2_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${LIBXML2_LIBRARIES} ${ZLIB_LIBRARY})
SET_TARGET_PROPERTIES(nelmisc PROPERTIES LINK_INTERFACE_LIBRARIES "")
NL_DEFAULT_PROPS(nelmisc "NeL, Library: NeL Misc")
NL_ADD_RUNTIME_FLAGS(nelmisc)

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

@ -86,7 +86,7 @@ namespace NLMISC
// TThreadId *_ParentThreadId;
// the thread of the task
IThread *_TaskThread;
CThread *_TaskThread;
/// The mutex of the task task
CFastMutex _TaskMutex;
@ -302,7 +302,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

@ -32,6 +32,8 @@
#include "nel/misc/variable.h"
#include "nel/misc/system_info.h"
#include <SDL_log.h>
#ifdef NL_OS_WINDOWS
# define _WIN32_WINDOWS 0x0410
# ifndef NL_COMP_MINGW
@ -1131,6 +1133,61 @@ std::string getLogDirectory()
return LogPath;
}
// Pass SDL log system into NeL log system
static void sdlLogOutputFunction(void *userdata, int category, SDL_LogPriority priority, const char *message)
{
INelContext *context = (INelContext *)userdata;
CLog *log;
switch (priority)
{
case SDL_LOG_PRIORITY_VERBOSE:
case SDL_LOG_PRIORITY_DEBUG:
log = context->getDebugLog();
break;
case SDL_LOG_PRIORITY_INFO:
log = context->getInfoLog();
break;
case SDL_LOG_PRIORITY_WARN:
log = context->getWarningLog();
break;
case SDL_LOG_PRIORITY_ERROR:
case SDL_LOG_PRIORITY_CRITICAL:
log = context->getErrorLog();
break;
default: // Unreachable
log = context->getAssertLog();
break;
}
switch (category)
{
case SDL_LOG_CATEGORY_APPLICATION:
log->setPosition(-1, "SDL_LOG_CATEGORY_APPLICATION");
break;
case SDL_LOG_CATEGORY_ERROR:
log->setPosition(-1, "SDL_LOG_CATEGORY_ERROR");
break;
case SDL_LOG_CATEGORY_SYSTEM:
log->setPosition(-1, "SDL_LOG_CATEGORY_SYSTEM");
break;
case SDL_LOG_CATEGORY_AUDIO:
log->setPosition(-1, "SDL_LOG_CATEGORY_AUDIO");
break;
case SDL_LOG_CATEGORY_VIDEO:
log->setPosition(-1, "SDL_LOG_CATEGORY_VIDEO");
break;
case SDL_LOG_CATEGORY_RENDER:
log->setPosition(-1, "SDL_LOG_CATEGORY_RENDER");
break;
case SDL_LOG_CATEGORY_INPUT:
log->setPosition(-1, "SDL_LOG_CATEGORY_INPUT");
break;
default:
log->setPosition(-1, "SDL_LOG_CATEGORY_CUSTOM");
break;
}
log->displayNL("%s", message);
}
// You should not call this, unless you know what you're trying to do (it kills debug/log)!
// Destroys debug environment, to clear up the memleak log.
// NeL context must be deleted immediately after debug destroyed,
@ -1229,6 +1286,8 @@ void createDebug (const char *logPath, bool logInFile, bool eraseLastLog)
initDebug2(logInFile);
SDL_LogSetOutputFunction(sdlLogOutputFunction, &INelContext::getInstance());
INelContext::getInstance().setAlreadyCreateSharedAmongThreads(true);
// alreadyCreateSharedAmongThreads = true;
}

@ -16,6 +16,8 @@
#include "stdmisc.h"
#include <SDL_loadso.h>
#include "nel/misc/dynloadlib.h"
#include "nel/misc/path.h"
@ -30,40 +32,20 @@ namespace NLMISC
NL_LIB_HANDLE nlLoadLibrary(const std::string &libName)
{
NL_LIB_HANDLE res = 0;
#ifdef NL_OS_WINDOWS
res = LoadLibrary(libName.c_str());
#elif defined(NL_OS_UNIX)
res = dlopen(libName.c_str(), RTLD_NOW);
#else
# error "You must code nlLoadLibrary() for your platform"
#endif
if(res == 0) nlwarning("Load library '%s' failed: %s", libName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
NL_LIB_HANDLE res = SDL_LoadObject(libName.c_str());
if(res == NULL) nlwarning("Load library '%s' failed: %s", libName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
return res;
}
bool nlFreeLibrary(NL_LIB_HANDLE libHandle)
{
#ifdef NL_OS_WINDOWS
return FreeLibrary(libHandle) > 0;
#elif defined(NL_OS_UNIX)
return dlclose(libHandle) == 0;
#else
# error "You must code nlFreeLibrary() for your platform"
#endif
SDL_UnloadObject(libHandle);
}
void *nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &procName)
{
void *res = 0;
#ifdef NL_OS_WINDOWS
res = (void *)GetProcAddress(libHandle, procName.c_str());
#elif defined(NL_OS_UNIX)
res = dlsym(libHandle, procName.c_str());
#else
# error "You must code nlGetProcAddress() for your platform"
#endif
if(res == 0) nlwarning("Getting symbol address of '%s' failed: %s", procName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
void *res = SDL_LoadFunction(libHandle, procName.c_str());
if(res == NULL) nlwarning("Getting symbol address of '%s' failed: %s", procName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());
return res;
}

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

@ -24,694 +24,64 @@
#include "nel/misc/time_nl.h"
#include "nel/misc/debug.h"
using namespace std;
#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
#ifndef NL_COMP_MINGW
# define WINVER 0x0400
# define NOMINMAX
#endif
#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 );
}
#include <SDL.h>
namespace NLMISC {
// ***************************************************************************
CUnfairMutex::CUnfairMutex()
{
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()
CMutex::CMutex()
{
pthread_mutex_destroy( &mutex );
m_SDLMutex = SDL_CreateMutex();
}
/*
* Unix version
*/
void CUnfairMutex::enter()
CMutex::CMutex(const std::string &name)
{
//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;
}*/
m_SDLMutex = SDL_CreateMutex();
}
/*
* Unix version
*/
void CUnfairMutex::leave()
CMutex::~CMutex()
{
//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;
}*/
SDL_DestroyMutex(m_SDLMutex);
}
/*
* Unix version
*/
CFairMutex::CFairMutex()
void CMutex::enter()
{
sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
SDL_LockMutex(m_SDLMutex);
}
CFairMutex::CFairMutex( const std::string &name )
void CMutex::leave()
{
sem_init( const_cast<sem_t*>(&_Sem), 0, 1 );
SDL_UnlockMutex(m_SDLMutex);
}
// ***************************************************************************
/*
* Unix version
*/
CFairMutex::~CFairMutex()
CAtomicLock::CAtomicLock() : m_SDLSpinLock(0)
{
sem_destroy( const_cast<sem_t*>(&_Sem) ); // needs that no thread is waiting on the semaphore
}
/*
* Unix version
*/
void CFairMutex::enter()
CAtomicLock::~CAtomicLock()
{
sem_wait( const_cast<sem_t*>(&_Sem) );
}
/*
* Unix version
*/
void CFairMutex::leave()
void CAtomicLock::init()
{
sem_post( const_cast<sem_t*>(&_Sem) );
m_SDLSpinLock = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
*
*/
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 )
void CAtomicLock::enter()
{
// Create a semaphore set containing one semaphore
/*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;
SDL_AtomicLock(&m_SDLSpinLock);
}
/*
*
*/
void CSharedMutex::destroy()
void CAtomicLock::leave()
{
// Destroy the semaphore
union semun arg;
nlverifyex( semctl( _SemId, 0, IPC_RMID, arg ) != -1, ("semid=%d, err=%s", _SemId, strerror(errno) ) );
_SemId = -1;
}
/*
*
*/
void CSharedMutex::enter()
{
// Decrement the semaphore
sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
nlverify( semop( _SemId, &buf, 1 ) != -1);
}
/*
*
*/
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;
}
////////////////////////
////////////////////////
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()
{
if ( (this!=ATMutex ) && (ATMutex!=NULL) )
{
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 CFairMutex::debugEndEnter()
{
// printf("1");
/* 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 CFairMutex::debugLeave()
{
// printf( "0" );
/* 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();
}
SDL_AtomicUnlock(&m_SDLSpinLock);
}
#endif // MUTEX_DEBUG
// ***************************************************************************
} // NLMISC

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

@ -44,6 +44,8 @@
#include "nel/misc/command.h"
#include "nel/misc/variable.h"
#include <SDL_cpuinfo.h>
using namespace std;
#ifdef DEBUG_NEW
@ -903,188 +905,24 @@ uint64 CSystemInfo::getProcessorFrequency(bool quick)
return freq;
}
static bool DetectMMX()
bool CSystemInfo::hasMMX()
{
#ifdef NL_CPU_INTEL
if (!CSystemInfo::hasCPUID()) return false; // cpuid not supported ...
sint32 CPUInfo[4];
nlcpuid(CPUInfo, 1);
// check for bit 23 = MMX instruction set
if (CPUInfo[3] & 0x800000) return true;
#endif // NL_CPU_INTEL
return false;
return SDL_HasMMX();
}
static bool DetectSSE()
bool CSystemInfo::hasSSE()
{
#ifdef NL_CPU_INTEL
if (!CSystemInfo::hasCPUID()) return false; // cpuid not supported ...
sint32 CPUInfo[4];
nlcpuid(CPUInfo, 1);
if (CPUInfo[3] & 0x2000000)
{
// check OS support for SSE
try
{
#ifdef NL_OS_WINDOWS
#ifdef NL_NO_ASM
unsigned int tmp = _mm_getcsr();
nlunreferenced(tmp);
#else
__asm
{
xorps xmm0, xmm0 // Streaming SIMD Extension
}
#endif // NL_NO_ASM
#elif NL_OS_UNIX
__asm__ __volatile__ ("xorps %xmm0, %xmm0;");
#endif // NL_OS_UNIX
}
catch(...)
{
return false;
}
// printf("sse detected\n");
return true;
}
#endif // NL_CPU_INTEL
return false;
return SDL_HasSSE();
}
bool CSystemInfo::_HaveMMX = DetectMMX ();
bool CSystemInfo::_HaveSSE = DetectSSE ();
bool CSystemInfo::hasCPUID ()
bool CSystemInfo::hasSSE2()
{
#ifdef NL_CPU_INTEL
uint32 result = 0;
#ifdef NL_OS_WINDOWS
#ifdef NL_NO_ASM
sint32 CPUInfo[4] = {-1};
nlcpuid(CPUInfo, 0);
if (CPUInfo[3] != -1) result = 1;
#else
__asm
{
pushad
pushfd
// If ID bit of EFLAGS can change, then cpuid is available
pushfd
pop eax // Get EFLAG
mov ecx,eax
xor eax,0x200000 // Flip ID bit
push eax
popfd // Write EFLAGS
pushfd
pop eax // read back EFLAG
xor eax,ecx
je noCpuid // no flip -> no CPUID instr.
popfd // restore state
popad
mov result, 1
jmp CPUIDPresent
noCpuid:
popfd // restore state
popad
mov result, 0
CPUIDPresent:
}
#endif // NL_NO_ASM
#elif NL_OS_UNIX // NL_OS_WINDOWS
__asm__ __volatile__ (
/* Save Register */
"pushl %%ebp;"
"pushl %%ebx;"
"pushl %%edx;"
/* Check if this CPU supports cpuid */
"pushf;"
"pushf;"
"popl %%eax;"
"movl %%eax, %%ebx;"
"xorl $(1 << 21), %%eax;" // CPUID bit
"pushl %%eax;"
"popf;"
"pushf;"
"popl %%eax;"
"popf;" // Restore flags
"xorl %%ebx, %%eax;"
"jz NoCPUID;"
"movl $1, %0;"
"jmp CPUID;"
"NoCPUID:;"
"movl $0, %0;"
"CPUID:;"
"popl %%edx;"
"popl %%ebx;"
"popl %%ebp;"
:"=a"(result)
);
#endif // NL_OS_UNIX
return result == 1;
#else
return false;
#endif
return SDL_HasSSE2();
}
uint32 CSystemInfo::getCPUID()
uint CSystemInfo::getCPUCount()
{
#ifdef NL_CPU_INTEL
if(hasCPUID())
{
uint32 result = 0;
sint32 CPUInfo[4];
nlcpuid(CPUInfo, 1);
return CPUInfo[3];
}
#endif // NL_CPU_INTEL
return 0;
}
/*
* Note: Not used in NeL probably in Ryzom closed source. Not translated in AT&T asm, I don't understand the aim of this method
* Returns true if the CPU has HT, even if it is disabled. Maybe shoud count how many (virtual) core there is.
*/
bool CSystemInfo::hasHyperThreading()
{
#ifdef NL_OS_WINDOWS
if(hasCPUID())
{
sint32 CPUInfo[4];
// get vendor string from cpuid
char vendor_id[32];
memset(vendor_id, 0, sizeof(vendor_id));
nlcpuid(CPUInfo, 0);
memcpy(vendor_id, &CPUInfo[1], sizeof(sint32));
memcpy(vendor_id+4, &CPUInfo[3], sizeof(sint32));
memcpy(vendor_id+8, &CPUInfo[2], sizeof(sint32));
// get cpuid flags
nlcpuid(CPUInfo, 1);
// pentium 4 or later processor?
if ((((CPUInfo[0] & 0xf00) == 0xf00) || (CPUInfo[0] & 0xf00000)) &&
strcmp(vendor_id, "GenuineIntel") == 0)
return (CPUInfo[3] & 0x10000000)!=0; // Intel Processor Hyper-Threading
}
#endif
return false;
return SDL_GetCPUCount();
}
bool CSystemInfo::isNT()

@ -17,6 +17,8 @@
#include "stdmisc.h"
#include "nel/misc/system_utils.h"
#include <SDL_video.h>
#ifdef NL_OS_WINDOWS
#ifndef NL_COMP_MINGW
#define NOMINMAX
@ -234,37 +236,14 @@ bool CSystemUtils::isAzertyKeyboard()
bool CSystemUtils::isScreensaverEnabled()
{
bool res = false;
#ifdef NL_OS_WINDOWS
// old code, is not working anymore
// BOOL bRetValue;
// SystemParametersInfoA(SPI_GETSCREENSAVEACTIVE, 0, &bRetValue, 0);
// res = (bRetValue == TRUE);
HKEY hKeyScreenSaver = NULL;
LSTATUS lReturn = RegOpenKeyExA(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE, &hKeyScreenSaver);
if (lReturn == ERROR_SUCCESS)
{
DWORD dwType = 0L;
DWORD dwSize = KeyMaxLength;
unsigned char Buffer[KeyMaxLength] = {0};
lReturn = RegQueryValueExA(hKeyScreenSaver, TEXT("SCRNSAVE.EXE"), NULL, &dwType, NULL, &dwSize);
// if SCRNSAVE.EXE is present, check also if it's empty
if (lReturn == ERROR_SUCCESS)
res = (Buffer[0] != '\0');
}
RegCloseKey(hKeyScreenSaver);
#endif
return res;
return SDL_IsScreenSaverEnabled();
}
bool CSystemUtils::enableScreensaver(bool screensaver)
{
bool res = false;
#ifdef NL_OS_WINDOWS
res = (SystemParametersInfoA(SPI_SETSCREENSAVEACTIVE, screensaver ? TRUE:FALSE, NULL, 0) == TRUE);
#endif
return res;
if (screensaver) SDL_EnableScreenSaver();
else SDL_DisableScreenSaver();
return true;
}
std::string CSystemUtils::getRootKey()

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

@ -20,19 +20,14 @@
#include "nel/misc/sstring.h"
#include "nel/misc/thread.h"
#include <SDL_timer.h>
#include <SDL_atomic.h>
#ifdef NL_OS_WINDOWS
# ifndef NL_COMP_MINGW
# define NOMINMAX
# endif
# include <windows.h>
#elif defined (NL_OS_UNIX)
# include <sys/time.h>
# include <unistd.h>
#endif
#ifdef NL_OS_MAC
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
#ifdef DEBUG_NEW
@ -42,260 +37,22 @@
namespace NLMISC
{
namespace {
#ifdef NL_OS_WINDOWS
bool a_HaveQueryPerformance = false;
LARGE_INTEGER a_QueryPerformanceFrequency;
#endif
#ifdef NL_OS_UNIX
# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
# if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
# define NL_MONOTONIC_CLOCK
# endif
# endif
# ifdef NL_MONOTONIC_CLOCK
bool a_CheckedMonotonicClock = false;
bool a_HasMonotonicClock = false;
uint64 a_MonotonicClockFrequency = 0;
uint64 a_MonotonicClockResolutionNs = 0;
bool hasMonotonicClock()
void CTime::probeTimerInfo(CTime::CTimerInfo &result)
{
if (!a_CheckedMonotonicClock)
{
/* Initialize the local time engine.
* On Unix, this method will find out if the Monotonic Clock is supported
* (seems supported by kernel 2.6, not by kernel 2.4). See getLocalTime().
*/
struct timespec tv;
if ((clock_gettime( CLOCK_MONOTONIC, &tv ) == 0) &&
(clock_getres( CLOCK_MONOTONIC, &tv ) == 0))
{
// nldebug( "Monotonic local time supported (resolution %.6f ms)", ((float)tv.tv_sec)*1000.0f + ((float)tv.tv_nsec)/1000000.0f );
result.HighPrecisionResolution = SDL_GetPerformanceFrequency();
result.IsHighPrecisionAvailable = (result.HighPrecisionResolution > 1000);
if (tv.tv_sec > 0)
{
nlwarning("Monotonic clock not ok, resolution > 1s");
a_HasMonotonicClock = false;
}
else
{
uint64 nsPerTick = tv.tv_nsec;
uint64 nsPerSec = 1000000000L;
uint64 tickPerSec = nsPerSec / nsPerTick;
a_MonotonicClockFrequency = tickPerSec;
a_MonotonicClockResolutionNs = nsPerTick;
a_HasMonotonicClock = true;
}
}
else
{
a_HasMonotonicClock = false;
}
a_CheckedMonotonicClock = true;
if (result.HighPrecisionResolution == 14318180)
{
nldebug("Detected known HPET era timer frequency");
}
return a_HasMonotonicClock;
}
# endif
#endif
}
void CTime::probeTimerInfo(CTime::CTimerInfo &result)
{
breakable
if (result.HighPrecisionResolution == 3579545)
{
#ifdef NL_OS_WINDOWS
LARGE_INTEGER winPerfFreq;
LARGE_INTEGER winPerfCount;
DWORD lowResTime;
if (!QueryPerformanceFrequency(&winPerfFreq))
{
nldebug("Cannot query performance frequency");
result.IsHighPrecisionAvailable = false;
}
else
{
result.HighPrecisionResolution = winPerfFreq.QuadPart;
}
if (winPerfFreq.QuadPart == 1000)
{
nldebug("Higher precision timer not available, OS defaulted to GetTickCount");
result.IsHighPrecisionAvailable = false;
}
if (!QueryPerformanceCounter(&winPerfCount))
{
nldebug("Cannot query performance counter");
result.IsHighPrecisionAvailable = false;
result.HighPrecisionResolution = 1000;
}
a_HaveQueryPerformance = result.IsHighPrecisionAvailable;
a_QueryPerformanceFrequency.QuadPart = winPerfFreq.QuadPart;
if (!result.IsHighPrecisionAvailable)
{
lowResTime = timeGetTime();
}
#else
// Other platforms are awesome. Generic implementation for now.
TTime localTime = getLocalTime();
result.IsHighPrecisionAvailable = true;
result.HighPrecisionResolution = 0;
# ifdef NL_MONOTONIC_CLOCK
timespec monoClock;
if (hasMonotonicClock())
{
clock_gettime(CLOCK_MONOTONIC, &monoClock);
result.HighPrecisionResolution = a_MonotonicClockFrequency;
}
else
{
nldebug("Monotonic clock not available");
}
# endif
#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");
}
if (result.HighPrecisionResolution == 3579545)
{
nldebug("Detected known AHCI era timer frequency");
}
if (result.HighPrecisionResolution == 1193182)
{
nldebug("Detected known i8253/i8254 era timer frequency");
}
nldebug("Detected known AHCI era timer frequency");
}
if (result.HighPrecisionResolution == 1193182)
{
nldebug("Detected known i8253/i8254 era timer frequency");
}
}
@ -303,7 +60,7 @@ void CTime::probeTimerInfo(CTime::CTimerInfo &result)
* coordinated universal time, according to the system clock.
* This values is the same on all computer if computers are synchronized (with NTP for example).
*/
uint32 CTime::getSecondsSince1970 ()
uint32 CTime::getSecondsSince1970()
{
return uint32(time(NULL));
}
@ -324,192 +81,60 @@ uint32 CTime::getSecondsSince1970 ()
// return nl_mktime(timeinfo);
//}
static uint32 s_LastTicks = 0;
static sint64 s_LocalTime = 0;
SDL_SpinLock s_TimeLock = 0;
/* Return the local time in milliseconds.
* Use it only to measure time difference, the absolute value does not mean anything.
* On Unix, getLocalTime() will try to use the Monotonic Clock if available, otherwise
* the value can jump backwards if the system time is changed by a user or a NTP time sync process.
* The value is different on 2 different computers; use the CUniTime class to get a universal
* time that is the same on all computers.
* \warning On Win32, the value is on 32 bits only. It wraps around to 0 every about 49.71 days.
*/
TTime CTime::getLocalTime ()
TTime CTime::getLocalTime()
{
#ifdef NL_OS_WINDOWS
//static bool initdone = false;
//static bool byperfcounter;
// Initialization
//if ( ! initdone )
//{
//byperfcounter = (getPerformanceTime() != 0);
//initdone = true;
//}
/* Retrieve time is ms
* Why do we prefer getPerformanceTime() to timeGetTime() ? Because on one dual-processor Win2k
* PC, we have noticed that timeGetTime() slows down when the client is running !!!
*/
/* Now we have noticed that on all WinNT4 PC the getPerformanceTime can give us value that
* are less than previous
*/
//if ( byperfcounter )
//{
// return (TTime)(ticksToSecond(getPerformanceTime()) * 1000.0f);
//}
//else
//{
// This is not affected by system time changes. But it cycles every 49 days.
// return timeGetTime(); // Only this was left active before it was commented.
//}
/*
* The above is no longer relevant.
*/
if (a_HaveQueryPerformance)
// NOTE: This function is managed to wrap at the TTime boundary
sint64 localTime;
if (SDL_AtomicTryLock(&s_TimeLock))
{
// On a (fast) 15MHz timer this rolls over after 7000 days.
// If my calculations are right.
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
counter.QuadPart *= (LONGLONG)1000L;
counter.QuadPart /= a_QueryPerformanceFrequency.QuadPart;
return counter.QuadPart;
// Only one thread can check the clock at once. Please cache results of getLocalTime where possible
uint32 ticks = SDL_GetTicks();
uint32 delta = ticks - s_LastTicks;
localTime = s_LocalTime;
if (delta)
{
s_LastTicks = ticks;
if (delta < (15 * 60 * 1000)) // Time difference since last call must be less than 15 minutes
{
localTime += (sint64)delta;
s_LocalTime = localTime;
}
}
SDL_AtomicUnlock(&s_TimeLock);
}
else
{
// Use default reliable low resolution timer.
return timeGetTime();
}
#elif defined (NL_OS_UNIX)
#ifdef NL_MONOTONIC_CLOCK
if (hasMonotonicClock())
{
timespec tv;
// This is not affected by system time changes.
if ( clock_gettime( CLOCK_MONOTONIC, &tv ) != 0 )
nlerror ("Can't get clock time again");
return (TTime)tv.tv_sec * (TTime)1000 + (TTime)((tv.tv_nsec/*+500*/) / 1000000);
// If another thread is checking the clock simultaneously, return it's result
SDL_AtomicLock(&s_TimeLock);
localTime = s_LocalTime;
SDL_AtomicUnlock(&s_TimeLock);
}
#endif
// This is affected by system time changes.
struct timeval tv;
if ( gettimeofday( &tv, NULL) != 0 )
nlerror ("Can't get time of day");
return (TTime)tv.tv_sec * (TTime)1000 + (TTime)tv.tv_usec / (TTime)1000;
#endif
return localTime;
}
/* Return the time in processor ticks. Use it for profile purpose.
* If the performance time is not supported on this hardware, it returns 0.
* \warning On a multiprocessor system, the value returned by each processor may
* be different. The only way to workaround this is to set a processor affinity
* to the measured thread.
* \warning The speed of tick increase can vary (especially on laptops or CPUs with
* power management), so profiling several times and computing the average could be
* a wise choice.
* If the performance time is not supported on this hardware, it returns getLocalTime().
*/
TTicks CTime::getPerformanceTime ()
TTicks CTime::getPerformanceTime()
{
#ifdef NL_OS_WINDOWS
LARGE_INTEGER ret;
if (QueryPerformanceCounter (&ret))
return ret.QuadPart;
else
return 0;
#elif defined(NL_OS_MAC)
return mach_absolute_time();
#else
#if defined(HAVE_X86_64)
uint64 hi, lo;
__asm__ volatile (".byte 0x0f, 0x31" : "=a" (lo), "=d" (hi));
return (hi << 32) | (lo & 0xffffffff);
#elif defined(HAVE_X86) and !defined(NL_OS_MAC)
uint64 x;
// RDTSC - Read time-stamp counter into EDX:EAX.
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
#else // HAVE_X86
static bool firstWarn = true;
if (firstWarn)
{
nlwarning ("TTicks CTime::getPerformanceTime () is not implemented for your processor, returning 0");
firstWarn = false;
}
return 0;
#endif // HAVE_X86
#endif // NL_OS_WINDOWS
return SDL_GetPerformanceCounter();
}
/*
#define GETTICKS(t) asm volatile ("push %%esi\n\t" "mov %0, %%esi" : : "r" (t)); \
asm volatile ("push %eax\n\t" "push %edx"); \
asm volatile ("rdtsc"); \
asm volatile ("movl %eax, (%esi)\n\t" "movl %edx, 4(%esi)"); \
asm volatile ("pop %edx\n\t" "pop %eax\n\t" "pop %esi");
*/
/* Convert a ticks count into second. If the performance time is not supported on this
* hardware, it returns 0.0.
*/
double CTime::ticksToSecond (TTicks ticks)
double CTime::ticksToSecond(TTicks ticks)
{
#ifdef NL_OS_WINDOWS
LARGE_INTEGER ret;
if (QueryPerformanceFrequency(&ret))
{
return (double)(sint64)ticks/(double)ret.QuadPart;
}
else
#elif defined(NL_OS_MAC)
{
static double factor = 0.0;
if (factor == 0.0)
{
mach_timebase_info_data_t tbInfo;
mach_timebase_info(&tbInfo);
factor = 1000000000.0 * (double)tbInfo.numer / (double)tbInfo.denom;
}
return double(ticks / factor);
}
#endif // NL_OS_WINDOWS
{
static bool benchFrequency = true;
static sint64 freq = 0;
if (benchFrequency)
{
// try to have an estimation of the cpu frequency
TTicks tickBefore = getPerformanceTime ();
TTicks tickAfter = tickBefore;
TTime timeBefore = getLocalTime ();
TTime timeAfter = timeBefore;
for(;;)
{
if (timeAfter - timeBefore > 1000)
break;
timeAfter = getLocalTime ();
tickAfter = getPerformanceTime ();
}
TTime timeDelta = timeAfter - timeBefore;
TTicks tickDelta = tickAfter - tickBefore;
freq = 1000 * tickDelta / timeDelta;
benchFrequency = false;
}
return (double)(sint64)ticks/(double)freq;
}
return (double)(sint64)ticks / (double)(sint64)SDL_GetPerformanceFrequency();
}

@ -1,611 +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"
#ifndef NL_COMP_MINGW
#define NOMINMAX
#endif
#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;

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

@ -79,7 +79,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 );
@ -951,7 +951,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();

@ -562,7 +562,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;
@ -1268,7 +1268,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;

@ -99,7 +99,7 @@ void CStreamSource::releasePhysicalSource()
uint32 CStreamSource::getTime()
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
if (hasPhysicalSource())
return getPhysicalSource()->getTime();
@ -117,7 +117,7 @@ void CStreamSource::setLooping(bool l)
{
CSourceCommon::setLooping(l);
//CAutoMutex<CMutex> autoMutex(m_BufferMutex);
//CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
//
//CSourceCommon::setLooping(l);
//if (hasPhysicalSource())
@ -150,7 +150,7 @@ void CStreamSource::play()
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 ((_RelativeMode ? getPos().sqrnorm() : (mixer->getListenPosVector() - getPos()).sqrnorm()) > m_StreamSound->getMaxDistance() * m_StreamSound->getMaxDistance())
@ -277,7 +277,7 @@ void CStreamSource::play()
void CStreamSource::stopInt()
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
// nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
// nlassert(_Playing);
@ -321,7 +321,7 @@ void CStreamSource::stop()
void CStreamSource::setPos(const NLMISC::CVector& pos)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setPos(pos);
if (hasPhysicalSource())
@ -330,7 +330,7 @@ void CStreamSource::setPos(const NLMISC::CVector& pos)
void CStreamSource::setVelocity(const NLMISC::CVector& vel)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setVelocity(vel);
if (hasPhysicalSource())
@ -342,7 +342,7 @@ void CStreamSource::setVelocity(const NLMISC::CVector& vel)
*/
void CStreamSource::setDirection(const NLMISC::CVector& dir)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setDirection(dir);
@ -373,7 +373,7 @@ void CStreamSource::setDirection(const NLMISC::CVector& dir)
void CStreamSource::updateFinalGain()
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
if (hasPhysicalSource())
getPhysicalSource()->setGain(getFinalGain());
@ -381,7 +381,7 @@ void CStreamSource::updateFinalGain()
void CStreamSource::setPitch(float pitch)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
m_PitchInv = 1.0f / pitch;
CSourceCommon::setPitch(pitch);
if (hasPhysicalSource())
@ -390,7 +390,7 @@ void CStreamSource::setPitch(float pitch)
void CStreamSource::setSourceRelativeMode(bool mode)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
CSourceCommon::setSourceRelativeMode(mode);
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.
uint8 *CStreamSource::lock(uint capacity)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
updateAvailableBuffers();
if (m_FreeBuffers > 0)
return m_Buffers[m_NextBuffer]->lock(capacity);
@ -440,7 +440,7 @@ bool CStreamSource::unlock(uint size)
{
nlassert(m_FreeBuffers > 0);
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CAutoMutex<CFastMutex> autoMutex(m_BufferMutex);
IBuffer *buffer = m_Buffers[m_NextBuffer];
bool result = buffer->unlock(size);

@ -151,7 +151,7 @@ public:
void tasksAndThreads()
{
// test running task in two separate thread (this stress the
// test running task in two separate thread (this stress the
// multithreading support of task). CoTask API ;ake use of
// thread local storage API to store by thread current task info.
@ -159,7 +159,7 @@ public:
result2.clear();
CTaskThread tt;
NLMISC::IThread *th = NLMISC::IThread::create(&tt);
NLMISC::CThread *th = NLMISC::CThread::create(&tt);
CTask2 t2;
@ -196,7 +196,7 @@ public:
TEST_ASSERT(referenceResultThread2[i] == result[i]);
}
}
void runTasks()
{
/// Run two main task and two working task at once and check that the result

@ -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;
};

@ -63,7 +63,7 @@ string deleteFile (const string &filename, bool throwException=true)
void setVersion(const std::string &version)
{
string fn = "VERSION";
setRWAccess(fn);
FILE *fp = fopen (fn.c_str(), "wb");
if (fp == NULL)
@ -105,16 +105,16 @@ string getVersion()
class CPatchThread : public IRunnable
{
public:
CPatchThread(const string &sp, const string &sv, const std::string &urlOk, const std::string &urlFailed, const std::string &logSeparator) :
ServerPath (sp), ServerVersion(sv), UrlOk(urlOk), UrlFailed(urlFailed), Ended(false), StateChanged(true), LogSeparator(logSeparator)
{
}
bool Ended; // true if the thread have ended the patch
bool PatchOk; // true if the patch was good
string Url; // url to display after the patch
string State;
string StateLog;
bool StateChanged;
@ -136,7 +136,7 @@ private:
string ClientPatchPath = "./patch/";
string ServerRootPath = CPath::standardizePath (ServerPath);
string DisplayedServerRootPath; // contains the serverpath without login and password
uint pos = ServerRootPath.find ("@");
if (pos != string::npos)
{
@ -198,7 +198,7 @@ private:
const char *gzerr = gzerror (gz, &gzerrno);
throw Exception ("Can't read '%s' : code=%d %s", DirFilename.c_str(), gzerrno, gzerr);
}
string b = buffer;
uint pos1 = b.find ("/");
uint pos2 = b.find ("/", pos1+1);
@ -238,9 +238,9 @@ private:
string path = ClientPatchPath + needToGetFilesList[i].Filename;
nlinfo ("Get the file from '%s' to '%s'", string(DisplayedServerRootPath+needToGetFilesList[i].Filename).c_str(), path.c_str());
// get the new file
downloadFile (ServerRootPath+needToGetFilesList[i].Filename+".ngz", path+".ngz");
// decompress it
decompressFile (path+".ngz", needToGetFilesList[i].Date);
@ -280,7 +280,7 @@ private:
// special case for nel_launcher.exe
if (needToGetFilesList[i].Filename == "nel_launcher.exe")
continue;
string path = ClientRootPath+needToGetFilesList[i].Filename;
if (!NLMISC::CFile::fileExists (path))
{
@ -308,7 +308,7 @@ private:
}
// now, we have to delete files that are not in the server list
setState(true, "Scanning patch directory");
vector<string> res;
CPath::getPathContent(ClientPatchPath, false, false, true, res);
@ -337,11 +337,11 @@ private:
setState (true, "Deleting %s", DirFilename.c_str());
string err = deleteFile (DirFilename, false);
if (!err.empty()) setState(true, err.c_str());
// now that all is ok, we set the new client version
setState (true, "set client version to %s", ServerVersion.c_str ());
setVersion (ServerVersion);
if (needToExecuteAPatch)
{
setState (true, "Launching patch_execute.bat");
@ -358,7 +358,7 @@ private:
nlinfo ("Patching completed");
setState (true, "Patching completed");
Url = UrlOk;
PatchOk = true;
Ended = true;
@ -401,12 +401,12 @@ private:
if (fp == NULL)
{
string err = toString("Can't open file '%s' : code=%d %s", dest.c_str(), errno, strerror(errno));
gzclose(gz);
deleteFile (filename);
throw Exception (err);
}
uint8 buffer[10000];
while (!gzeof(gz))
{
@ -473,7 +473,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetOpen() failed: %s (ec %d)", errorstr.c_str(), errcode);
}
}
@ -523,7 +523,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetOpenUrl() failed on file '%s': %s (ec %d)", source.c_str (), errorstr.c_str(), errcode);
}
else
@ -543,7 +543,7 @@ private:
deleteFile (dest);
throw Exception (err);
}
CurrentBytesToGet += realSize;
if (TotalBytesToGet == 0 && TotalFilesToGet == 0)
@ -568,7 +568,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetCloseHandle() failed on file '%s': %s (ec %d)", source.c_str (), errorstr.c_str(), errcode);
}
}
@ -611,11 +611,11 @@ void startPatchThread (const std::string &serverPath, const std::string &serverV
nlwarning ("patch thread already running");
return;
}
PatchThread = new CPatchThread (serverPath, serverVersion, urlOk, urlFailed, logSeparator);
nlassert (PatchThread != NULL);
IThread *thread = IThread::create (PatchThread);
CThread *thread = CThread::create (PatchThread);
nlassert (thread != NULL);
thread->start ();
}

@ -96,7 +96,7 @@ string deleteFile (const string &filename, bool throwException=true)
void setVersion(const std::string &version)
{
string fn = "VERSION";
setRWAccess(fn);
FILE *fp = fopen (fn.c_str(), "wb");
if (fp == NULL)
@ -138,16 +138,16 @@ string getVersion()
class CPatchThread : public IRunnable
{
public:
CPatchThread(const string &sp, const string &sv, const std::string &urlOk, const std::string &urlFailed, const std::string &logSeparator) :
ServerPath (sp), ServerVersion(sv), UrlOk(urlOk), UrlFailed(urlFailed), Ended(false), StateChanged(true), LogSeparator(logSeparator)
{
}
bool Ended; // true if the thread have ended the patch
bool PatchOk; // true if the patch was good
string Url; // url to display after the patch
string State;
string StateLog;
bool StateChanged;
@ -158,7 +158,7 @@ private:
string ClientPatchPath; // the patch path (c:\ryzom\patch)
string ServerRootPath; // the root server path (http://www.toto.com)
string DisplayedServerRootPath; // contains the serverpath without login and password
// get a file and decompress it in the patch directory
void getFile (const CEntry &e)
{
@ -186,7 +186,7 @@ private:
ClientPatchPath = "./patch/";
ServerRootPath = CPath::standardizePath (ServerPath);
DisplayedServerRootPath; // contains the serverpath without login and password
uint pos = ServerRootPath.find ("@");
if (pos != string::npos)
{
@ -248,7 +248,7 @@ private:
const char *gzerr = gzerror (gz, &gzerrno);
throw Exception ("Can't read '%s' : code=%d %s", DirFilename.c_str(), gzerrno, gzerr);
}
string b = buffer;
uint pos1 = b.find ("/");
uint pos2 = b.find ("/", pos1+1);
@ -280,7 +280,7 @@ private:
// nel_launcher.exe and relaunch it now
bool patchExe = false, patchCfg = false, patchBat = false;
uint i;
for (i = 0; i < needToGetFilesList.size(); i++)
@ -307,42 +307,42 @@ private:
if (patchBat)
{
setState (true, true, "Launching %s", RelaunchNelLauncherBatchFilename.c_str());
//if (_execlp ("update_nel_launcher.bat", "update_nel_launcher.bat", NULL) == -1)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
// Flag permettant de prendre en compte wShowWindow
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)RelaunchNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)RelaunchNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
)
{
// error occurs during the launch
string str = toString("Can't execute '%s': code=%d %s", RelaunchNelLauncherBatchFilename.c_str(), errno, strerror(errno));
throw Exception (str);
}
// Close process and thread handles.
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
exit(0);
}
else if (patchExe || patchCfg)
@ -355,7 +355,7 @@ private:
}
fprintf(fp, "@echo off\n");
if (patchExe)
{
nlinfo ("Need to special patch '%s'",NelLauncherFilename.c_str());
@ -379,52 +379,52 @@ private:
}
fprintf(fp, "start %s\n", NelLauncherFilename.c_str());
fclose (fp);
// remove the files list file
setState (true, true, "Deleting %s", DirFilename.c_str());
string err = deleteFile (DirFilename, false);
if (!err.empty()) setState(true, true, err.c_str());
// launching the .bat
setState (true, true, "Launching %s", UpdateNelLauncherBatchFilename.c_str());
//if (_execlp ("update_nel_launcher.bat", "update_nel_launcher.bat", NULL) == -1)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
// Flag permettant de prendre en compte wShowWindow
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)UpdateNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)UpdateNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
)
{
// error occurs during the launch
string str = toString("Can't execute '%s': code=%d %s", UpdateNelLauncherBatchFilename.c_str(), errno, strerror(errno));
throw Exception (str);
}
// Close process and thread handles.
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
exit(0);
}
@ -442,12 +442,12 @@ private:
{
executeFinalizeBat = true;
}
// put the file in the ryzom patch directory
string path = ClientPatchPath + needToGetFilesList[i].Filename;
//nldebug ("path '%s' -> %d %s", path.c_str(), NLMISC::CFile::fileExists (ClientRootPath + needToGetFilesList[i].Filename), strlwr(NLMISC::CFile::getExtension(needToGetFilesList[i].Filename)).c_str());
// move dll exe and already existing file in the root directory
if (NLMISC::CFile::fileExists (ClientRootPath + needToGetFilesList[i].Filename) ||
strlwr(NLMISC::CFile::getExtension(needToGetFilesList[i].Filename)) == "dll" ||
@ -471,7 +471,7 @@ private:
}
// now, we have to delete files that are not in the server list
setState(true, true, "Scanning patch directory");
vector<string> res;
CPath::getPathContent(ClientPatchPath, false, false, true, res);
@ -512,10 +512,10 @@ private:
setState (true, true, "Launching %s", fn.c_str());
system(fn.c_str());
}
// it s the end of the patch process
setState (true, true, "Patching completed");
Url = UrlOk;
PatchOk = true;
Ended = true;
@ -558,12 +558,12 @@ private:
if (fp == NULL)
{
string err = toString("Can't open file '%s' : code=%d %s", dest.c_str(), errno, strerror(errno));
gzclose(gz);
deleteFile (filename);
throw Exception (err);
}
uint32 currentSize = 0;
uint8 buffer[10000];
while (!gzeof(gz))
@ -633,7 +633,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetOpen() failed: %s (ec %d)", errorstr.c_str(), errcode);
}
}
@ -683,7 +683,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetOpenUrl() failed on file '%s': %s (ec %d)", source.c_str (), errorstr.c_str(), errcode);
}
else
@ -703,7 +703,7 @@ private:
deleteFile (dest);
throw Exception (err);
}
CurrentBytesToGet += realSize;
if (TotalBytesToGet == 0 && TotalFilesToGet == 0)
@ -728,7 +728,7 @@ private:
errorstr = (LPCTSTR)lpMsgBuf;
}
LocalFree(lpMsgBuf);
throw Exception ("InternetCloseHandle() failed on file '%s': %s (ec %d)", source.c_str (), errorstr.c_str(), errcode);
}
}
@ -742,7 +742,7 @@ private:
nlinfo (str);
State = str;
if(log)
{
{
StateLog += str;
StateLog += LogSeparator;
}
@ -773,11 +773,11 @@ void startPatchThread (const std::string &serverPath, const std::string &serverV
nlwarning ("patch thread already running");
return;
}
PatchThread = new CPatchThread (serverPath, serverVersion, urlOk, urlFailed, logSeparator);
nlassert (PatchThread != NULL);
IThread *thread = IThread::create (PatchThread);
CThread *thread = CThread::create (PatchThread);
nlassert (thread != NULL);
thread->start ();
}

@ -110,7 +110,7 @@ void setVersion(const std::string &version)
if(VerboseLog) nlinfo("setVersion to '%s'", version.c_str());
string fn = "VERSION";
setRWAccess(fn);
FILE *fp = fopen (fn.c_str(), "wb");
if (fp == NULL)
@ -157,16 +157,16 @@ int myProgressFunc(void *foo, double t, double d, double ultotal, double ulnow);
class CPatchThread : public IRunnable
{
public:
CPatchThread(const string &sp, const string &sv, const std::string &urlOk, const std::string &urlFailed, const std::string &logSeparator) :
ServerPath (sp), ServerVersion(sv), UrlOk(urlOk), UrlFailed(urlFailed), Ended(false), StateChanged(true), LogSeparator(logSeparator)
{
}
bool Ended; // true if the thread have ended the patch
bool PatchOk; // true if the patch was good
string Url; // url to display after the patch
string State;
string StateLog;
bool StateChanged;
@ -177,7 +177,7 @@ private:
string ClientPatchPath; // the patch path (c:\ryzom\patch)
string ServerRootPath; // the root server path (http://www.toto.com)
string DisplayedServerRootPath; // contains the serverpath without login and password
// get a file and decompress it in the patch directory
void getFile (const CEntry &e)
{
@ -207,7 +207,7 @@ private:
ClientPatchPath = "./patch/";
ServerRootPath = CPath::standardizePath (ServerPath)+ServerVersion+"/";
DisplayedServerRootPath; // contains the serverpath without login and password
uint pos = ServerRootPath.find ("@");
if (pos != string::npos)
{
@ -269,7 +269,7 @@ private:
const char *gzerr = gzerror (gz, &gzerrno);
throw Exception ("Can't read '%s' : code=%d %s (error code 27)", DirFilename.c_str(), gzerrno, gzerr);
}
string b = buffer;
uint pos1 = b.find ("/");
uint pos2 = b.find ("/", pos1+1);
@ -309,7 +309,7 @@ private:
// nel_launcher.exe and relaunch it now
bool patchExe = false, patchCfg = false, patchBat = false;
uint i;
for (i = 0; i < needToGetFilesList.size(); i++)
@ -336,42 +336,42 @@ private:
if (patchBat)
{
setState (true, true, "Launching %s", RelaunchNelLauncherBatchFilename.c_str());
//if (_execlp ("update_nel_launcher.bat", "update_nel_launcher.bat", NULL) == -1)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
// Flag permettant de prendre en compte wShowWindow
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)RelaunchNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)RelaunchNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
)
{
// error occurs during the launch
string str = toString("Can't execute '%s': code=%d %s (error code 28)", RelaunchNelLauncherBatchFilename.c_str(), errno, strerror(errno));
throw Exception (str);
}
// Close process and thread handles.
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
exit(0);
}
else if (patchExe || patchCfg)
@ -384,7 +384,7 @@ private:
}
fprintf(fp, "@echo off\n");
if (patchExe)
{
nlinfo ("Need to special patch '%s'",NelLauncherFilename.c_str());
@ -408,52 +408,52 @@ private:
}
fprintf(fp, "start %s\n", NelLauncherFilename.c_str());
fclose (fp);
// remove the files list file
setState (true, true, "Deleting %s", DirFilename.c_str());
string err = deleteFile (DirFilename, false);
if (!err.empty()) setState(true, true, err.c_str());
// launching the .bat
setState (true, true, "Launching %s", UpdateNelLauncherBatchFilename.c_str());
//if (_execlp ("update_nel_launcher.bat", "update_nel_launcher.bat", NULL) == -1)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
// Flag permettant de prendre en compte wShowWindow
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)UpdateNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
(char*)UpdateNelLauncherBatchFilename.c_str(), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
)
{
// error occurs during the launch
string str = toString("Can't execute '%s': code=%d %s (error code 30)", UpdateNelLauncherBatchFilename.c_str(), errno, strerror(errno));
throw Exception (str);
}
// Close process and thread handles.
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
quit();
}
@ -471,12 +471,12 @@ private:
{
executeFinalizeBat = true;
}
// put the file in the ryzom patch directory
string path = ClientPatchPath + needToGetFilesList[i].Filename;
//nldebug ("path '%s' -> %d %s", path.c_str(), NLMISC::CFile::fileExists (ClientRootPath + needToGetFilesList[i].Filename), strlwr(NLMISC::CFile::getExtension(needToGetFilesList[i].Filename)).c_str());
// move dll exe and already existing file in the root directory
if (NLMISC::CFile::fileExists (ClientRootPath + needToGetFilesList[i].Filename) ||
strlwr(NLMISC::CFile::getExtension(needToGetFilesList[i].Filename)) == "dll" ||
@ -500,7 +500,7 @@ private:
}
// now, we have to delete files that are not in the server list
setState(true, true, "Scanning patch directory");
vector<string> res;
CPath::getPathContent(ClientPatchPath, false, false, true, res);
@ -541,10 +541,10 @@ private:
setState (true, true, "Launching %s", fn.c_str());
system(fn.c_str());
}
// it s the end of the patch process
setState (true, true, "Patching completed");
Url = UrlOk;
PatchOk = true;
Ended = true;
@ -590,12 +590,12 @@ private:
if (fp == NULL)
{
string err = toString("Can't open file '%s' : code=%d %s, (error code 32)", dest.c_str(), errno, strerror(errno));
gzclose(gz);
deleteFile (filename);
throw Exception (err);
}
if(VerboseLog) nlinfo("Entering the while loop decompression");
uint32 currentSize = 0;
@ -656,7 +656,7 @@ private:
}
if(VerboseLog) nlinfo("Exiting the decompressing file");
}
void downloadFileWithCurl (const string &source, const string &dest)
{
#ifdef USE_CURL
@ -723,7 +723,7 @@ private:
// file not found, delete it
NLMISC::CFile::deleteFile(dest.c_str());
throw Exception ("curl download failed: (ec %d %d)", res, r);
}
}
#else
throw Exception("USE_CURL is not defined, no curl method");
#endif
@ -747,7 +747,7 @@ private:
uint8 buffer[bufferSize];
if(VerboseLog) nlinfo("downloadFile '%s'", dest.c_str());
if (RootInternet == NULL)
{
RootInternet = InternetOpen("nel_launcher", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
@ -768,7 +768,7 @@ private:
{
errorstr = "FormatMessage can't get the message";
}
throw Exception ("InternetOpen() failed: %s (ec %d) (error code 35)", errorstr.c_str(), errcode);
}
}
@ -826,7 +826,7 @@ private:
{
errorstr = "FormatMessage can't get the message";
}
fclose(fp);
deleteFile (dest);
@ -849,7 +849,7 @@ private:
deleteFile (dest);
throw Exception (err);
}
CurrentBytesToGet += realSize;
if (TotalBytesToGet == 0 && TotalFilesToGet == 0)
@ -878,7 +878,7 @@ private:
{
errorstr = "FormatMessage can't get the message";
}
throw Exception ("InternetCloseHandle() failed on file '%s': %s (ec %d) (error code 40)", source.c_str (), errorstr.c_str(), errcode);
}
}
@ -892,7 +892,7 @@ private:
nlinfo (str);
State = str;
if(log)
{
{
StateLog += str;
StateLog += LogSeparator;
}
@ -907,7 +907,7 @@ private:
string UrlOk;
string UrlFailed;
friend int myProgressFunc(void *foo, double t, double d, double ultotal, double ulnow);
friend int myProgressFunc(void *foo, double t, double d, double ultotal, double ulnow);
public:
uint TotalFilesToGet;
@ -917,7 +917,7 @@ public:
};
CPatchThread *PatchThread = NULL;
IThread *thread = NULL;
CThread *thread = NULL;
int myProgressFunc(void *foo, double t, double d, double ultotal, double ulnow)
{
@ -936,11 +936,11 @@ void startPatchThread (const std::string &serverPath, const std::string &serverV
nlwarning ("patch thread already running");
return;
}
PatchThread = new CPatchThread (serverPath, serverVersion, urlOk, urlFailed, logSeparator);
nlassert (PatchThread != NULL);
thread = IThread::create (PatchThread);
thread = CThread::create (PatchThread);
nlassert (thread != NULL);
thread->start ();
}

@ -78,6 +78,7 @@ IF(APPLE)
ENDIF(APPLE)
INCLUDE_DIRECTORIES(
${SDL2_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${LIBXML2_INCLUDE_DIR}
${LUA_INCLUDE_DIR}
@ -97,6 +98,7 @@ TARGET_LINK_LIBRARIES(ryzom_client
ryzom_clientsheets
ryzom_gameshare
nelpacs
${SDL2_LIBRARY}
${LIBXML2_LIBRARIES}
${LUA_LIBRARIES}
${LUABIND_LIBRARIES}

@ -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;

@ -32,6 +32,8 @@
#include <csignal>
#endif
#include <SDL.h>
#ifdef NL_OS_MAC
#include <stdio.h>
#include <sys/resource.h>
@ -119,6 +121,41 @@ static void sigHandler(int Sig)
}
#endif
extern const unsigned char splash_screen[];
extern const unsigned int splash_screenSize;
SDL_Window *s_SplashScreen = NULL;
SDL_Renderer *s_SplashRenderer = NULL;
void createSplashScreen()
{
SDL_RWops *rw = SDL_RWFromMem(const_cast<void *>((const void *)splash_screen), splash_screenSize);
SDL_Surface *surf = SDL_LoadBMP_RW(rw, 1); // 1 releases rw stream on surface free
s_SplashScreen = SDL_CreateWindow("Ryzom Core", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 435, 362, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS);
s_SplashRenderer = SDL_CreateRenderer(s_SplashScreen, -1, SDL_RENDERER_SOFTWARE);
SDL_Texture *tex = SDL_CreateTextureFromSurface(s_SplashRenderer, surf);
SDL_FreeSurface(surf);
SDL_RenderCopy(s_SplashRenderer, tex, NULL, NULL);
SDL_RenderPresent(s_SplashRenderer);
SDL_DestroyTexture(tex);
}
void pumpSplashScreen()
{
SDL_PumpEvents();
SDL_RenderPresent(s_SplashRenderer);
}
void destroySplashScreen()
{
if (s_SplashScreen)
{
SDL_DestroyRenderer(s_SplashRenderer);
s_SplashRenderer = NULL;
SDL_DestroyWindow(s_SplashScreen);
s_SplashScreen = NULL;
}
}
//---------------------------------------------------
// MAIN :
// Entry for the Application.
@ -361,6 +398,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR cm
int main(int argc, char **argv)
#endif
{
// TODO: Test new splash screen on Windows
#ifndef NL_OS_WINDOW
createSplashScreen();
#endif
// init the Nel context
CApplicationContext *appContext = new CApplicationContext;
@ -519,7 +561,7 @@ int main(int argc, char **argv)
#else
// TODO for Linux : splashscreen
pumpSplashScreen();
if (argc >= 4)
{

@ -105,6 +105,8 @@
#include <windows.h>
extern HINSTANCE HInstance;
extern HWND SlashScreen;
#else
void destroySplashScreen();
#endif // NL_OS_WINDOWS
#include "app_bundle_utils.h"
@ -378,42 +380,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;
}
void displayCPUInfo()
{
nlinfo("CPUInfo: CPUMask before change: %x, after change: %x, CPUID: %x, hasHyperThreading: %s", (uint32)Debug_OldCPUMask, (uint32)Debug_NewCPUMask, CSystemInfo::getCPUID(), (CSystemInfo::hasHyperThreading()?"YES":"NO"));
}
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;
@ -421,10 +392,6 @@ string getSystemInformation()
s += "Process Virtual Memory: " + bytesToHumanReadable(CSystemInfo::virtualMemory()) + "\n";
s += "OS: " + CSystemInfo::getOS() + "\n";
s += "Processor: " + CSystemInfo::getProc() + "\n";
s += toString("CPUID: %x\n", CSystemInfo::getCPUID());
s += toString("HT: %s\n", CSystemInfo::hasHyperThreading()?"YES":"NO");
s += toString("CpuMask: %x\n", IProcess::getCurrentProcess ()->getCPUMask());
if(Driver)
s += "NeL3D: " + string(Driver->getVideocardInformation()) + "\n";
@ -748,12 +715,10 @@ void prelogInit()
#ifdef NL_OS_WINDOWS
_control87 (_EM_INVALID|_EM_DENORMAL/*|_EM_ZERODIVIDE|_EM_OVERFLOW*/|_EM_UNDERFLOW|_EM_INEXACT, _MCW_EM);
#endif // NL_OS_WINDOWS
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
NLMISC::TTime initStart = ryzomGetLocalTime ();
@ -794,9 +759,6 @@ void prelogInit()
setCrashCallback(crashCallback);
// Display Some Info On CPU
displayCPUInfo();
// Display the client version.
#if FINAL_VERSION
nlinfo("RYZOM VERSION : FV %s ("__DATE__" "__TIME__")", RYZOM_VERSION);
@ -943,7 +905,7 @@ void prelogInit()
Driver->setSwapVBLInterval(1);
else
Driver->setSwapVBLInterval(0);
if (StereoDisplay) // VR_CONFIG // VR_DRIVER
{
// override mode TODO
@ -975,13 +937,19 @@ 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);
#else
destroySplashScreen();
#endif // NL_OS_WINDOW
// Set the title
@ -1003,7 +971,7 @@ void prelogInit()
filenames.push_back(CPath::lookup("ryzom.png"));
vector<CBitmap> bitmaps;
for(size_t i = 0; i < filenames.size(); ++i)
{
CIFile file;
@ -1113,7 +1081,7 @@ void prelogInit()
// resetTextContext ("bremenb.ttf", false);
resetTextContext ("ryzom.ttf", false);
CInterfaceManager::getInstance();
// Yoyo: initialize NOW the InputHandler for Event filtering.
@ -1162,7 +1130,7 @@ void prelogInit()
// init bloom effect
CBloomEffect::getInstance().init(driver != UDriver::Direct3d);
if (StereoDisplay) // VR_CONFIG
{
// Init stereo display resources

@ -301,7 +301,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;

@ -469,7 +469,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;

File diff suppressed because it is too large Load Diff

@ -52,7 +52,7 @@ struct TChangeTrackerHeader
#ifdef USE_FAST_MUTEX
/// Fast mutex (TODO: use multi-processor version)
volatile NLMISC::CFastMutex FastMutex;
NLMISC::CFastMutex FastMutex;
#endif
/*
* 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
/// Return the mutex
volatile NLMISC::CFastMutex& trackerMutex() { return _Header->FastMutex; }
NLMISC::CFastMutex& trackerMutex() { return _Header->FastMutex; }
#else
/// Return the mutex
NLMISC::CSharedMutex& trackerMutex() { return _TrackerMutex; }

@ -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;

@ -259,7 +259,7 @@ public:
};
CSendRunnable SendTask;
IThread* SendThread = NULL;
CThread* SendThread = NULL;
/*
* Receive task
@ -1325,7 +1325,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
}

@ -217,7 +217,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;

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

@ -144,7 +144,7 @@ private:
private:
// data for the singleton instance
CStdinMonitorThread* _StdinMonitorThreadInstance;
NLMISC::IThread* _StdinMonitorThreadHandle;
NLMISC::CThread* _StdinMonitorThreadHandle;
};
CStdinMonitorSingleton StdinMonitorSingleton;
@ -165,7 +165,7 @@ static CStdinMonitorSingleton& getInstance()
void CStdinMonitorSingleton::init()
{
_StdinMonitorThreadInstance= new CStdinMonitorThread;
_StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance);
_StdinMonitorThreadHandle = NLMISC::CThread::create (_StdinMonitorThreadInstance);
_StdinMonitorThreadHandle->start();
}

@ -340,7 +340,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;
};

@ -159,7 +159,7 @@ int CPatchManager::getTotalFilesToGet()
{
if (ScanDataThread != NULL)
return ScanDataThread->TotalFileToScan;
return 1;
}
@ -168,7 +168,7 @@ int CPatchManager::getCurrentFilesToGet()
{
if (ScanDataThread != NULL)
return ScanDataThread->CurrentFileScanned;
return 1;
}
@ -226,7 +226,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
ftpOut.FileName = rFilename;
ftpOut.LocalFileToDelete = false;
ftpOut.LocalFileExists = false;
// It happens some time (maybe a bug) that the versionCount is 0... =>
// It happens some time (maybe a bug) that the versionCount is 0... =>
// it happens if the BNP file is empty (8 bytes)
ftpOut.FinalFileSize = EmptyBnpFileSize;
// BNP does not exists : get all the patches version
@ -261,7 +261,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
}
}
}
// If the version cannot be found with size and time try with sha1
if (nVersionFound == 0xFFFFFFFF)
{
@ -280,7 +280,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
}
}
}
// No version available found
if (nVersionFound == 0xFFFFFFFF)
{
@ -290,7 +290,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
ftpOut.FileName = rFilename;
ftpOut.LocalFileToDelete = true;
ftpOut.LocalFileExists = true;
// It happens some time (maybe a bug) that the versionCount is 0... =>
// It happens some time (maybe a bug) that the versionCount is 0... =>
// it happens if the BNP file is empty (8 bytes)
ftpOut.FinalFileSize = EmptyBnpFileSize;
// Get all the patches version
@ -314,7 +314,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
for (j = 0; j < rFile.versionCount(); ++j)
if (rFile.getVersion(j).getVersionNumber() == nVersionFound)
break;
nlassert(j != rFile.versionCount()); // Not normal if we cant find the version we found previously
// Point on the next version
@ -335,7 +335,7 @@ void CPatchManager::getPatchFromDesc(SFileToPatch &ftpOut, const CBNPFile &fIn,
// For info, get its final file size
ftpOut.FinalFileSize= rFile.getVersion(rFile.versionCount()-1).getFileSize();
}
} // end of else local BNP file exists
} // end of else local BNP file exists
}
@ -352,7 +352,7 @@ void CPatchManager::startScanDataThread()
nlwarning ("a thread is already running");
return;
}
// Reset result
clearDataScanLog();
@ -362,8 +362,8 @@ void CPatchManager::startScanDataThread()
// start thread
ScanDataThread = new CScanDataThread();
nlassert (ScanDataThread != NULL);
thread = IThread::create (ScanDataThread);
thread = CThread::create (ScanDataThread);
nlassert (thread != NULL);
thread->start ();
}
@ -376,14 +376,14 @@ bool CPatchManager::isScanDataThreadEnded(bool &ok)
ok = false;
return true;
}
bool end = ScanDataThread->Ended;
if (end)
{
ok = ScanDataThread->CheckOk;
stopScanDataThread();
}
return end;
}
@ -430,7 +430,7 @@ bool CPatchManager::getDataScanLog(ucstring &text)
}
// then reset
val.Changed= false;
}
}
return changed;
}
@ -443,7 +443,7 @@ void CPatchManager::addDataScanLogCorruptedFile(const SFileToPatch &ftp)
CDataScanState &val= ac.value();
val.FilesWithScanDataError.push_back(ftp);
val.Changed= true;
}
}
}
// ***************************************************************************
@ -454,7 +454,7 @@ void CPatchManager::clearDataScanLog()
CDataScanState &val= ac.value();
val.FilesWithScanDataError.clear();
val.Changed= true;
}
}
}
// ***************************************************************************
@ -494,8 +494,8 @@ void CScanDataThread::run ()
string sClientVersion = pPM->getClientVersion();
ucstring sTranslate = dummyI18N("Client Version") + " (" + sClientVersion + ") ";
pPM->setState(true, sTranslate);
// For all bnp in the description file get all patches to apply
// For all bnp in the description file get all patches to apply
// depending on the version of the client bnp files
const CBNPFileSet &rDescFiles = pPM->DescFile.getFiles();
TotalFileToScan = rDescFiles.fileCount();

@ -61,7 +61,7 @@ public:
_Instance = new CPatchManager();
return _Instance;
}
// init
void init();
@ -69,31 +69,31 @@ public:
std::string getClientVersion ();
bool isVerboseLog() { return VerboseLog; }
void setVerboseLog(bool b) { VerboseLog = b; }
// Get the string information about what the threads are doing
// Get the string information about what the threads are doing
// Return true if the state has changed
bool getThreadState (ucstring &state, std::vector<ucstring> &stateLog);
// TODO : Revoir ca pour la seconde partie ...
// On a peut etre pas les informations de taille des patches ... voir avec daniel
// pour l'instant c'est un fake qui retourne 1 !
int getTotalFilesToGet();
int getCurrentFilesToGet();
// ----------------------------------------------
// ScanData Part : optional task wich verify all data
// ----------------------------------------------
// start the full check of BNP
void startScanDataThread();
// if the scan data thread has ended
bool isScanDataThreadEnded(bool &ok);
// ask to stop the Scan Data thread. NB: for security, the thread will continue to the current scanned file,
// ask to stop the Scan Data thread. NB: for security, the thread will continue to the current scanned file,
// then stop. Hence, you must still wait isScanDataThreadEnded() return true
void askForStopScanDataThread();
@ -109,7 +109,7 @@ private:
// Set the thread state (called by threads to let us know what they are doing)
void setState (bool bOutputToLog, const ucstring &ucsState);
/// Read the description file (throw exception if it doesn't exists)
void readDescFile(sint32 nVersion);
@ -126,7 +126,7 @@ private:
void addDataScanLogCorruptedFile(const SFileToPatch &ftp);
void clearDataScanLog();
static void getCorruptedFileInfo(const SFileToPatch &ftp, ucstring &sTranslate);
private:
/// Constructor
@ -143,7 +143,7 @@ private:
// Threads
CScanDataThread *ScanDataThread;
NLMISC::IThread *thread;
NLMISC::CThread *thread;
// State
struct CState
@ -197,7 +197,7 @@ public:
public:
// Written by MainThread, read by thread
bool AskForCancel; // true if the main thread ask to cancel the task
bool AskForCancel; // true if the main thread ask to cancel the task
// Written by thread, read by Main Thread
bool Ended; // true if the thread have ended

@ -0,0 +1,3 @@
ADD_SUBDIRECTORY(bin2c)

@ -0,0 +1,10 @@
FILE(GLOB SRC *.cpp *.h)
ADD_EXECUTABLE(bin2c ${SRC})
TARGET_LINK_LIBRARIES(bin2c)
NL_DEFAULT_PROPS(bin2c "NeL, Tools: bin2c")
NL_ADD_RUNTIME_FLAGS(bin2c)
INSTALL(TARGETS bin2c RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT toolsmisc)

@ -21,6 +21,8 @@
#include <stdlib.h>
#include <string.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
int main(int argc, char* argv[])
{
if (argc<2)
@ -29,23 +31,36 @@ int main(int argc, char* argv[])
}
else
{
char sDir[256];
char sPath[256];
char sName[256];
char sExt[256];
_splitpath (argv[1], sDir, sPath, sName, sExt);
char sOutput[256];
if (argc>2)
strcpy (sOutput, argv[2]);
char *cExt = strrchr(argv[1], '.');
char *cName = max(strrchr(argv[1], '/'), strrchr(argv[1], '\\')) + 1;
char sName[256];
strcpy(sName, cName);
if (cExt > cName)
{
sName[cExt - cName] = '\x00';
}
if (argc > 2)
{
strcpy(sOutput, argv[2]);
}
else
{
_makepath (sOutput, sDir, sPath, sName, ".cpp");
strcpy(sOutput, argv[1]);
if (cExt <= cName)
{
cExt = sOutput + strlen(sOutput);
cExt[0] = '.';
}
cExt[1] = 'c';
cExt[2] = '\x00';
}
FILE *pIn=fopen( argv[1], "rb");
if (pIn==NULL)
{
printf ("Can't open %s.", argv[1]);
}
else
{
FILE *pOut=fopen( sOutput, "w");
@ -53,7 +68,7 @@ int main(int argc, char* argv[])
printf ("Can't open %s.", sOutput);
else
{
fprintf (pOut,
fprintf (pOut,
"/**\n"
" * Generated by bin2c.exe\n"
" * binfile: %s\n"
@ -61,7 +76,7 @@ int main(int argc, char* argv[])
"\n"
"extern const unsigned char %s[];\n"
"extern const unsigned int %sSize;\n\n"
"static const unsigned char %s[] =\n"
"const unsigned char %s[] =\n"
"{\n", argv[1], sName, sName, sName);
unsigned int size=0;
@ -82,14 +97,14 @@ int main(int argc, char* argv[])
break;
}
fprintf (pOut, "};\n\n");
fprintf (pOut, "static const unsigned int %sSize = %d;\n\n", sName, size);
fprintf (pOut, "const unsigned int %sSize = %d;\n\n", sName, size);
fclose (pOut);
fclose (pIn);
}
}
}
return 0;
}

Loading…
Cancel
Save