init - 初始化项目

This commit is contained in:
Lee Nony
2022-05-06 01:58:53 +08:00
commit 90a5cc7cb6
6772 changed files with 2837787 additions and 0 deletions

116
3rdparty/openexr/IlmThread/IlmThread.cpp vendored Normal file
View File

@@ -0,0 +1,116 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Thread -- this file contains two implementations of thread:
// - dummy implementation for platforms that do not support threading
// when OPENEXR_FORCE_CXX03 is on
// - c++11 and newer version
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#include "IlmThread.h"
#include "Iex.h"
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
#ifndef ILMBASE_FORCE_CXX03
//-----------------------------------------------------------------------------
// C++11 and newer implementation
//-----------------------------------------------------------------------------
bool
supportsThreads ()
{
return true;
}
Thread::Thread ()
{
// empty
}
Thread::~Thread ()
{
// hopefully the thread has basically exited and we are just
// cleaning up, because run is a virtual function, so the v-table
// has already been partly destroyed...
if ( _thread.joinable () )
_thread.join ();
}
void
Thread::start ()
{
_thread = std::thread (&Thread::run, this);
}
#else
# if !defined (_WIN32) &&!(_WIN64) && !(HAVE_PTHREAD)
//-----------------------------------------------------------------------------
// OPENEXR_FORCE_CXX03 with no windows / pthread support
//-----------------------------------------------------------------------------
bool
supportsThreads ()
{
return false;
}
Thread::Thread ()
{
throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
Thread::~Thread ()
{
throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
void
Thread::start ()
{
throw IEX_NAMESPACE::NoImplExc ("Threads not supported on this platform.");
}
# endif
#endif
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT

153
3rdparty/openexr/IlmThread/IlmThread.h vendored Normal file
View File

@@ -0,0 +1,153 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILM_THREAD_H
#define INCLUDED_ILM_THREAD_H
//-----------------------------------------------------------------------------
//
// class Thread
//
// Class Thread is a portable interface to a system-dependent thread
// primitive. In order to make a thread actually do something useful,
// you must derive a subclass from class Thread and implement the
// run() function. If the operating system supports threading then
// the run() function will be executed int a new thread.
//
// The actual creation of the thread is done by the start() routine
// which then calls the run() function. In general the start()
// routine should be called from the constructor of the derived class.
//
// The base-class thread destructor will join/destroy the thread.
//
// IMPORTANT: Due to the mechanisms that encapsulate the low-level
// threading primitives in a C++ class there is a race condition
// with code resembling the following:
//
// {
// WorkerThread myThread;
// } // myThread goes out of scope, is destroyed
// // and the thread is joined
//
// The race is between the parent thread joining the child thread
// in the destructor of myThread, and the run() function in the
// child thread. If the destructor gets executed first then run()
// will be called with an invalid "this" pointer.
//
// This issue can be fixed by using a Semaphore to keep track of
// whether the run() function has already been called. You can
// include a Semaphore member variable within your derived class
// which you post() on in the run() function, and wait() on in the
// destructor before the thread is joined. Alternatively you could
// do something like this:
//
// Semaphore runStarted;
//
// void WorkerThread::run ()
// {
// runStarted.post()
// // do some work
// ...
// }
//
// {
// WorkerThread myThread;
// runStarted.wait (); // ensure that we have started
// // the run function
// } // myThread goes out of scope, is destroyed
// // and the thread is joined
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#include "IlmThreadExport.h"
#include "IlmThreadNamespace.h"
#ifdef ILMBASE_FORCE_CXX03
# if defined _WIN32 || defined _WIN64
# ifdef NOMINMAX
# undef NOMINMAX
# endif
# define NOMINMAX
# include <windows.h>
# include <process.h>
# elif HAVE_PTHREAD
# include <pthread.h>
# endif
#else
# include <thread>
#endif
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
//
// Query function to determine if the current platform supports
// threads AND this library was compiled with threading enabled.
//
ILMTHREAD_EXPORT bool supportsThreads ();
class Thread
{
public:
ILMTHREAD_EXPORT Thread ();
ILMTHREAD_EXPORT virtual ~Thread ();
ILMTHREAD_EXPORT void start ();
ILMTHREAD_EXPORT virtual void run () = 0;
private:
#ifdef ILMBASE_FORCE_CXX03
# if defined _WIN32 || defined _WIN64
HANDLE _thread;
# elif HAVE_PTHREAD
pthread_t _thread;
# endif
void operator = (const Thread& t); // not implemented
Thread (const Thread& t); // not implemented
#else
std::thread _thread;
Thread &operator= (const Thread& t) = delete;
Thread (const Thread& t) = delete;
#endif
};
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
#endif // INCLUDED_ILM_THREAD_H

View File

@@ -0,0 +1,46 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#if defined(OPENEXR_DLL)
#if defined(ILMTHREAD_EXPORTS)
#define ILMTHREAD_EXPORT __declspec(dllexport)
#define ILMTHREAD_EXPORT_CONST extern __declspec(dllexport)
#else
#define ILMTHREAD_EXPORT __declspec(dllimport)
#define ILMTHREAD_EXPORT_CONST extern __declspec(dllimport)
#endif
#else
#define ILMTHREAD_EXPORT
#define ILMTHREAD_EXPORT_CONST extern const
#endif

View File

@@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILMTHREADFORWARD_H
#define INCLUDED_ILMTHREADFORWARD_H
#include "IlmThreadNamespace.h"
#ifndef ILMBASE_FORCE_CXX03
namespace std { class mutex; }
#endif
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
class Thread;
#ifdef ILMBASE_FORCE_CXX03
class Mutex;
#else
using Mutex = std::mutex;
#endif
class Lock;
class ThreadPool;
class Task;
class TaskGroup;
class Semaphore;
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
#endif // INCLUDED_ILMTHREADFORWARD_H

View File

@@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Mutex, class Lock -- dummy implementation
// for platforms that do not support threading
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#ifdef ILMBASE_FORCE_CXX03
# if !defined (_WIN32) && !(_WIN64) && !(HAVE_PTHREAD)
# include "IlmThreadMutex.h"
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex () {}
Mutex::~Mutex () {}
void Mutex::lock () const {}
void Mutex::unlock () const {}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
# endif
#endif

View File

@@ -0,0 +1,180 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILM_THREAD_MUTEX_H
#define INCLUDED_ILM_THREAD_MUTEX_H
//-----------------------------------------------------------------------------
//
// class Mutex, class Lock
//
// Class Mutex is a wrapper for a system-dependent mutual exclusion
// mechanism. Actual locking and unlocking of a Mutex object must
// be performed using an instance of a Lock (defined below).
//
// Class lock provides safe locking and unlocking of mutexes even in
// the presence of C++ exceptions. Constructing a Lock object locks
// the mutex; destroying the Lock unlocks the mutex.
//
// Lock objects are not themselves thread-safe. You should never
// share a Lock object among multiple threads.
//
// Typical usage:
//
// Mutex mtx; // Create a Mutex object that is visible
// //to multiple threads
//
// ... // create some threads
//
// // Then, within each thread, construct a critical section like so:
//
// {
// Lock lock (mtx); // Lock constructor locks the mutex
// ... // do some computation on shared data
// } // leaving the block unlocks the mutex
//
//-----------------------------------------------------------------------------
#include "IlmThreadExport.h"
#include "IlmBaseConfig.h"
#include "IlmThreadNamespace.h"
#ifdef ILMBASE_FORCE_CXX03
# if defined _WIN32 || defined _WIN64
# ifdef NOMINMAX
# undef NOMINMAX
# endif
# define NOMINMAX
# include <windows.h>
# elif HAVE_PTHREAD
# include <pthread.h>
# endif
#else
# include <mutex>
#endif
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
// in c++11, this can just be
//
// using Mutex = std::mutex;
// unfortunately we can't use std::unique_lock as a replacement for Lock since
// they have different API.
//
// if we decide to break the API, we can just
//
// using Lock = std::lock_guard<std::mutex>;
// or
// using Lock = std::unique_lock<std::mutex>;
//
// (or eliminate the type completely and have people use the std library)
#ifdef ILMBASE_FORCE_CXX03
class Lock;
class ILMTHREAD_EXPORT Mutex
{
public:
Mutex ();
virtual ~Mutex ();
private:
void lock () const;
void unlock () const;
#if defined _WIN32 || defined _WIN64
mutable CRITICAL_SECTION _mutex;
#elif HAVE_PTHREAD
mutable pthread_mutex_t _mutex;
#endif
void operator = (const Mutex& M); // not implemented
Mutex (const Mutex& M); // not implemented
friend class Lock;
};
#else
using Mutex = std::mutex;
#endif
class ILMTHREAD_EXPORT Lock
{
public:
Lock (const Mutex& m, bool autoLock = true):
_mutex (const_cast<Mutex &>(m)), _locked (false)
{
if (autoLock)
{
_mutex.lock();
_locked = true;
}
}
~Lock ()
{
if (_locked)
_mutex.unlock();
}
void acquire ()
{
_mutex.lock();
_locked = true;
}
void release ()
{
_mutex.unlock();
_locked = false;
}
bool locked ()
{
return _locked;
}
private:
Mutex & _mutex;
bool _locked;
};
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
#endif // INCLUDED_ILM_THREAD_MUTEX_H

View File

@@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Mutex -- implementation for
// platforms that support Posix threads
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#ifdef ILMBASE_FORCE_CXX03
# if HAVE_PTHREAD
# include "IlmThreadMutex.h"
# include "Iex.h"
# include <assert.h>
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex ()
{
if (int error = ::pthread_mutex_init (&_mutex, 0))
IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot initialize mutex (%T).", error);
}
Mutex::~Mutex ()
{
int error = ::pthread_mutex_destroy (&_mutex);
assert (error == 0);
}
void
Mutex::lock () const
{
if (int error = ::pthread_mutex_lock (&_mutex))
IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot lock mutex (%T).", error);
}
void
Mutex::unlock () const
{
if (int error = ::pthread_mutex_unlock (&_mutex))
IEX_INTERNAL_NAMESPACE::throwErrnoExc ("Cannot unlock mutex (%T).", error);
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
# endif
#endif

View File

@@ -0,0 +1,78 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Mutex -- implementation for Windows
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#ifdef ILMBASE_FORCE_CXX03
# include "IlmThreadMutex.h"
# include "Iex.h"
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Mutex::Mutex ()
{
::InitializeCriticalSection (&_mutex);
}
Mutex::~Mutex ()
{
::DeleteCriticalSection (&_mutex);
}
void
Mutex::lock () const
{
::EnterCriticalSection (&_mutex);
}
void
Mutex::unlock () const
{
::LeaveCriticalSection (&_mutex);
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif

View File

@@ -0,0 +1,114 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILMTHREADNAMESPACE_H
#define INCLUDED_ILMTHREADNAMESPACE_H
//
// The purpose of this file is to make it possible to specify an
// ILMTHREAD_INTERNAL_NAMESPACE as a preprocessor definition and have all of
// the IlmThread symbols defined within that namespace rather than the
// standard IlmThread namespace. Those symbols are made available to client
// code through the ILMTHREAD_NAMESPACE in addition to the
// ILMTHREAD_INTERNAL_NAMESPACE.
//
// To ensure source code compatibility, the ILMTHREAD_NAMESPACE defaults to
// IlmThread and then "using namespace ILMTHREAD_INTERNAL_NAMESPACE;" brings
// all of the declarations from the ILMTHREAD_INTERNAL_NAMESPACE into the
// ILMTHREAD_NAMESPACE. This means that client code can continue to use
// syntax like IlmThread::Thread, but at link time it will resolve to a
// mangled symbol based on the ILMTHREAD_INTERNAL_NAMESPACE.
//
// As an example, if one needed to build against a newer version of IlmThread
// and have it run alongside an older version in the same application, it is
// now possible to use an internal namespace to prevent collisions between
// the older versions of IlmThread symbols and the newer ones. To do this,
// the following could be defined at build time:
//
// ILMTHREAD_INTERNAL_NAMESPACE = IlmThread_v2
//
// This means that declarations inside IlmThread headers look like this
// (after the preprocessor has done its work):
//
// namespace IlmThread_v2 {
// ...
// class declarations
// ...
// }
//
// namespace IlmThread {
// using namespace IlmThread_v2;
// }
//
//
// Open Source version of this file pulls in the IlmBaseConfig.h file
// for the configure time options.
//
#include "IlmBaseConfig.h"
#ifndef ILMTHREAD_NAMESPACE
#define ILMTHREAD_NAMESPACE IlmThread
#endif
#ifndef ILMTHREAD_INTERNAL_NAMESPACE
#define ILMTHREAD_INTERNAL_NAMESPACE ILMTHREAD_NAMESPACE
#endif
//
// We need to be sure that we import the internal namespace into the public one.
// To do this, we use the small bit of code below which initially defines
// ILMTHREAD_INTERNAL_NAMESPACE (so it can be referenced) and then defines
// ILMTHREAD_NAMESPACE and pulls the internal symbols into the public
// namespace.
//
namespace ILMTHREAD_INTERNAL_NAMESPACE {}
namespace ILMTHREAD_NAMESPACE {
using namespace ILMTHREAD_INTERNAL_NAMESPACE;
}
//
// There are identical pairs of HEADER/SOURCE ENTER/EXIT macros so that
// future extension to the namespace mechanism is possible without changing
// project source code.
//
#define ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER namespace ILMTHREAD_INTERNAL_NAMESPACE {
#define ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT }
#define ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER namespace ILMTHREAD_INTERNAL_NAMESPACE {
#define ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT }
#endif // INCLUDED_ILMTHREADNAMESPACE_H

View File

@@ -0,0 +1,851 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Task, class ThreadPool, class TaskGroup
//
//-----------------------------------------------------------------------------
#include "IlmThread.h"
#include "IlmThreadMutex.h"
#include "IlmThreadSemaphore.h"
#include "IlmThreadPool.h"
#include "Iex.h"
#include <vector>
#ifndef ILMBASE_FORCE_CXX03
# include <memory>
# include <atomic>
# include <thread>
#endif
using namespace std;
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
#if defined(__GNU_LIBRARY__) && ( __GLIBC__ < 2 || ( __GLIBC__ == 2 && __GLIBC_MINOR__ < 21 ) )
# define ENABLE_SEM_DTOR_WORKAROUND
#endif
struct TaskGroup::Data
{
Data ();
~Data ();
void addTask () ;
void removeTask ();
#ifndef ILMBASE_FORCE_CXX03
std::atomic<int> numPending;
#else
int numPending; // number of pending tasks to still execute
#endif
Semaphore isEmpty; // used to signal that the taskgroup is empty
#if defined(ENABLE_SEM_DTOR_WORKAROUND) || defined(ILMBASE_FORCE_CXX03)
// this mutex is also used to lock numPending in the legacy c++ mode...
Mutex dtorMutex; // used to work around the glibc bug:
// http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
#endif
};
struct ThreadPool::Data
{
typedef ThreadPoolProvider *TPPointer;
Data ();
~Data();
struct SafeProvider
{
SafeProvider (Data *d, ThreadPoolProvider *p) : _data( d ), _ptr( p )
{
}
~SafeProvider()
{
if ( _data )
_data->coalesceProviderUse();
}
SafeProvider (const SafeProvider &o)
: _data( o._data ), _ptr( o._ptr )
{
if ( _data )
_data->bumpProviderUse();
}
SafeProvider &operator= (const SafeProvider &o)
{
if ( this != &o )
{
if ( o._data )
o._data->bumpProviderUse();
if ( _data )
_data->coalesceProviderUse();
_data = o._data;
_ptr = o._ptr;
}
return *this;
}
#ifndef ILMBASE_FORCE_CXX03
SafeProvider( SafeProvider &&o )
: _data( o._data ), _ptr( o._ptr )
{
o._data = nullptr;
}
SafeProvider &operator=( SafeProvider &&o )
{
std::swap( _data, o._data );
std::swap( _ptr, o._ptr );
return *this;
}
#endif
inline ThreadPoolProvider *get () const
{
return _ptr;
}
ThreadPoolProvider *operator-> () const
{
return get();
}
Data *_data;
ThreadPoolProvider *_ptr;
};
// NB: In C++20, there is full support for atomic shared_ptr, but that is not
// yet in use or finalized. Once stabilized, add appropriate usage here
inline SafeProvider getProvider ();
inline void coalesceProviderUse ();
inline void bumpProviderUse ();
inline void setProvider (ThreadPoolProvider *p);
#ifdef ILMBASE_FORCE_CXX03
Semaphore provSem;
Mutex provMutex;
int provUsers;
ThreadPoolProvider *provider;
ThreadPoolProvider *oldprovider;
#else
std::atomic<ThreadPoolProvider *> provider;
std::atomic<int> provUsers;
#endif
};
namespace {
class DefaultWorkerThread;
struct DefaultWorkData
{
Semaphore taskSemaphore; // threads wait on this for ready tasks
mutable Mutex taskMutex; // mutual exclusion for the tasks list
vector<Task*> tasks; // the list of tasks to execute
Semaphore threadSemaphore; // signaled when a thread starts executing
mutable Mutex threadMutex; // mutual exclusion for threads list
vector<DefaultWorkerThread*> threads; // the list of all threads
#ifdef ILMBASE_FORCE_CXX03
bool stopping; // flag indicating whether to stop threads
mutable Mutex stopMutex; // mutual exclusion for stopping flag
#else
std::atomic<bool> hasThreads;
std::atomic<bool> stopping;
#endif
inline bool stopped () const
{
#ifdef ILMBASE_FORCE_CXX03
Lock lock (stopMutex);
return stopping;
#else
return stopping.load( std::memory_order_relaxed );
#endif
}
inline void stop ()
{
#ifdef ILMBASE_FORCE_CXX03
Lock lock (stopMutex);
#endif
stopping = true;
}
};
//
// class WorkerThread
//
class DefaultWorkerThread: public Thread
{
public:
DefaultWorkerThread (DefaultWorkData* data);
virtual void run ();
private:
DefaultWorkData * _data;
};
DefaultWorkerThread::DefaultWorkerThread (DefaultWorkData* data):
_data (data)
{
start();
}
void
DefaultWorkerThread::run ()
{
//
// Signal that the thread has started executing
//
_data->threadSemaphore.post();
while (true)
{
//
// Wait for a task to become available
//
_data->taskSemaphore.wait();
{
Lock taskLock (_data->taskMutex);
//
// If there is a task pending, pop off the next task in the FIFO
//
if (!_data->tasks.empty())
{
Task* task = _data->tasks.back();
_data->tasks.pop_back();
taskLock.release();
TaskGroup* taskGroup = task->group();
task->execute();
delete task;
taskGroup->_data->removeTask ();
}
else if (_data->stopped())
{
break;
}
}
}
}
//
// class DefaultThreadPoolProvider
//
class DefaultThreadPoolProvider : public ThreadPoolProvider
{
public:
DefaultThreadPoolProvider(int count);
virtual ~DefaultThreadPoolProvider();
virtual int numThreads() const;
virtual void setNumThreads(int count);
virtual void addTask(Task *task);
virtual void finish();
private:
DefaultWorkData _data;
};
DefaultThreadPoolProvider::DefaultThreadPoolProvider (int count)
{
setNumThreads(count);
}
DefaultThreadPoolProvider::~DefaultThreadPoolProvider ()
{
finish();
}
int
DefaultThreadPoolProvider::numThreads () const
{
Lock lock (_data.threadMutex);
return static_cast<int> (_data.threads.size());
}
void
DefaultThreadPoolProvider::setNumThreads (int count)
{
//
// Lock access to thread list and size
//
Lock lock (_data.threadMutex);
size_t desired = static_cast<size_t>(count);
if (desired > _data.threads.size())
{
//
// Add more threads
//
while (_data.threads.size() < desired)
_data.threads.push_back (new DefaultWorkerThread (&_data));
}
else if ((size_t)count < _data.threads.size())
{
//
// Wait until all existing threads are finished processing,
// then delete all threads.
//
finish ();
//
// Add in new threads
//
while (_data.threads.size() < desired)
_data.threads.push_back (new DefaultWorkerThread (&_data));
}
#ifndef ILMBASE_FORCE_CXX03
_data.hasThreads = !(_data.threads.empty());
#endif
}
void
DefaultThreadPoolProvider::addTask (Task *task)
{
//
// Lock the threads, needed to access numThreads
//
#ifdef ILMBASE_FORCE_CXX03
bool doPush;
{
Lock lock (_data.threadMutex);
doPush = !_data.threads.empty();
}
#else
bool doPush = _data.hasThreads.load( std::memory_order_relaxed );
#endif
if ( doPush )
{
//
// Get exclusive access to the tasks queue
//
{
Lock taskLock (_data.taskMutex);
//
// Push the new task into the FIFO
//
_data.tasks.push_back (task);
}
//
// Signal that we have a new task to process
//
_data.taskSemaphore.post ();
}
else
{
// this path shouldn't normally happen since we have the
// NullThreadPoolProvider, but just in case...
task->execute ();
task->group()->_data->removeTask ();
delete task;
}
}
void
DefaultThreadPoolProvider::finish ()
{
_data.stop();
//
// Signal enough times to allow all threads to stop.
//
// Wait until all threads have started their run functions.
// If we do not wait before we destroy the threads then it's
// possible that the threads have not yet called their run
// functions.
// If this happens then the run function will be called off
// of an invalid object and we will crash, most likely with
// an error like: "pure virtual method called"
//
size_t curT = _data.threads.size();
for (size_t i = 0; i != curT; ++i)
{
_data.taskSemaphore.post();
_data.threadSemaphore.wait();
}
//
// Join all the threads
//
for (size_t i = 0; i != curT; ++i)
delete _data.threads[i];
Lock lock1 (_data.taskMutex);
#ifdef ILMBASE_FORCE_CXX03
Lock lock2 (_data.stopMutex);
#endif
_data.threads.clear();
_data.tasks.clear();
_data.stopping = false;
}
class NullThreadPoolProvider : public ThreadPoolProvider
{
virtual ~NullThreadPoolProvider() {}
virtual int numThreads () const { return 0; }
virtual void setNumThreads (int count)
{
}
virtual void addTask (Task *t)
{
t->execute ();
t->group()->_data->removeTask ();
delete t;
}
virtual void finish () {}
};
} //namespace
//
// struct TaskGroup::Data
//
TaskGroup::Data::Data (): isEmpty (1), numPending (0)
{
// empty
}
TaskGroup::Data::~Data ()
{
//
// A TaskGroup acts like an "inverted" semaphore: if the count
// is above 0 then waiting on the taskgroup will block. This
// destructor waits until the taskgroup is empty before returning.
//
isEmpty.wait ();
#ifdef ENABLE_SEM_DTOR_WORKAROUND
// Update: this was fixed in v. 2.2.21, so this ifdef checks for that
//
// Alas, given the current bug in glibc we need a secondary
// syncronisation primitive here to account for the fact that
// destructing the isEmpty Semaphore in this thread can cause
// an error for a separate thread that is issuing the post() call.
// We are entitled to destruct the semaphore at this point, however,
// that post() call attempts to access data out of the associated
// memory *after* it has woken the waiting threads, including this one,
// potentially leading to invalid memory reads.
// http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
Lock lock (dtorMutex);
#endif
}
void
TaskGroup::Data::addTask ()
{
//
// in c++11, we use an atomic to protect numPending to avoid the
// extra lock but for c++98, to add the ability for custom thread
// pool we add the lock here
//
#if ILMBASE_FORCE_CXX03
Lock lock (dtorMutex);
#endif
if (numPending++ == 0)
isEmpty.wait ();
}
void
TaskGroup::Data::removeTask ()
{
// Alas, given the current bug in glibc we need a secondary
// syncronisation primitive here to account for the fact that
// destructing the isEmpty Semaphore in a separate thread can
// cause an error. Issuing the post call here the current libc
// implementation attempts to access memory *after* it has woken
// waiting threads.
// Since other threads are entitled to delete the semaphore the
// access to the memory location can be invalid.
// http://sources.redhat.com/bugzilla/show_bug.cgi?id=12674
// Update: this bug has been fixed, but how do we know which
// glibc version we're in?
// Further update:
//
// we could remove this if it is a new enough glibc, however
// we've changed the API to enable a custom override of a
// thread pool. In order to provide safe access to the numPending,
// we need the lock anyway, except for c++11 or newer
#ifdef ILMBASE_FORCE_CXX03
Lock lock (dtorMutex);
if (--numPending == 0)
isEmpty.post ();
#else
if (--numPending == 0)
{
#ifdef ENABLE_SEM_DTOR_WORKAROUND
Lock lock (dtorMutex);
#endif
isEmpty.post ();
}
#endif
}
//
// struct ThreadPool::Data
//
ThreadPool::Data::Data ():
provUsers (0), provider (NULL)
#ifdef ILMBASE_FORCE_CXX03
, oldprovider (NULL)
#else
#endif
{
// empty
}
ThreadPool::Data::~Data()
{
#ifdef ILMBASE_FORCE_CXX03
provider->finish();
#else
ThreadPoolProvider *p = provider.load( std::memory_order_relaxed );
p->finish();
#endif
}
inline ThreadPool::Data::SafeProvider
ThreadPool::Data::getProvider ()
{
#ifdef ILMBASE_FORCE_CXX03
Lock provLock( provMutex );
++provUsers;
return SafeProvider( this, provider );
#else
provUsers.fetch_add( 1, std::memory_order_relaxed );
return SafeProvider( this, provider.load( std::memory_order_relaxed ) );
#endif
}
inline void
ThreadPool::Data::coalesceProviderUse ()
{
#ifdef ILMBASE_FORCE_CXX03
Lock provLock( provMutex );
--provUsers;
if ( provUsers == 0 )
{
if ( oldprovider )
provSem.post();
}
#else
int ov = provUsers.fetch_sub( 1, std::memory_order_relaxed );
// ov is the previous value, so one means that now it might be 0
if ( ov == 1 )
{
}
#endif
}
inline void
ThreadPool::Data::bumpProviderUse ()
{
#ifdef ILMBASE_FORCE_CXX03
Lock lock (provMutex);
++provUsers;
#else
provUsers.fetch_add( 1, std::memory_order_relaxed );
#endif
}
inline void
ThreadPool::Data::setProvider (ThreadPoolProvider *p)
{
#ifdef ILMBASE_FORCE_CXX03
Lock provLock( provMutex );
if ( oldprovider )
throw IEX_INTERNAL_NAMESPACE::ArgExc ("Attempt to set the thread pool provider while"
" another thread is currently setting the provider.");
oldprovider = provider;
provider = p;
while ( provUsers > 0 )
{
provLock.release();
provSem.wait();
provLock.acquire();
}
if ( oldprovider )
{
oldprovider->finish();
delete oldprovider;
oldprovider = NULL;
}
#else
ThreadPoolProvider *old = provider.load( std::memory_order_relaxed );
do
{
if ( ! provider.compare_exchange_weak( old, p, std::memory_order_release, std::memory_order_relaxed ) )
continue;
} while ( false );
// wait for any other users to finish prior to deleting, given
// that these are just mostly to query the thread count or push a
// task to the queue (so fast), just spin...
//
// (well, and normally, people don't do this mid stream anyway, so
// this will be 0 99.999% of the time, but just to be safe)
//
while ( provUsers.load( std::memory_order_relaxed ) > 0 )
std::this_thread::yield();
if ( old )
{
old->finish();
delete old;
}
// NB: the shared_ptr mechanism is safer and means we don't have
// to have the provUsers counter since the shared_ptr keeps that
// for us. However, gcc 4.8/9 compilers which many people are
// still using even though it is 2018 forgot to add the shared_ptr
// functions... once that compiler is fully deprecated, switch to
// using the below, change provider to a std::shared_ptr and remove
// provUsers...
//
// std::shared_ptr<ThreadPoolProvider> newp( p );
// std::shared_ptr<ThreadPoolProvider> curp = std::atomic_load_explicit( &provider, std::memory_order_relaxed );
// do
// {
// if ( ! std::atomic_compare_exchange_weak_explicit( &provider, &curp, newp, std::memory_order_release, std::memory_order_relaxed ) )
// continue;
// } while ( false );
// if ( curp )
// curp->finish();
#endif
}
//
// class Task
//
Task::Task (TaskGroup* g): _group(g)
{
if ( g )
g->_data->addTask ();
}
Task::~Task()
{
// empty
}
TaskGroup*
Task::group ()
{
return _group;
}
TaskGroup::TaskGroup ():
_data (new Data())
{
// empty
}
TaskGroup::~TaskGroup ()
{
delete _data;
}
void
TaskGroup::finishOneTask ()
{
_data->removeTask ();
}
//
// class ThreadPoolProvider
//
ThreadPoolProvider::ThreadPoolProvider()
{
}
ThreadPoolProvider::~ThreadPoolProvider()
{
}
//
// class ThreadPool
//
ThreadPool::ThreadPool (unsigned nthreads):
_data (new Data)
{
if ( nthreads == 0 )
_data->setProvider( new NullThreadPoolProvider );
else
_data->setProvider( new DefaultThreadPoolProvider( int(nthreads) ) );
}
ThreadPool::~ThreadPool ()
{
delete _data;
}
int
ThreadPool::numThreads () const
{
return _data->getProvider ()->numThreads ();
}
void
ThreadPool::setNumThreads (int count)
{
if (count < 0)
throw IEX_INTERNAL_NAMESPACE::ArgExc ("Attempt to set the number of threads "
"in a thread pool to a negative value.");
bool doReset = false;
{
Data::SafeProvider sp = _data->getProvider ();
int curT = sp->numThreads ();
if ( curT == count )
return;
if ( curT == 0 )
{
NullThreadPoolProvider *npp = dynamic_cast<NullThreadPoolProvider *>( sp.get() );
if ( npp )
doReset = true;
}
else if ( count == 0 )
{
DefaultThreadPoolProvider *dpp = dynamic_cast<DefaultThreadPoolProvider *>( sp.get() );
if ( dpp )
doReset = true;
}
if ( ! doReset )
sp->setNumThreads( count );
}
if ( doReset )
{
if ( count == 0 )
_data->setProvider( new NullThreadPoolProvider );
else
_data->setProvider( new DefaultThreadPoolProvider( count ) );
}
}
void
ThreadPool::setThreadProvider (ThreadPoolProvider *provider)
{
_data->setProvider (provider);
}
void
ThreadPool::addTask (Task* task)
{
_data->getProvider ()->addTask (task);
}
ThreadPool&
ThreadPool::globalThreadPool ()
{
//
// The global thread pool
//
static ThreadPool gThreadPool (0);
return gThreadPool;
}
void
ThreadPool::addGlobalTask (Task* task)
{
globalThreadPool().addTask (task);
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT

View File

@@ -0,0 +1,214 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILM_THREAD_POOL_H
#define INCLUDED_ILM_THREAD_POOL_H
//-----------------------------------------------------------------------------
//
// class Task, class ThreadPool, class TaskGroup
//
// Class ThreadPool manages a set of worker threads and accepts
// tasks for processing. Tasks added to the thread pool are
// executed concurrently by the worker threads.
//
// Class Task provides an abstract interface for a task which
// a ThreadPool works on. Derived classes need to implement the
// execute() function which performs the actual task.
//
// Class TaskGroup allows synchronization on the completion of a set
// of tasks. Every task that is added to a ThreadPool belongs to a
// single TaskGroup. The destructor of the TaskGroup waits for all
// tasks in the group to finish.
//
// Note: if you plan to use the ThreadPool interface in your own
// applications note that the implementation of the ThreadPool calls
// operator delete on tasks as they complete. If you define a custom
// operator new for your tasks, for instance to use a custom heap,
// then you must also write an appropriate operator delete.
//
//-----------------------------------------------------------------------------
#include "IlmThreadNamespace.h"
#include "IlmThreadExport.h"
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
class TaskGroup;
class Task;
//-------------------------------------------------------
// ThreadPoolProvider -- this is a pure virtual interface
// enabling custom overloading of the threads used and how
// the implementation of the processing of tasks
// is implemented
//-------------------------------------------------------
class ILMTHREAD_EXPORT ThreadPoolProvider
{
public:
ThreadPoolProvider();
virtual ~ThreadPoolProvider();
// as in ThreadPool below
virtual int numThreads () const = 0;
// as in ThreadPool below
virtual void setNumThreads (int count) = 0;
// as in ThreadPool below
virtual void addTask (Task* task) = 0;
// Ensure that all tasks in this set are finished
// and threads shutdown
virtual void finish () = 0;
// Make the provider non-copyable
#if __cplusplus >= 201103L
ThreadPoolProvider (const ThreadPoolProvider &) = delete;
ThreadPoolProvider &operator= (const ThreadPoolProvider &) = delete;
ThreadPoolProvider (ThreadPoolProvider &&) = delete;
ThreadPoolProvider &operator= (ThreadPoolProvider &&) = delete;
#else
private:
ThreadPoolProvider (const ThreadPoolProvider &);
ThreadPoolProvider &operator= (const ThreadPoolProvider &);
#endif
};
class ILMTHREAD_EXPORT ThreadPool
{
public:
//-------------------------------------------------------
// Constructor -- creates numThreads worker threads which
// wait until a task is available,
// using a default ThreadPoolProvider
//-------------------------------------------------------
ThreadPool (unsigned numThreads = 0);
//-----------------------------------------------------------
// Destructor -- waits for all tasks to complete, joins all
// the threads to the calling thread, and then destroys them.
//-----------------------------------------------------------
virtual ~ThreadPool ();
//--------------------------------------------------------
// Query and set the number of worker threads in the pool.
//
// Warning: never call setNumThreads from within a worker
// thread as this will almost certainly cause a deadlock
// or crash.
//--------------------------------------------------------
int numThreads () const;
void setNumThreads (int count);
//--------------------------------------------------------
// Set the thread provider for the pool.
//
// The ThreadPool takes ownership of the ThreadPoolProvider
// and will call delete on it when it is finished or when
// it is changed
//
// Warning: never call setThreadProvider from within a worker
// thread as this will almost certainly cause a deadlock
// or crash.
//--------------------------------------------------------
void setThreadProvider (ThreadPoolProvider *provider);
//------------------------------------------------------------
// Add a task for processing. The ThreadPool can handle any
// number of tasks regardless of the number of worker threads.
// The tasks are first added onto a queue, and are executed
// by threads as they become available, in FIFO order.
//------------------------------------------------------------
void addTask (Task* task);
//-------------------------------------------
// Access functions for the global threadpool
//-------------------------------------------
static ThreadPool& globalThreadPool ();
static void addGlobalTask (Task* task);
struct Data;
protected:
Data * _data;
};
class ILMTHREAD_EXPORT Task
{
public:
Task (TaskGroup* g);
virtual ~Task ();
virtual void execute () = 0;
TaskGroup * group();
protected:
TaskGroup * _group;
};
class ILMTHREAD_EXPORT TaskGroup
{
public:
TaskGroup();
~TaskGroup();
// marks one task as finished
// should be used by the thread pool provider to notify
// as it finishes tasks
void finishOneTask ();
struct Data;
Data* const _data;
};
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
#endif // INCLUDED_ILM_THREAD_POOL_H

View File

@@ -0,0 +1,100 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Thread -- implementation for
// platforms that support Posix threads
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#if HAVE_PTHREAD
#ifdef ILMBASE_FORCE_CXX03
#include "IlmThread.h"
#include "Iex.h"
#include <assert.h>
extern "C"
{
typedef void * (* Start) (void *);
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
supportsThreads ()
{
return true;
}
namespace {
void
threadLoop (void * t)
{
return (reinterpret_cast<Thread*>(t))->run();
}
} // namespace
Thread::Thread ()
{
// empty
}
Thread::~Thread ()
{
int error = ::pthread_join (_thread, 0);
assert (error == 0);
}
void
Thread::start ()
{
if (int error = ::pthread_create (&_thread, 0, Start (threadLoop), this))
IEX_NAMESPACE::throwErrnoExc ("Cannot create new thread (%T).", error);
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif
#endif

View File

@@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Semaphore -- dummy implementation for
// for platforms that do not support threading
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#if !defined (_WIN32) && !(_WIN64) && !(HAVE_PTHREAD)
#include "IlmThreadSemaphore.h"
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Semaphore::Semaphore (unsigned int value) {}
Semaphore::~Semaphore () {}
void Semaphore::wait () {}
bool Semaphore::tryWait () {return true;}
void Semaphore::post () {}
int Semaphore::value () const {return 0;}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif

View File

@@ -0,0 +1,127 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_ILM_THREAD_SEMAPHORE_H
#define INCLUDED_ILM_THREAD_SEMAPHORE_H
//-----------------------------------------------------------------------------
//
// class Semaphore -- a wrapper class for
// system-dependent counting semaphores
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#include "IlmThreadExport.h"
#include "IlmThreadNamespace.h"
#if defined _WIN32 || defined _WIN64
# ifdef NOMINMAX
# undef NOMINMAX
# endif
# define NOMINMAX
# include <windows.h>
#elif HAVE_POSIX_SEMAPHORES
# include <semaphore.h>
#else
# ifdef ILMBASE_FORCE_CXX03
# if HAVE_PTHREAD
# include <pthread.h>
# endif
# else
# include <mutex>
# include <condition_variable>
# endif
#endif
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
class ILMTHREAD_EXPORT Semaphore
{
public:
Semaphore (unsigned int value = 0);
virtual ~Semaphore();
void wait();
bool tryWait();
void post();
int value() const;
private:
#if defined _WIN32 || defined _WIN64
mutable HANDLE _semaphore;
#elif HAVE_POSIX_SEMAPHORES
mutable sem_t _semaphore;
#else
//
// If the platform has Posix threads but no semapohores,
// then we implement them ourselves using condition variables
//
struct sema_t
{
unsigned int count;
unsigned long numWaiting;
# if ILMBASE_FORCE_CXX03
# if HAVE_PTHREAD
pthread_mutex_t mutex;
pthread_cond_t nonZero;
# else
# error unhandled legacy setup
# endif
# else
std::mutex mutex;
std::condition_variable nonZero;
# endif
};
mutable sema_t _semaphore;
#endif
void operator = (const Semaphore& s); // not implemented
Semaphore (const Semaphore& s); // not implemented
};
ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
#endif // INCLUDED_ILM_THREAD_SEMAPHORE_H

View File

@@ -0,0 +1,106 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Semaphore -- implementation for platforms
// that support Posix threads and Posix semaphores
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#if HAVE_PTHREAD && HAVE_POSIX_SEMAPHORES
#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <assert.h>
#include <errno.h>
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
Semaphore::Semaphore (unsigned int value)
{
if (::sem_init (&_semaphore, 0, value))
IEX_NAMESPACE::throwErrnoExc ("Cannot initialize semaphore (%T).");
}
Semaphore::~Semaphore ()
{
int error = ::sem_destroy (&_semaphore);
assert (error == 0);
}
void
Semaphore::wait ()
{
while( ::sem_wait( &_semaphore ) == -1 && errno == EINTR )
{
}
}
bool
Semaphore::tryWait ()
{
return sem_trywait (&_semaphore) == 0;
}
void
Semaphore::post ()
{
if (::sem_post (&_semaphore))
IEX_NAMESPACE::throwErrnoExc ("Post operation on semaphore failed (%T).");
}
int
Semaphore::value () const
{
int value;
if (::sem_getvalue (&_semaphore, &value))
IEX_NAMESPACE::throwErrnoExc ("Cannot read semaphore value (%T).");
return value;
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif

View File

@@ -0,0 +1,227 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Semaphore -- implementation for for platforms that do
// support Posix threads but do not support Posix semaphores,
// for example, OS X
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#if (!HAVE_POSIX_SEMAPHORES) && !defined (_WIN32) && ! defined (_WIN64)
#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <assert.h>
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
#if ILMBASE_FORCE_CXX03 && HAVE_PTHREAD
Semaphore::Semaphore (unsigned int value)
{
if (int error = ::pthread_mutex_init (&_semaphore.mutex, 0))
IEX_NAMESPACE::throwErrnoExc ("Cannot initialize mutex (%T).", error);
if (int error = ::pthread_cond_init (&_semaphore.nonZero, 0))
IEX_NAMESPACE::throwErrnoExc ("Cannot initialize condition variable (%T).",
error);
_semaphore.count = value;
_semaphore.numWaiting = 0;
}
Semaphore::~Semaphore ()
{
int error = ::pthread_cond_destroy (&_semaphore.nonZero);
assert (error == 0);
error = ::pthread_mutex_destroy (&_semaphore.mutex);
assert (error == 0);
}
void
Semaphore::wait ()
{
::pthread_mutex_lock (&_semaphore.mutex);
_semaphore.numWaiting++;
while (_semaphore.count == 0)
{
if (int error = ::pthread_cond_wait (&_semaphore.nonZero,
&_semaphore.mutex))
{
::pthread_mutex_unlock (&_semaphore.mutex);
IEX_NAMESPACE::throwErrnoExc ("Cannot wait on condition variable (%T).",
error);
}
}
_semaphore.numWaiting--;
_semaphore.count--;
::pthread_mutex_unlock (&_semaphore.mutex);
}
bool
Semaphore::tryWait ()
{
::pthread_mutex_lock (&_semaphore.mutex);
if (_semaphore.count == 0)
{
::pthread_mutex_unlock (&_semaphore.mutex);
return false;
}
else
{
_semaphore.count--;
::pthread_mutex_unlock (&_semaphore.mutex);
return true;
}
}
void
Semaphore::post ()
{
::pthread_mutex_lock (&_semaphore.mutex);
if (_semaphore.numWaiting > 0)
{
int error;
if (_semaphore.numWaiting > 1 && _semaphore.count > 1)
{
error = ::pthread_cond_broadcast (&_semaphore.nonZero);
}
else
{
error = ::pthread_cond_signal (&_semaphore.nonZero);
}
if (error)
{
::pthread_mutex_unlock (&_semaphore.mutex);
IEX_NAMESPACE::throwErrnoExc ("Cannot signal condition variable (%T).",
error);
}
}
_semaphore.count++;
::pthread_mutex_unlock (&_semaphore.mutex);
}
int
Semaphore::value () const
{
::pthread_mutex_lock (&_semaphore.mutex);
int value = _semaphore.count;
::pthread_mutex_unlock (&_semaphore.mutex);
return value;
}
#else
Semaphore::Semaphore (unsigned int value)
{
_semaphore.count = value;
_semaphore.numWaiting = 0;
}
Semaphore::~Semaphore ()
{
}
void
Semaphore::wait ()
{
std::unique_lock<std::mutex> lk(_semaphore.mutex);
_semaphore.numWaiting++;
while (_semaphore.count == 0)
_semaphore.nonZero.wait (lk);
_semaphore.numWaiting--;
_semaphore.count--;
}
bool
Semaphore::tryWait ()
{
std::lock_guard<std::mutex> lk(_semaphore.mutex);
if (_semaphore.count == 0)
return false;
_semaphore.count--;
return true;
}
void
Semaphore::post ()
{
std::lock_guard<std::mutex> lk(_semaphore.mutex);
_semaphore.count++;
if (_semaphore.numWaiting > 0)
{
if (_semaphore.count > 1)
_semaphore.nonZero.notify_all();
else
_semaphore.nonZero.notify_one();
}
}
int
Semaphore::value () const
{
std::lock_guard<std::mutex> lk(_semaphore.mutex);
return _semaphore.count;
}
#endif
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif

View File

@@ -0,0 +1,147 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Semaphore -- implementation for Windows
//
//-----------------------------------------------------------------------------
#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <string>
#include <assert.h>
#include <iostream>
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
using namespace IEX_NAMESPACE;
namespace {
std::string
errorString ()
{
LPSTR messageBuffer;
DWORD bufferLength;
std::string message;
//
// Call FormatMessage() to allow for message
// text to be acquired from the system.
//
if (bufferLength = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
GetLastError (),
MAKELANGID (LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPSTR) &messageBuffer,
0,
NULL))
{
message = messageBuffer;
LocalFree (messageBuffer);
}
return message;
}
} // namespace
Semaphore::Semaphore (unsigned int value)
{
if ((_semaphore = ::CreateSemaphore (0, value, 0x7fffffff, 0)) == 0)
{
THROW (LogicExc, "Could not create semaphore "
"(" << errorString() << ").");
}
}
Semaphore::~Semaphore()
{
bool ok = ::CloseHandle (_semaphore) != FALSE;
assert (ok);
}
void
Semaphore::wait()
{
if (::WaitForSingleObject (_semaphore, INFINITE) != WAIT_OBJECT_0)
{
THROW (LogicExc, "Could not wait on semaphore "
"(" << errorString() << ").");
}
}
bool
Semaphore::tryWait()
{
return ::WaitForSingleObject (_semaphore, 0) == WAIT_OBJECT_0;
}
void
Semaphore::post()
{
if (!::ReleaseSemaphore (_semaphore, 1, 0))
{
THROW (LogicExc, "Could not post on semaphore "
"(" << errorString() << ").");
}
}
int
Semaphore::value() const
{
LONG v = -1;
if (!::ReleaseSemaphore (_semaphore, 0, &v) || v < 0)
{
THROW (LogicExc, "Could not get value of semaphore "
"(" << errorString () << ").");
}
return v;
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT

View File

@@ -0,0 +1,101 @@
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005-2012, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// class Thread -- implementation for Windows
//
//-----------------------------------------------------------------------------
#include "IlmBaseConfig.h"
#ifdef ILMBASE_FORCE_CXX03
#include "IlmThread.h"
#include "Iex.h"
#include <iostream>
#include <assert.h>
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_ENTER
bool
supportsThreads ()
{
return true;
}
namespace {
unsigned __stdcall
threadLoop (void * t)
{
reinterpret_cast<Thread*>(t)->run();
_endthreadex (0);
return 0;
}
} // namespace
Thread::Thread ()
{
// empty
}
Thread::~Thread ()
{
DWORD status = ::WaitForSingleObject (_thread, INFINITE);
assert (status == WAIT_OBJECT_0);
bool ok = ::CloseHandle (_thread) != FALSE;
assert (ok);
}
void
Thread::start ()
{
unsigned id;
_thread = (HANDLE)::_beginthreadex (0, 0, &threadLoop, this, 0, &id);
if (_thread == 0)
IEX_NAMESPACE::throwErrnoExc ("Cannot create new thread (%T).");
}
ILMTHREAD_INTERNAL_NAMESPACE_SOURCE_EXIT
#endif