Browse Source

sys: get rid of pthreads.

Since C++11 threads are available on every platform that has threads, we
no longer need our pthread implementation. The LOL_FEATURE_CXX11_THREADS
macro is gone, too, and we now just use LOL_FEATURE_THREADS.

Note that it is still necessary to link with -lpthread or -pthread on
some platforms, so we don’t throw that part away.
undefined
Sam Hocevar 9 years ago
parent
commit
144cb0df31
7 changed files with 41 additions and 212 deletions
  1. +1
    -1
      build/lol-build
  2. +0
    -1
      build/msbuild/lol.vars.props
  3. +1
    -1
      configure.ac
  4. +0
    -4
      src/lol/base/features.h
  5. +0
    -1
      src/platform/nacl/opengl_context.cpp
  6. +0
    -1
      src/platform/nacl/opengl_context.h
  7. +39
    -203
      src/sys/threadbase.h

+ 1
- 1
build/lol-build View File

@@ -236,7 +236,7 @@ configure()
# ant clean # ant clean
;; ;;
raspi-arm) raspi-arm)
do_configure --host=arm-bcm2708hardfp-linux-gnueabi CPPFLAGS="-I$RASPI_SDK_ROOT/firmware/opt/vc/include -I$RASPI_SDK_ROOT/firmware/opt/vc/include/interface/vcos/pthreads -I$RASPI_SDK_ROOT/firmware/opt/vc/include/interface/vmcs_host/linux -I$RASPI_SDK_ROOT/chroot/usr/include -I$RASPI_SDK_ROOT/chroot/usr/include/arm-linux-gnueabihf" LDFLAGS="-L$RASPI_SDK_ROOT/firmware/opt/vc/lib -L$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -L$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,--unresolved-symbols=ignore-in-shared-libs"
do_configure --host=arm-bcm2708hardfp-linux-gnueabi CPPFLAGS="-I$RASPI_SDK_ROOT/firmware/opt/vc/include -I$RASPI_SDK_ROOT/firmware/opt/vc/include/interface/vmcs_host/linux -I$RASPI_SDK_ROOT/chroot/usr/include -I$RASPI_SDK_ROOT/chroot/usr/include/arm-linux-gnueabihf" LDFLAGS="-L$RASPI_SDK_ROOT/firmware/opt/vc/lib -L$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/lib/arm-linux-gnueabihf -L$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,-rpath-link -Wl,$RASPI_SDK_ROOT/chroot/usr/lib/arm-linux-gnueabihf -Wl,--unresolved-symbols=ignore-in-shared-libs"
;; ;;
nacl-i386) nacl-i386)
do_configure CXX=i686-nacl-g++ CC=i686-nacl-gcc ac_cv_exeext=.32.nexe --host=i386 CPPFLAGS="-I$NACL_SDK_ROOT/include" LOL_LIBS="-lppapi -lppapi_gles2 -lppapi_cpp -u _ZN2pp12CreateModuleEv" do_configure CXX=i686-nacl-g++ CC=i686-nacl-gcc ac_cv_exeext=.32.nexe --host=i386 CPPFLAGS="-I$NACL_SDK_ROOT/include" LOL_LIBS="-lppapi -lppapi_gles2 -lppapi_cpp -u _ZN2pp12CreateModuleEv"


+ 0
- 1
build/msbuild/lol.vars.props View File

@@ -98,7 +98,6 @@


<!-- PS4-specific --> <!-- PS4-specific -->
<OrbisDefines>HAVE_STDIO_H; <OrbisDefines>HAVE_STDIO_H;
HAVE_PTHREAD_H;
$(OrbisDefines)</OrbisDefines> $(OrbisDefines)</OrbisDefines>


<!-- X360-specific --> <!-- X360-specific -->


+ 1
- 1
configure.ac View File

@@ -99,7 +99,7 @@ AC_ARG_ENABLE(doc,


dnl Common C headers dnl Common C headers
AC_CHECK_HEADERS(stdio.h stdarg.h inttypes.h endian.h stdint.h getopt.h math.h) AC_CHECK_HEADERS(stdio.h stdarg.h inttypes.h endian.h stdint.h getopt.h math.h)
AC_CHECK_HEADERS(fastmath.h pthread.h libutil.h util.h pty.h glob.h unistd.h io.h)
AC_CHECK_HEADERS(fastmath.h libutil.h util.h pty.h glob.h unistd.h io.h)
AC_CHECK_HEADERS(execinfo.h) AC_CHECK_HEADERS(execinfo.h)
AC_CHECK_HEADERS(sys/ioctl.h sys/ptrace.h sys/stat.h sys/syscall.h sys/user.h) AC_CHECK_HEADERS(sys/ioctl.h sys/ptrace.h sys/stat.h sys/syscall.h sys/user.h)
AC_CHECK_HEADERS(sys/wait.h sys/time.h sys/types.h) AC_CHECK_HEADERS(sys/wait.h sys/time.h sys/types.h)


+ 0
- 4
src/lol/base/features.h View File

@@ -28,7 +28,6 @@


#if defined EMSCRIPTEN #if defined EMSCRIPTEN
# undef LOL_FEATURE_THREADS # undef LOL_FEATURE_THREADS
# define LOL_FEATURE_THREADS 0
#endif #endif


/* Use this to disable code that causes compiler crashes. */ /* Use this to disable code that causes compiler crashes. */
@@ -51,9 +50,6 @@
#undef LOL_FEATURE_CXX11_NULLPTR #undef LOL_FEATURE_CXX11_NULLPTR
#undef LOL_FEATURE_CXX11_TEMPLATE_ALIASES #undef LOL_FEATURE_CXX11_TEMPLATE_ALIASES
#undef LOL_FEATURE_CXX11_SFINAE_FOR_CTORS #undef LOL_FEATURE_CXX11_SFINAE_FOR_CTORS
#undef LOL_FEATURE_CXX11_THREADS /* Touky: Is it really needed ? */

#define LOL_FEATURE_CXX11_THREADS 1 /* Touky: This should be available everywhere */


/* Features supported by GCC */ /* Features supported by GCC */
#if defined __GNUC__ #if defined __GNUC__


+ 0
- 1
src/platform/nacl/opengl_context.cpp View File

@@ -4,7 +4,6 @@


#include <lol/engine-internal.h> #include <lol/engine-internal.h>


#include <pthread.h>
#include <ppapi/cpp/completion_callback.h> #include <ppapi/cpp/completion_callback.h>
#include <ppapi/gles2/gl2ext_ppapi.h> #include <ppapi/gles2/gl2ext_ppapi.h>




+ 0
- 1
src/platform/nacl/opengl_context.h View File

@@ -11,7 +11,6 @@
/// ///


#include <assert.h> #include <assert.h>
#include <pthread.h>


#include <algorithm> #include <algorithm>
#include <string> #include <string>


+ 39
- 203
src/sys/threadbase.h View File

@@ -18,16 +18,12 @@
// ----------------------------------- // -----------------------------------
// //


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
# include <thread> # include <thread>
# include <mutex> # include <mutex>
# include <condition_variable> # include <condition_variable>
#elif defined HAVE_PTHREAD_H
# include <pthread.h>
#else #else
# error No threading support yet :(
/* Nothing */
#endif #endif


/* XXX: workaround for a bug in Visual Studio 2012 and 2013! /* XXX: workaround for a bug in Visual Studio 2012 and 2013!
@@ -54,152 +50,74 @@ namespace lol
class mutex_base class mutex_base
{ {
public: public:
//-------------------------------------------------------------------------
mutex_base()
{
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
/* Nothing */
#elif defined HAVE_PTHREAD_H
pthread_mutex_init(&m_mutex, nullptr);
#endif
}

//-------------------------------------------------------------------------
~mutex_base()
{
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
/* Nothing */
#elif defined HAVE_PTHREAD_H
pthread_mutex_destroy(&m_mutex);
#endif
}

//Will block the thread if another has already locked ---------------------
// Will block the thread if another has already locked
void lock() void lock()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
m_mutex.lock(); m_mutex.lock();
#elif defined HAVE_PTHREAD_H
pthread_mutex_lock(&m_mutex);
#endif #endif
} }


// Will not block if another thread has already locked ---------------------
// Will not block if another thread has already locked
bool try_lock() bool try_lock()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
return false;
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
return m_mutex.try_lock(); return m_mutex.try_lock();
#elif defined HAVE_PTHREAD_H
return !pthread_mutex_trylock(&m_mutex);
#else
return false;
#endif #endif
} }


//-------------------------------------------------------------------------
void unlock() void unlock()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
m_mutex.unlock(); m_mutex.unlock();
#elif defined HAVE_PTHREAD_H
pthread_mutex_unlock(&m_mutex);
#endif #endif
} }


//-------------------------------------------------------------------------
private: private:
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
std::mutex m_mutex; std::mutex m_mutex;
#elif defined HAVE_PTHREAD_H
pthread_mutex_t m_mutex;
#endif #endif
}; };


//A FIFO queue for threads ----------------------------------------------------
// A FIFO queue for threads
template<typename T, int N> template<typename T, int N>
class queue_base class queue_base
{ {
public: public:
queue_base() queue_base()
: m_start(0),
m_count(0)
{ {
m_start = m_count = 0;
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
/* Nothing */
#elif defined HAVE_PTHREAD_H
m_poppers = m_pushers = 0;
pthread_mutex_init(&m_mutex, nullptr);
pthread_cond_init(&m_empty_cond, nullptr);
pthread_cond_init(&m_full_cond, nullptr);
#endif
} }


~queue_base() ~queue_base()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
/* Nothing */
#elif defined HAVE_PTHREAD_H
pthread_cond_destroy(&m_empty_cond);
pthread_cond_destroy(&m_full_cond);
pthread_mutex_destroy(&m_mutex);
#endif
} }


//Will block the thread if another has already locked ---------------------
// Will block the thread if another has already locked
void push(T value) void push(T value)
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Wait for the mutex availability or non-fullness */ /* Wait for the mutex availability or non-fullness */
std::unique_lock<std::mutex> uni_lock(m_mutex); std::unique_lock<std::mutex> uni_lock(m_mutex);
m_full_cond.wait(uni_lock, [&]{return m_count < CAPACITY; }); m_full_cond.wait(uni_lock, [&]{return m_count < CAPACITY; });
#elif defined HAVE_PTHREAD_H
pthread_mutex_lock(&m_mutex);
/* If queue is full, wait on the "full" cond var. */
m_pushers++;
while (m_count == CAPACITY)
pthread_cond_wait(&m_full_cond, &m_mutex);
m_pushers--;
#endif #endif


do_push(value); /* Push value */ do_push(value); /* Push value */


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Release lock and notify empty condition var (in that order) */ /* Release lock and notify empty condition var (in that order) */
uni_lock.unlock(); uni_lock.unlock();
m_empty_cond.notify_one(); m_empty_cond.notify_one();
#elif defined HAVE_PTHREAD_H
/* If there were poppers waiting, signal the "empty" cond var. */
if (m_poppers)
pthread_cond_signal(&m_empty_cond);
pthread_mutex_unlock(&m_mutex);
#endif #endif
} }


//Will not block if another has already locked ----------------------------
// Will not block if another has already locked
bool try_push(T value) bool try_push(T value)
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
if (m_count == CAPACITY)
return false;
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Same as Push(), except .... */ /* Same as Push(), except .... */
std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock); std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock);
/* Bail on fail try_lock fail */ /* Bail on fail try_lock fail */
@@ -211,84 +129,48 @@ public:
uni_lock.unlock(); uni_lock.unlock();
return false; return false;
} }
#elif defined HAVE_PTHREAD_H
/* Bail on fail try_lock */
if (pthread_mutex_trylock(&m_mutex))
return false;
/* Bail on max CAPACITY */
#else
if (m_count == CAPACITY) if (m_count == CAPACITY)
{
pthread_mutex_unlock(&m_mutex);
return false; return false;
}
#endif #endif


do_push(value); /* Push value */ do_push(value); /* Push value */


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Release lock and notify empty condition var (in that order) */ /* Release lock and notify empty condition var (in that order) */
uni_lock.unlock(); uni_lock.unlock();
m_empty_cond.notify_one(); m_empty_cond.notify_one();
#elif defined HAVE_PTHREAD_H
/* If there were poppers waiting, signal the "empty" cond var. */
if (m_poppers)
pthread_cond_signal(&m_empty_cond);
pthread_mutex_unlock(&m_mutex);
#endif #endif


return true; return true;
} }


//Will block the thread if another has already locked ---------------------
// Will block the thread if another has already locked
T pop() T pop()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
ASSERT(0, "Pop should only be used with threads. Use try_pop instead.");
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Wait for the mutex availability or non-emptiness */ /* Wait for the mutex availability or non-emptiness */
std::unique_lock<std::mutex> uni_lock(m_mutex); std::unique_lock<std::mutex> uni_lock(m_mutex);
m_empty_cond.wait(uni_lock, [&]{return m_count > 0; }); m_empty_cond.wait(uni_lock, [&]{return m_count > 0; });
#elif defined HAVE_PTHREAD_H
pthread_mutex_lock(&m_mutex);
/* Wait until there is something in the queue. Be careful, we
* could get woken up but another thread may have eaten the
* message in the meantime. */
m_poppers++;
while (m_count == 0)
pthread_cond_wait(&m_empty_cond, &m_mutex);
m_poppers--;
#else
ASSERT(0, "Pop should only be used with threads. Use try_pop instead.");
#endif #endif


T ret = do_pop(); /* Pop value */ T ret = do_pop(); /* Pop value */


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Release lock and notify full condition var (in that order) */ /* Release lock and notify full condition var (in that order) */
uni_lock.unlock(); uni_lock.unlock();
m_full_cond.notify_one(); m_full_cond.notify_one();
#elif defined HAVE_PTHREAD_H
/* If there were pushers waiting, signal the "full" cond var. */
if (m_pushers)
pthread_cond_signal(&m_full_cond);
pthread_mutex_unlock(&m_mutex);
#else
LeaveCriticalSection(&m_mutex);
ReleaseSemaphore(m_empty_sem, 1, nullptr);
#endif #endif


return ret; return ret;
} }


//Will not block if another has already locked ----------------------------
// Will not block if another has already locked
bool try_pop(T &ret) bool try_pop(T &ret)
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
if (m_count == 0)
return false;
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Same as Pop(), except .... */ /* Same as Pop(), except .... */
std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock); std::unique_lock<std::mutex> uni_lock(m_mutex, std::try_to_lock);
/* Bail on fail try_lock fail */ /* Bail on fail try_lock fail */
@@ -300,37 +182,23 @@ public:
uni_lock.unlock(); uni_lock.unlock();
return false; return false;
} }
#elif defined HAVE_PTHREAD_H
pthread_mutex_lock(&m_mutex);
#else
if (m_count == 0) if (m_count == 0)
{
pthread_mutex_unlock(&m_mutex);
return false; return false;
}
#endif #endif


ret = do_pop(); /* Pop value */ ret = do_pop(); /* Pop value */


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
/* Release lock and notify full condition var (in that order) */ /* Release lock and notify full condition var (in that order) */
uni_lock.unlock(); uni_lock.unlock();
m_full_cond.notify_one(); m_full_cond.notify_one();
#elif defined HAVE_PTHREAD_H
/* If there were pushers waiting, signal the "full" cond var. */
if (m_pushers)
pthread_cond_signal(&m_full_cond);
pthread_mutex_unlock(&m_mutex);
#else
LeaveCriticalSection(&m_mutex);
ReleaseSemaphore(m_empty_sem, 1, nullptr);
#endif #endif


return true; return true;
} }


//Inner methods for actual update -----------------------------------------
// Inner methods for actual update
private: private:
void do_push(T &value) void do_push(T &value)
{ {
@@ -340,30 +208,23 @@ private:


T& do_pop() T& do_pop()
{ {
size_t idx = m_start;
ptrdiff_t idx = m_start;
m_start = (m_start + 1) % CAPACITY; m_start = (m_start + 1) % CAPACITY;
m_count--; m_count--;
return m_values[idx]; return m_values[idx];
} }


//-------------------------------------------------------------------------
private: private:
static size_t const CAPACITY = N;
static ptrdiff_t const CAPACITY = N;
T m_values[CAPACITY]; T m_values[CAPACITY];
size_t m_start, m_count;
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
ptrdiff_t m_start, m_count;
#if LOL_FEATURE_THREADS
std::mutex m_mutex; std::mutex m_mutex;
std::condition_variable m_empty_cond, m_full_cond; std::condition_variable m_empty_cond, m_full_cond;
#elif defined HAVE_PTHREAD_H
size_t m_poppers, m_pushers;
pthread_mutex_t m_mutex;
pthread_cond_t m_empty_cond, m_full_cond;
#endif #endif
}; };


//Base class for threads ------------------------------------------------------
// Base class for threads
class thread_base class thread_base
{ {
public: public:
@@ -373,38 +234,24 @@ public:


void Init() void Init()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
m_thread = std::thread(trampoline, this); m_thread = std::thread(trampoline, this);
#elif defined HAVE_PTHREAD_H
/* Set the joinable attribute for systems who don't play nice */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&m_thread, &attr, trampoline, this);
#endif #endif
} }


virtual ~thread_base() virtual ~thread_base()
{ {
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
# if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND # if LOL_VISUAL_STUDIO_BUG_747145_WORKAROUND
m_thread.detach(); m_thread.detach();
# else # else
m_thread.join(); m_thread.join();
# endif # endif
#elif defined HAVE_PTHREAD_H
pthread_join(m_thread, nullptr);
#endif #endif
} }


private: private:
#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
static void trampoline(thread_base *that) static void trampoline(thread_base *that)
{ {
that->m_function(); that->m_function();
@@ -412,23 +259,12 @@ private:
ExitThread(0); ExitThread(0);
# endif # endif
} }
#else
static void *trampoline(void *data)
{
thread_base *that = (thread_base *)data;
that->m_function();
return nullptr;
}
#endif #endif


std::function<void(void)> m_function; std::function<void(void)> m_function;


#if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS
/* Nothing */
#elif LOL_FEATURE_CXX11_THREADS
#if LOL_FEATURE_THREADS
std::thread m_thread; std::thread m_thread;
#elif defined HAVE_PTHREAD_H
pthread_t m_thread;
#endif #endif
}; };




Loading…
Cancel
Save