Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
10
src/core/util/CMakeLists.txt
Normal file
10
src/core/util/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
set(SRCS
|
||||
SynchronizedCounter.cc
|
||||
Logger.hpp
|
||||
Logger.cc
|
||||
ProtoStream.cc
|
||||
)
|
||||
|
||||
add_library(util ${SRCS})
|
||||
|
||||
# FIXME: Add protobuf-dependency (required by ProtoStream.cc@line56)
|
||||
26
src/core/util/Logger.cc
Normal file
26
src/core/util/Logger.cc
Normal file
@ -0,0 +1,26 @@
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <time.h>
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
void Logger::timestamp()
|
||||
{
|
||||
(*m_pDest) << "[" << m_description;
|
||||
if (m_showTime) {
|
||||
time_t rawtime;
|
||||
struct tm* timeinfo;
|
||||
char buffer[80];
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buffer, 80, "%H:%M:%S", timeinfo);
|
||||
(*m_pDest) << " " << buffer;
|
||||
}
|
||||
(*m_pDest) << "] ";
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
53
src/core/util/Logger.hpp
Normal file
53
src/core/util/Logger.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __LOGGER_HPP__
|
||||
#define __LOGGER_HPP__
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class Logger
|
||||
* Provides logging mechanisms.
|
||||
*/
|
||||
class Logger {
|
||||
private:
|
||||
std::ostream* m_pDest;
|
||||
std::string m_description;
|
||||
bool m_showTime;
|
||||
void timestamp();
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param description Description shown alongside each log entry in
|
||||
* square brackets [ ]. Can be overridden in single add() calls.
|
||||
* @param show_time Show a timestamp with each log entry.
|
||||
* @param dest Stream to log into.
|
||||
*/
|
||||
Logger(const std::string& description = "Fail*", bool show_time = true,
|
||||
std::ostream& dest = std::cout)
|
||||
: m_pDest(&dest), m_description(description), m_showTime(show_time) { }
|
||||
/**
|
||||
* Change the default description which is shown alongside each log
|
||||
* entry in square brackets [ ].
|
||||
* @param descr The description text.
|
||||
*/
|
||||
void setDescription(const std::string& descr) { m_description = descr; }
|
||||
/**
|
||||
* Change the default option of show_time which shows a timestamp
|
||||
* each log entry.
|
||||
* @param choice The choice for show_time
|
||||
*/
|
||||
void showTime(bool choice) { m_showTime = choice; }
|
||||
/**
|
||||
* Add a new log entry.
|
||||
* @param v data to log
|
||||
* @return a \c std::ostream reference to continue streaming a longer log entry
|
||||
*/
|
||||
template<class T>
|
||||
inline std::ostream& operator <<(const T& v) { timestamp(); return (*m_pDest) << v; }
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __LOGGER_HPP__
|
||||
80
src/core/util/MemoryMap.hpp
Normal file
80
src/core/util/MemoryMap.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef __MEMORYMAP_HPP__
|
||||
#define __MEMORYMAP_HPP__
|
||||
|
||||
#ifdef BOOST_1_46_OR_NEWER
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
using namespace boost::icl;
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class MemoryMap
|
||||
* An efficient container for memory maps with holes.
|
||||
*/
|
||||
class MemoryMap {
|
||||
private:
|
||||
#ifdef BOOST_1_46_OR_NEWER
|
||||
typedef interval<address_t>::type address_interval;
|
||||
typedef interval_set<address_t>::type address_set;
|
||||
|
||||
address_set as;
|
||||
public:
|
||||
MemoryMap() { }
|
||||
void clear() { as.clear(); }
|
||||
void add(address_t addr, int size) { as.add(address_interval(addr, addr+size-1)); }
|
||||
void isMatching(address_t addr, int size) { return intersects(as, address_interval(addr, addr+size-1)); }
|
||||
#endif
|
||||
std::set<address_t> as;
|
||||
public:
|
||||
MemoryMap() { }
|
||||
/**
|
||||
* Clears the map.
|
||||
*/
|
||||
void clear() { as.clear(); }
|
||||
/**
|
||||
* Adds one or a sequence of addresses to the map.
|
||||
*/
|
||||
void add(address_t addr, int size = 1)
|
||||
{
|
||||
for (int i = 0; i < size; ++i) {
|
||||
as.insert(addr + i);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Determines whether a given memory access at address \a addr with width
|
||||
* \a size hits the map.
|
||||
*/
|
||||
bool isMatching(address_t addr, int size = 1)
|
||||
{
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (as.find(addr + i) != as.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* The (STL-style) iterator of this class used to iterate over all
|
||||
* addresses in this map.
|
||||
*/
|
||||
typedef std::set<address_t>::iterator iterator;
|
||||
/**
|
||||
* Returns an (STL-style) iterator to the beginning of the internal data
|
||||
* structure.
|
||||
*/
|
||||
iterator begin() { return as.begin(); }
|
||||
/**
|
||||
* Returns an (STL-style) iterator to the end of the interal data
|
||||
* structure.
|
||||
*/
|
||||
iterator end() { return as.end(); }
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __MEMORYMAP_HPP__
|
||||
62
src/core/util/ProtoStream.cc
Normal file
62
src/core/util/ProtoStream.cc
Normal file
@ -0,0 +1,62 @@
|
||||
#include "ProtoStream.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
ProtoOStream::ProtoOStream(std::ostream *outfile) : m_outfile(outfile)
|
||||
{
|
||||
m_log.setDescription("ProtoStream");
|
||||
// TODO: log-Level?
|
||||
m_log.showTime(false);
|
||||
}
|
||||
|
||||
bool ProtoOStream::writeMessage(google::protobuf::Message* m)
|
||||
{
|
||||
m_size = htonl(m->ByteSize());
|
||||
m_outfile->write(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
|
||||
if (m_outfile->bad()) {
|
||||
m_log << "Could not write to file!" << std::endl;
|
||||
// TODO: log-Level?
|
||||
return false;
|
||||
}
|
||||
|
||||
m->SerializeToOstream(m_outfile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ProtoIStream::ProtoIStream(std::istream *infile) : m_infile(infile)
|
||||
{
|
||||
m_log.setDescription("ProtoStream");
|
||||
// TODO: log-Level?
|
||||
m_log.showTime(false);
|
||||
}
|
||||
|
||||
void ProtoIStream::reset()
|
||||
{
|
||||
m_infile->clear();
|
||||
m_infile->seekg(0, std::ios::beg);
|
||||
}
|
||||
|
||||
bool ProtoIStream::getNext(google::protobuf::Message* m)
|
||||
{
|
||||
m_infile->read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
|
||||
if (!m_infile->good())
|
||||
return false;
|
||||
m_size = ntohl(m_size);
|
||||
|
||||
// FIXME reuse buffer (efficiency)
|
||||
// FIXME new[] may fail (i.e., return 0)
|
||||
char *buf = new char[m_size];
|
||||
m_infile->read(buf, m_size);
|
||||
if (!m_infile->good())
|
||||
// FIXME we're leaking buf[]
|
||||
return false;
|
||||
std::string st(buf, m_size);
|
||||
m->ParseFromString(st);
|
||||
|
||||
delete [] buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
81
src/core/util/ProtoStream.hpp
Normal file
81
src/core/util/ProtoStream.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* \brief One way to manage large protobuf-messages
|
||||
*
|
||||
* Google protobuf is not designed for large messages. That leads to
|
||||
* much memory which is consumed by processing large messages. To
|
||||
* solve this problem the ProtoStream class stores the protobuf-messages
|
||||
* in an other way. Instead of using the repeat-function the data is
|
||||
* written sequentially in a file. Written in the format:
|
||||
*
|
||||
* \code
|
||||
* | 4 bytes length-information of the first message | first message
|
||||
* | 4 bytes length-information of the second message | second message
|
||||
* | ...
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#ifndef __PROTOSTREAM_HPP__
|
||||
#define __PROTOSTREAM_HPP__
|
||||
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class ProtoOStream
|
||||
*
|
||||
* This class can be used to sequentially write a large number of
|
||||
* protocol buffer messages to a \c std::ostream.
|
||||
*/
|
||||
class ProtoOStream {
|
||||
private:
|
||||
uint32_t m_size; // TODO: comments needed here
|
||||
Logger m_log;
|
||||
std::ostream* m_outfile;
|
||||
public:
|
||||
ProtoOStream(std::ostream *outfile);
|
||||
virtual ~ProtoOStream() { }
|
||||
/**
|
||||
* Writes a message to a file.
|
||||
* @param m The protobuf-message to be written
|
||||
* @return Returns \c true on success, \c false otherwise
|
||||
*/
|
||||
bool writeMessage(google::protobuf::Message* m);
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ProtoIStream
|
||||
*
|
||||
* This class can be used to read protocol buffer messages sequentially
|
||||
* from a \c std::istream.
|
||||
*/
|
||||
class ProtoIStream {
|
||||
private:
|
||||
uint32_t m_size; // TODO: comments needed here
|
||||
long m_sizeOfInfile;
|
||||
Logger m_log;
|
||||
std::istream *m_infile;
|
||||
public:
|
||||
ProtoIStream(std::istream *infile);
|
||||
virtual ~ProtoIStream() { }
|
||||
/**
|
||||
* Resets the position of the get pointer. After that \c getNext()
|
||||
* reads the first message again.
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* Reads the next protobuf message from the input stream.
|
||||
* @param m The output protobuf message
|
||||
* @return Returns \c true on success, \c false otherwise
|
||||
*/
|
||||
bool getNext(google::protobuf::Message* m);
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __PROTOSTREAM_HPP__
|
||||
29
src/core/util/SynchronizedCounter.cc
Normal file
29
src/core/util/SynchronizedCounter.cc
Normal file
@ -0,0 +1,29 @@
|
||||
#include "SynchronizedCounter.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
int SynchronizedCounter::increment()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
return ++m_counter;
|
||||
}
|
||||
|
||||
int SynchronizedCounter::decrement()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
return --m_counter;
|
||||
}
|
||||
|
||||
int SynchronizedCounter::getValue()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
return m_counter;
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
38
src/core/util/SynchronizedCounter.hpp
Normal file
38
src/core/util/SynchronizedCounter.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* \brief Thread safe (synchronized) counter.
|
||||
*/
|
||||
|
||||
#ifndef __SYNCHRONIZED_COUNTER_HPP__
|
||||
#define __SYNCHRONIZED_COUNTER_HPP__
|
||||
|
||||
#ifndef __puma
|
||||
#include <boost/thread.hpp>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class ssd
|
||||
*
|
||||
* Provides a thread safe (synchronized) counter. When a method is called,
|
||||
* the internal mutex is automatically locked. On return, the lock is
|
||||
* automatically released ("scoped lock").
|
||||
*/
|
||||
class SynchronizedCounter {
|
||||
private:
|
||||
int m_counter;
|
||||
#ifndef __puma
|
||||
boost::mutex m_mutex; //! The mutex to synchronise on
|
||||
#endif
|
||||
public:
|
||||
SynchronizedCounter() : m_counter(0) { }
|
||||
|
||||
int increment();
|
||||
int decrement();
|
||||
int getValue();
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __SYNCHRONIZED_COUNTER_HPP__
|
||||
116
src/core/util/SynchronizedMap.hpp
Normal file
116
src/core/util/SynchronizedMap.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* \brief Map class that has thread synchronisation
|
||||
*/
|
||||
|
||||
#ifndef __SYNCHRONIZED_MAP_HPP__
|
||||
#define __SYNCHRONIZED_MAP_HPP__
|
||||
|
||||
#include <map>
|
||||
|
||||
#ifndef __puma
|
||||
#include <boost/thread.hpp>
|
||||
#endif
|
||||
|
||||
// TODO: We should consider to use Aspects for synchronisation primitives.
|
||||
|
||||
namespace fail {
|
||||
|
||||
template <typename Tkey, typename Tvalue>
|
||||
class SynchronizedMap {
|
||||
private:
|
||||
typedef std::map< Tkey, Tvalue > Tmap;
|
||||
typedef typename Tmap::iterator Tit;
|
||||
|
||||
Tmap m_map; //! Use STL map to store data
|
||||
#ifndef __puma
|
||||
boost::mutex m_mutex; //! The mutex to synchronise on
|
||||
#endif
|
||||
|
||||
int nextpick;
|
||||
enum { pick_window_size = 500 };
|
||||
|
||||
public:
|
||||
SynchronizedMap() : nextpick(0) { }
|
||||
int Size()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
return m_map.size();
|
||||
}
|
||||
/**
|
||||
* Retrieves one element from the map from a small window at the beginning.
|
||||
* @return a pointer to the element, or \c NULL if empty
|
||||
*/
|
||||
Tvalue pickone()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
if (m_map.size() == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// XXX not really elegant: linear complexity
|
||||
typename Tmap::iterator it = m_map.begin();
|
||||
for (int i = 0; i < nextpick; ++i) {
|
||||
++it;
|
||||
if (it == m_map.end()) {
|
||||
it = m_map.begin();
|
||||
nextpick = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++nextpick;
|
||||
if (nextpick >= pick_window_size) {
|
||||
nextpick = 0;
|
||||
}
|
||||
return it->second;
|
||||
} // Lock is automatically released here
|
||||
/**
|
||||
* Add data to the map, return false if already present
|
||||
* @param key Map key
|
||||
* @param value value according to key
|
||||
* @return false if key already present
|
||||
*/
|
||||
bool insert(const Tkey& key, const Tvalue& value)
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
if( m_map.find(key) == m_map.end() ){ // not present, add it
|
||||
m_map[key] = value;
|
||||
return true;
|
||||
}else{ // item is already in, oops
|
||||
return false;
|
||||
}
|
||||
|
||||
} // Lock is automatically released here
|
||||
|
||||
/**
|
||||
* Remove value from the map.
|
||||
* @param key The Map key to remove
|
||||
* @return false if key was not present
|
||||
*
|
||||
*/
|
||||
bool remove(const Tkey& key, Tvalue& value)
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
Tit iterator;
|
||||
if ((iterator = m_map.find(key)) != m_map.end()) {
|
||||
value = iterator->second;
|
||||
m_map.erase(iterator);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} // Lock is automatically released here
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __SYNCHRONIZED_MAP_HPP__
|
||||
96
src/core/util/SynchronizedQueue.hpp
Normal file
96
src/core/util/SynchronizedQueue.hpp
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* \brief Queue class that has thread synchronisation.
|
||||
*/
|
||||
|
||||
#ifndef __SYNCHRONIZED_QUEUE_HPP__
|
||||
#define __SYNCHRONIZED_QUEUE_HPP__
|
||||
|
||||
#include <queue>
|
||||
|
||||
#ifndef __puma
|
||||
#include <boost/thread.hpp>
|
||||
#endif
|
||||
|
||||
namespace fail {
|
||||
|
||||
template <typename T>
|
||||
class SynchronizedQueue { // Adapted from: http://www.quantnet.com/cplusplus-multithreading-boost/
|
||||
private:
|
||||
std::queue<T> m_queue; //!< Use STL queue to store data
|
||||
#ifndef __puma
|
||||
boost::mutex m_mutex; //!< The mutex to synchronise on
|
||||
boost::condition_variable m_cond; //!< The condition to wait for
|
||||
#endif
|
||||
public:
|
||||
int Size()
|
||||
{
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
return m_queue.size();
|
||||
}
|
||||
// Add data to the queue and notify others
|
||||
void Enqueue(const T& data)
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
// Add the data to the queue
|
||||
m_queue.push(data);
|
||||
// Notify others that data is ready
|
||||
#ifndef __puma
|
||||
m_cond.notify_one();
|
||||
#endif
|
||||
} // Lock is automatically released here
|
||||
|
||||
/**
|
||||
* Get data from the queue. Wait for data if not available
|
||||
*/
|
||||
T Dequeue()
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
// When there is no data, wait till someone fills it.
|
||||
// Lock is automatically released in the wait and obtained
|
||||
// again after the wait
|
||||
#ifndef __puma
|
||||
while (m_queue.size() == 0)
|
||||
m_cond.wait(lock);
|
||||
#endif
|
||||
// Retrieve the data from the queue
|
||||
T result=m_queue.front(); m_queue.pop();
|
||||
return result;
|
||||
} // Lock is automatically released here
|
||||
|
||||
|
||||
/**
|
||||
* Get data from the queue. Non blocking variant.
|
||||
* @param d Pointer to copy queue element to
|
||||
* @return false if no element in queue
|
||||
*
|
||||
*/
|
||||
bool Dequeue_nb(T& d)
|
||||
{
|
||||
// Acquire lock on the queue
|
||||
#ifndef __puma
|
||||
boost::unique_lock<boost::mutex> lock(m_mutex);
|
||||
#endif
|
||||
// When there is no data, return false.
|
||||
// Lock is automatically released in the wait and obtained
|
||||
// again after the wait
|
||||
if (m_queue.size() > 0) {
|
||||
// Retrieve the data from the queue
|
||||
d = m_queue.front(); m_queue.pop();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} // Lock is automatically released here
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __SYNCHRONIZED_QUEUE_HPP__
|
||||
Reference in New Issue
Block a user