Commit cfc5aef0 authored by Chris Cantwell's avatar Chris Cantwell

Merge branch 'master' into feature/FieldConvertCleanUp

Conflicts:
	utilities/PostProcessing/FieldConvert/CMakeLists.txt
parents d3823772 6c3be247
......@@ -111,7 +111,8 @@ OperatorFactory& GetOperatorFactory()
{
typedef Loki::SingletonHolder<OperatorFactory,
Loki::CreateUsingNew,
Loki::NoDestroy > Type;
Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance();
}
......
......@@ -66,7 +66,8 @@ namespace Nektar
{
typedef Loki::SingletonHolder<MeshPartitionFactory,
Loki::CreateUsingNew,
Loki::NoDestroy > Type;
Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance();
}
......
......@@ -43,6 +43,8 @@
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/shared_ptr.hpp>
......@@ -65,6 +67,8 @@ namespace Nektar
// Generate parameter typenames with default type of 'none'
#define FACTORY_print(z, n, data) BOOST_PP_CAT(data, n) = none
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
/**
* @class NekFactory
......@@ -144,7 +148,7 @@ namespace Nektar
public:
NekFactory() {}
NekFactory() : m_mutex() {}
/**
* @brief Create an instance of the class referred to by \c idKey.
......@@ -158,6 +162,9 @@ namespace Nektar
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM)
BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
{
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey);
......@@ -165,11 +172,14 @@ namespace Nektar
// create a new instance of the class.
if (it != getMapFactory()->end())
{
if (it->second.m_func)
ModuleEntry *tmp = &(it->second);
vReadLock.unlock();
if (tmp->m_func)
{
try
{
return it->second.m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x));
return tmp->m_func(BOOST_PP_ENUM_PARAMS(MAX_PARAM, x));
}
catch (const std::string& s)
{
......@@ -205,6 +215,8 @@ namespace Nektar
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator,
tDescription pDesc = "")
{
WriteLock vWriteLock(m_mutex);
ModuleEntry e(classCreator, pDesc);
getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
return idKey;
......@@ -216,6 +228,8 @@ namespace Nektar
*/
bool ModuleExists(tKey idKey)
{
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey);
......@@ -232,6 +246,8 @@ namespace Nektar
*/
void PrintAvailableClasses(std::ostream& pOut = std::cout)
{
ReadLock vReadLock(m_mutex);
pOut << std::endl << "Available classes: " << std::endl;
TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
......@@ -260,6 +276,8 @@ namespace Nektar
*/
tKey GetKey(tDescription pDesc)
{
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
{
......@@ -280,6 +298,8 @@ namespace Nektar
*/
std::string GetClassDescription(tKey idKey)
{
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey);
......@@ -305,6 +325,8 @@ namespace Nektar
TMapFactory mMapFactory;
boost::shared_mutex m_mutex;
};
#undef FACTORY_print
......@@ -325,6 +347,11 @@ namespace Nektar
#define n BOOST_PP_ITERATION()
// Define macro for printing the non-required template parameters
#define FACTORY_print(z, n, data) data
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
template < typename tKey,
typename tBase BOOST_PP_COMMA_IF(n)
......@@ -352,19 +379,24 @@ namespace Nektar
typedef std::map<tKey, ModuleEntry, tPredicator> TMapFactory;
typedef typename TMapFactory::iterator TMapFactoryIterator;
NekFactory() {}
NekFactory() : m_mutex() {}
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(n)
BOOST_PP_ENUM_BINARY_PARAMS(n, tParam, x))
{
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it = getMapFactory()->find(idKey);
if (it != getMapFactory()->end())
{
if (it->second.m_func)
ModuleEntry *tmp = &(it->second);
vReadLock.unlock();
if (tmp->m_func)
{
try
{
return it->second.m_func(BOOST_PP_ENUM_PARAMS(n, x));
return tmp->m_func(BOOST_PP_ENUM_PARAMS(n, x));
}
catch (const std::string& s)
{
......@@ -385,6 +417,8 @@ namespace Nektar
tKey RegisterCreatorFunction(tKey idKey,
CreatorFunction classCreator,
tDescription pDesc = "") {
WriteLock vWriteLock(m_mutex);
ModuleEntry e(classCreator, pDesc);
getMapFactory()->insert(std::pair<tKey,ModuleEntry>(idKey, e));
return idKey;
......@@ -392,6 +426,8 @@ namespace Nektar
bool ModuleExists(tKey idKey)
{
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey);
......@@ -404,6 +440,8 @@ namespace Nektar
void PrintAvailableClasses(std::ostream& pOut = std::cout)
{
ReadLock vReadLock(m_mutex);
pOut << std::endl << "Available classes: " << std::endl;
TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
......@@ -423,6 +461,8 @@ namespace Nektar
tKey GetKey(tDescription pDesc)
{
ReadLock vReadLock(m_mutex);
TMapFactoryIterator it;
for (it = getMapFactory()->begin(); it != getMapFactory()->end(); ++it)
{
......@@ -439,6 +479,8 @@ namespace Nektar
std::string GetClassDescription(tKey idKey)
{
ReadLock vReadLock(m_mutex);
// Now try and find the key in the map.
TMapFactoryIterator it = getMapFactory()->find(idKey);
......@@ -458,6 +500,8 @@ namespace Nektar
NekFactory& operator=(const NekFactory& rhs);
TMapFactory mMapFactory;
boost::shared_mutex m_mutex;
};
#undef n
#undef FACTORY_print
......
......@@ -41,6 +41,8 @@
#include <boost/function.hpp>
#include <boost/call_traits.hpp>
#include <boost/concept_check.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/shared_ptr.hpp>
#include <LibUtilities/BasicUtils/ErrorUtil.hpp>
......@@ -51,6 +53,9 @@ namespace Nektar
{
namespace LibUtilities
{
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
typedef boost::shared_lock<boost::shared_mutex> ReadLock;
template <typename KeyType>
struct defOpLessCreator
{
......@@ -76,9 +81,10 @@ namespace Nektar
typedef std::map<std::string, BoolSharedPtr> FlagContainerPool;
NekManager(std::string whichPool="") :
m_values(),
m_values(),
m_globalCreateFunc(),
m_keySpecificCreateFuncs()
{
if (!whichPool.empty())
{
......@@ -114,6 +120,7 @@ namespace Nektar
{
if (!whichPool.empty())
{
ReadLock v_rlock(m_mutex); // reading static members
typename ValueContainerPool::iterator iter = m_ValueContainerPool.find(whichPool);
if (iter != m_ValueContainerPool.end())
{
......@@ -122,6 +129,12 @@ namespace Nektar
}
else
{
v_rlock.unlock();
// now writing static members. Apparently upgrade_lock has less desirable properties
// than just dropping read lock, grabbing write lock.
// write will block until all reads are done, but reads cannot be acquired if write
// lock is blocking. In this context writes are supposed to be rare.
WriteLock v_wlock(m_mutex);
m_values = ValueContainerShPtr(new ValueContainer);
m_ValueContainerPool[whichPool] = m_values;
if (m_managementEnabledContainerPool.find(whichPool) == m_managementEnabledContainerPool.end())
......@@ -138,14 +151,14 @@ namespace Nektar
m_managementEnabled = BoolSharedPtr(new bool(true));
}
}
~NekManager()
{
}
/// Register the given function and associate it with the key.
/// The return value is just to facilitate calling statically.
bool RegisterCreator(typename boost::call_traits<KeyType>::const_reference key,
bool RegisterCreator(typename boost::call_traits<KeyType>::const_reference key,
const CreateFuncType& createFunc)
{
m_keySpecificCreateFuncs[key] = createFunc;
......@@ -170,7 +183,7 @@ namespace Nektar
{
value = true;
}
return value;
}
......@@ -227,6 +240,8 @@ namespace Nektar
typename ValueContainerPool::iterator x;
if (!whichPool.empty())
{
WriteLock v_wlock(m_mutex);
x = m_ValueContainerPool.find(whichPool);
ASSERTL1(x != m_ValueContainerPool.end(),
"Could not find pool " + whichPool);
......@@ -234,6 +249,8 @@ namespace Nektar
}
else
{
WriteLock v_wlock(m_mutex);
for (x = m_ValueContainerPool.begin(); x != m_ValueContainerPool.end(); ++x)
{
x->second->clear();
......@@ -246,6 +263,8 @@ namespace Nektar
typename FlagContainerPool::iterator x;
if (!whichPool.empty())
{
WriteLock v_wlock(m_mutex);
x = m_managementEnabledContainerPool.find(whichPool);
if (x != m_managementEnabledContainerPool.end())
{
......@@ -263,6 +282,8 @@ namespace Nektar
typename FlagContainerPool::iterator x;
if (!whichPool.empty())
{
WriteLock v_wlock(m_mutex);
x = m_managementEnabledContainerPool.find(whichPool);
if (x != m_managementEnabledContainerPool.end())
{
......@@ -276,8 +297,8 @@ namespace Nektar
}
private:
NekManager(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
NekManager<KeyType, ValueType, opLessCreator>& operator=(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
NekManager(const NekManager<KeyType, ValueType, opLessCreator>& rhs);
ValueContainerShPtr m_values;
BoolSharedPtr m_managementEnabled;
......@@ -285,9 +306,12 @@ namespace Nektar
static FlagContainerPool m_managementEnabledContainerPool;
CreateFuncType m_globalCreateFunc;
CreateFuncContainer m_keySpecificCreateFuncs;
static boost::shared_mutex m_mutex;
};
template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::ValueContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_ValueContainerPool;
template <typename KeyType, typename ValueT, typename opLessCreator> typename NekManager<KeyType, ValueT, opLessCreator>::FlagContainerPool NekManager<KeyType, ValueT, opLessCreator>::m_managementEnabledContainerPool;
template <typename KeyType, typename ValueT, typename opLessCreator>
typename boost::shared_mutex NekManager<KeyType, ValueT, opLessCreator>::m_mutex;
}
}
......
///////////////////////////////////////////////////////////////////////////////
//
// File Thread.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: Thread manager
//
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include "LibUtilities/BasicUtils/Thread.h"
namespace Nektar
{
namespace Thread
{
/**
*
*/
ThreadManagerFactory& GetThreadManagerFactory()
{
typedef Loki::SingletonHolder<ThreadManagerFactory,
Loki::CreateUsingNew,
Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance();
}
/**
* @brief ThreadJob implementation
*/
ThreadJob::ThreadJob()
{
// empty
}
/**
*
*/
ThreadJob::~ThreadJob()
{
// empty
}
/**
* Part of the thread interface. Do not use unless you're
* an implementation of ThreadManager.
* @warning Do not use: needs to be public so thread implementation can call it.
*/
void ThreadJob::SetWorkerNum(unsigned int num)
{
m_workerNum = num;
}
/**
*
*/
unsigned int ThreadJob::GetWorkerNum()
{
return m_workerNum;
}
/**
* Implementations should not override this function, since they
* are initialised.
*
* @returns True if this ThreadManager has been initialised.
*/
bool ThreadManager::IsInitialised()
{
return true;
}
/**
* Should stop worker threads and clean up.
* This shouldn't be called until the program is exiting
* anyway, some implementations may need to unlock threads
* to allow clean exit.
*/
ThreadManager::~ThreadManager()
{
// empty
}
/**
* ThreadMaster implementation
*/
ThreadMaster::ThreadMaster() : m_threadManagers(THREADMANAGER_MAX),
m_mutex(), m_threadingType()
{
// empty
}
/**
* Will clear the list of ThreadManagers, destructing them.
*/
ThreadMaster::~ThreadMaster()
{
// Locking is a bit pointless, since the map is empty after this call.
m_threadManagers.clear();
}
/**
*
*/
ThreadMaster& GetThreadMaster()
{
typedef Loki::SingletonHolder<ThreadMaster,
Loki::CreateUsingNew,
Loki::NoDestroy,
Loki::SingleThreaded> Type;
return Type::Instance();
}
/**
* @param p_type String to be passed to the ThreadManagerFactory
*
* Subsequent CreateInstance calls will pass this string to the
* ThreadManagerFactory to create a ThreadManager.
*
* It is an error to call this more than once (since having different kinds of
* ThreadManager active is probably a stupendously bad idea).
*/
void ThreadMaster::SetThreadingType(const std::string &p_type)
{
ASSERTL0(m_threadingType.empty(),
"Tried to SetThreadingType when it was already set");
m_threadingType = p_type;
}
/**
* @returns a shared pointer to /em either a ThreadStartupManager
* or whatever ThreadManager has been created for the string s
* with CreateInstance.
*
* Calling code may store the result if it is sure the call to
* GetInstance(s) has occurred after the call to CreateInstance(s).
* This cannot be before threadedcommReader::StartThreads(), as that's
* where SetThreadingType is called.
*
* @warning Static initialisation may want to access a ThreadManager.
* Such code must be able to cope with the temporary ThreadStartupManager.
*/
ThreadManagerSharedPtr& ThreadMaster::GetInstance(const ThreadManagerName t)
{
if ( !m_threadManagers[t] )
{
m_threadManagers[t] = ThreadManagerSharedPtr(
new ThreadStartupManager());
return m_threadManagers[t];
}
return m_threadManagers[t];
}
/**
* @return Shared pointer to the created ThreadManager.
*
* An error occurs if this is called before SetThreadingType.
*/
ThreadManagerSharedPtr ThreadMaster::CreateInstance(const ThreadManagerName t,
unsigned int nThr)
{
ASSERTL0(!m_threadingType.empty(),
"Trying to create a ThreadManager before SetThreadingType called");
return m_threadManagers[t] =
Thread::GetThreadManagerFactory().CreateInstance(m_threadingType, nThr);
}
/**
* @brief ThreadDefaultManager
*/
ThreadStartupManager::ThreadStartupManager() : m_type("Threading starting up")
{
// empty
}
/**
*
*/
ThreadStartupManager::~ThreadStartupManager()
{
// empty
}
/**
*
*/
void ThreadStartupManager::QueueJobs(std::vector<ThreadJob*>& joblist)
{
NEKERROR(ErrorUtil::efatal,
"Attempted to QueueJobs in ThreadDefaultManager");
}
/**
*
*/
void ThreadStartupManager::QueueJob(ThreadJob* job)
{
NEKERROR(ErrorUtil::efatal,
"Attempted to QueueJob in ThreadDefaultManager");
}
/**
*
*/
unsigned int ThreadStartupManager::GetNumWorkers()
{
return 1;
}
/**
*
*/
unsigned int ThreadStartupManager::GetWorkerNum()
{
return 0;
}
/**
*
*/
void ThreadStartupManager::SetNumWorkers(const unsigned int num)
{
ASSERTL0(num==1,
"Attempted to SetNumWorkers to != 1 in ThreadDefaultManager");
}
/**
*
*/
void ThreadStartupManager::SetNumWorkers()
{
return;
}
/**
*
*/
unsigned int ThreadStartupManager::GetMaxNumWorkers()
{
return 1;
}
/**
*
*/
void ThreadStartupManager::Wait()
{
return;
}
/**
*
*/
void ThreadStartupManager::SetChunkSize(unsigned int chnk)
{
NEKERROR(ErrorUtil::efatal,
"Attempted to SetChunkSize in ThreadDefaultManager");
}
/**
*
*/
void ThreadStartupManager::SetSchedType(SchedType s)
{
NEKERROR(ErrorUtil::efatal,
"Attempted to SetSchedType in ThreadDefaultManager");
}
/**
*
*/
bool ThreadStartupManager::InThread()
{
return false;
}