Assimilate exceptions and RefPtr from mspmisc
authorMikko Rasa <tdb@tdb.fi>
Fri, 25 May 2007 17:22:57 +0000 (17:22 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 25 May 2007 17:22:57 +0000 (17:22 +0000)
Assimilate GetOpt
Do not require pthread on win32
Add an optional feature to generate backtraces on exceptions
Allow semaphores to be created with an external mutex
Rewrite win32 semaphore implementation to more closely correspond the POSIX one
Allow MutexLock to be unlocked initially
Rewrite MutexPtr to use a RefPtr<MutexLock> instead of being refcounted itself
Fix some multiple inclusion guards
Add $Id$ tags
Fix Time::now() on win32

24 files changed:
Build
source/core/application.cpp
source/core/application.h
source/core/error.cpp [new file with mode: 0644]
source/core/error.h
source/core/getopt.cpp [new file with mode: 0644]
source/core/getopt.h [new file with mode: 0644]
source/core/main.cpp
source/core/mutex.h
source/core/refptr.h [new file with mode: 0644]
source/core/semaphore.cpp
source/core/semaphore.h
source/core/thread.cpp
source/core/thread.h
source/core/types.h
source/debug/backtrace.cpp [new file with mode: 0644]
source/debug/backtrace.h [new file with mode: 0644]
source/debug/demangle.cpp [new file with mode: 0644]
source/debug/demangle.h [new file with mode: 0644]
source/time/datetime.cpp
source/time/timedelta.cpp
source/time/timedelta.h
source/time/utils.cpp
source/time/utils.h

diff --git a/Build b/Build
index bec4c611147ddd37f86acb54d416b7c75421831b..d172391103c3d5d57894284d7083105aa5fa5de1 100644 (file)
--- a/Build
+++ b/Build
@@ -3,9 +3,13 @@ package "mspcore"
        version "0.1";
        description "Mikkosoft Productions core library";
 
-       require "mspmisc";
-       require "pthread";
        require "sigc++-2.0";
+       if "arch!=win32"
+       {
+               require "pthread";
+       };
+
+       feature "exception_backtrace" "Generate a backtrace when an exception is thrown.";
 
        library "mspcore"
        {
index 1012ea20f8b3ae400ead7b23fec92af737e8c2c2..0e93a9c653064ec4aeccbd39d358a80e74fb7be9 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
index fa0c9c41bcf42a7923237b21cdcc410233599226..81569ad45a965ad85c165a7eb5914f360be3f9a7 100644 (file)
@@ -1,10 +1,11 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_APPLICATION_H_
-#define MSP_FRAMEWORK_APPLICATION_H_
+#ifndef MSP_CORE_APPLICATION_H_
+#define MSP_CORE_APPLICATION_H_
 
 #include "semaphore.h"
 
@@ -29,7 +30,7 @@ protected:
                TICK_SLEEP, /// Call tick every iteration, with a short sleep in between
                TICK_YIELD  /// Call tick every iteration, with sched_yield in between
        };
-       
+
        class RegBase
        {
        public:
diff --git a/source/core/error.cpp b/source/core/error.cpp
new file mode 100644 (file)
index 0000000..727fa21
--- /dev/null
@@ -0,0 +1,40 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <sstream>
+#include "backtrace.h"
+#include "error.h"
+
+using namespace std;
+
+namespace Msp {
+
+Exception::Exception(const string &w_):
+       w(w_)
+{
+#ifdef WITH_EXCEPTION_BACKTRACE
+       bt=Backtrace::create();
+#endif
+}
+
+SystemError::SystemError(const string &w_, int e):
+       Exception(build_what(w_, e)),
+       err(e)
+{ }
+
+string SystemError::build_what(const string &w, int e)
+{
+       ostringstream buf;
+       buf<<w<<": ";
+#ifdef WIN32
+       buf<<e;
+#else
+       buf<<strerror(e);
+#endif
+       return buf.str();
+}
+
+} // namespace Msp
index a8ad2939daa72bb5021719fa1da126a0b151efba..1f9662e274b1d9b087d9cb16e5c1cf30f8c6811b 100644 (file)
@@ -1,16 +1,57 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_ERRORS_H_
-#define MSP_FRAMEWORK_ERRORS_H_
+#ifndef MSP_CORE_ERROR_H_
+#define MSP_CORE_ERROR_H_
 
-#include <msp/error.h>
+#include <exception>
+#include <string>
+#include "backtrace.h"
 
 namespace Msp {
 
-class UsageError: public Msp::Exception
+/**
+Base class for all Msp exceptions.
+*/
+class Exception: public std::exception
+{
+public:
+       Exception(const std::string &);
+       ~Exception() throw() { }
+
+       const char *what() const throw() { return w.c_str(); }
+       const Backtrace &get_backtrace() const throw() { return bt; }
+private:
+       std::string w;
+       Backtrace bt;
+
+};
+
+/**
+Thrown when a function parameter has an invalid value.
+*/
+class InvalidParameterValue: public Exception
+{
+public:
+       InvalidParameterValue(const std::string &w_): Exception(w_) { }
+};
+
+/**
+Thrown when the current object state doesn't allow the requested action.
+*/
+class InvalidState: public Exception
+{
+public:
+       InvalidState(const std::string &w_): Exception(w_) { }
+};
+
+/**
+Thrown when the application is invoked with wrong parameters.
+*/
+class UsageError: public Exception
 {
 public:
        UsageError(const std::string &r, bool b=true): Exception(r), brief(b) { }
@@ -19,6 +60,20 @@ private:
        bool brief;
 };
 
+/**
+Thrown when a system call fails.
+*/
+class SystemError: public Exception
+{
+public:
+       SystemError(const std::string &, int);
+       int get_error_code() const { return err; }
+private:
+       int err;
+
+       static std::string build_what(const std::string &, int);
+};
+
 } // namespace Msp
 
 #endif
diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp
new file mode 100644 (file)
index 0000000..67c4d41
--- /dev/null
@@ -0,0 +1,214 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include "getopt.h"
+
+using namespace std;
+
+namespace Msp {
+
+/**
+Generates a single line that gives an overview about the known options.
+
+@param   argv0  The program name to be used in the usage string
+
+@return  The generated usage string
+*/
+string GetOpt::generate_usage(const string &argv0) const
+{
+       ostringstream line;
+       
+       line<<argv0;
+       for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
+       {
+               line<<" [";
+               if((*i)->get_short())
+               {
+                       line<<'-'<<(*i)->get_short();
+                       if(!(*i)->get_long().empty())
+                               line<<'|';
+                       else if((*i)->get_arg_type()==OPTIONAL_ARG)
+                               line<<"[ARG]";
+                       else if((*i)->get_arg_type()==REQUIRED_ARG)
+                               line<<" ARG";
+               }
+               if(!(*i)->get_long().empty())
+               {
+                       line<<"--"<<(*i)->get_long();
+
+                       if((*i)->get_arg_type()==OPTIONAL_ARG)
+                               line<<"[=ARG]";
+                       else if((*i)->get_arg_type()==REQUIRED_ARG)
+                               line<<"=ARG";
+               }
+               line<<']';
+       }
+
+       return line.str();
+}
+
+/**
+Generates help for known options in tabular format, one option per line.
+The returned string will have a linefeed at the end.
+*/
+string GetOpt::generate_help() const
+{
+       string result;
+       for(list<OptBase *>::const_iterator i=opts.begin(); i!=opts.end(); ++i)
+       {
+               ostringstream line;
+               line<<"  ";
+               if((*i)->get_short())
+               {
+                       line<<'-'<<(*i)->get_short();
+                       if(!(*i)->get_long().empty())
+                               line<<", ";
+                       else if((*i)->get_arg_type()==OPTIONAL_ARG)
+                               line<<"[ARG]";
+                       else if((*i)->get_arg_type()==REQUIRED_ARG)
+                               line<<" ARG";
+               }
+               if(!(*i)->get_long().empty())
+               {
+                       line<<"--"<<(*i)->get_long();
+
+                       if((*i)->get_arg_type()==OPTIONAL_ARG)
+                               line<<"[=ARG]";
+                       else if((*i)->get_arg_type()==REQUIRED_ARG)
+                               line<<"=ARG";
+               }
+
+               line<<"  "<<(*i)->get_help()<<'\n';
+
+               result+=line.str();
+       }
+       
+       return result;
+}
+
+void GetOpt::operator()(unsigned argc, const char *const *argv)
+{
+       unsigned i=1;
+       for(; i<argc;)
+       {
+               if(argv[i][0]=='-')
+               {
+                       if(argv[i][1]=='-')
+                       {
+                               if(!argv[i][2])
+                                       break;
+
+                               i+=process_long(argv+i);
+                       }
+                       else
+                               i+=process_short(argv+i);
+               }
+               else
+                       args.push_back(argv[i++]);
+       }
+       
+       for(; i<argc; ++i)
+               args.push_back(argv[i]);
+}
+
+GetOpt::~GetOpt()
+{
+       for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
+               delete *i;
+}
+
+GetOpt::OptBase &GetOpt::get_option(char s)
+{
+       for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
+               if((*i)->get_short()==s)
+                       return **i;
+       throw UsageError(string("Unknown option -")+s);
+}
+
+GetOpt::OptBase &GetOpt::get_option(const string &l)
+{
+       for(list<OptBase *>::iterator i=opts.begin(); i!=opts.end(); ++i)
+               if((*i)->get_long()==l)
+                       return **i;
+       throw UsageError(string("Unknown option --")+l);
+}
+
+/**
+Processes the given argument as a long option.
+
+@param   argp  Pointer to the argument
+
+@return  The number of arguments eaten (1 or 2)
+*/
+unsigned GetOpt::process_long(const char *const *argp)
+{
+       // Skip the --
+       const char *arg=argp[0]+2;
+
+       // See if the argument contains an =
+       unsigned equals=0;
+       for(; arg[equals] && arg[equals]!='='; ++equals);
+       
+       OptBase &opt=get_option(string(arg, equals));
+       
+       if(arg[equals])
+               // Process the part after the = as option argument
+               opt.process(arg+equals+1);
+       else if(opt.get_arg_type()==REQUIRED_ARG)
+       {
+               if(!argp[1])
+                       throw UsageError("Premature end of arguments");
+
+               // Process the next argument as option argument
+               opt.process(argp[1]);
+               return 2;
+       }
+       else
+               opt.process();
+       
+       return 1;
+}
+
+/**
+Processes short options from the given argument.
+
+@param   argp  Pointer to the argument
+
+@return  The number of arguments eaten (1 or 2)
+*/
+unsigned GetOpt::process_short(const char *const *argp)
+{
+       // Skip the -
+       const char *arg=argp[0]+1;
+
+       // Loop through all characters in the argument
+       for(; *arg; ++arg)
+       {
+               OptBase &opt=get_option(*arg);
+
+               if(arg[1] && opt.get_arg_type()!=NO_ARG)
+               {
+                       // Need an option argument and we have characters left - use them
+                       opt.process(arg+1);
+                       return 1;
+               }
+               else if(opt.get_arg_type()==REQUIRED_ARG)
+               {
+                       if(!argp[1])
+                               throw UsageError("Premature end of arguments");
+                       
+                       // Use the next argument as option argument
+                       opt.process(argp[1]);
+                       return 2;
+               }
+               else
+                       opt.process();
+       }
+
+       return 1;
+}
+
+} // namespace Msp
diff --git a/source/core/getopt.h b/source/core/getopt.h
new file mode 100644 (file)
index 0000000..2824a0b
--- /dev/null
@@ -0,0 +1,144 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#ifndef MSP_CORE_GETOPT_H_
+#define MSP_CORE_GETOPT_H_
+
+#include <list>
+#include <sstream>
+#include <string>
+#include "error.h"
+
+namespace Msp {
+
+class GetOpt
+{
+public:
+       enum ArgType
+       {
+               NO_ARG,
+               OPTIONAL_ARG,
+               REQUIRED_ARG
+       };
+       
+       class OptBase
+       {
+       public:
+               OptBase           &set_help(const std::string &h) { help=h; return *this; }
+               char              get_short() const               { return shrt; }
+               const std::string &get_long() const               { return lng; }
+               ArgType           get_arg_type() const            { return arg_type; }
+               const std::string &get_help() const               { return help; }
+               unsigned          get_seen_count() const          { return seen_count; }
+               virtual void      process()=0;
+               virtual void      process(const std::string &)=0;
+               virtual ~OptBase() { }
+       protected:
+               char        shrt;
+               std::string lng;
+               ArgType     arg_type;
+               unsigned    seen_count;
+               std::string help;
+
+               OptBase(char s, const std::string &l, ArgType a): shrt(s), lng(l), arg_type(a), seen_count(0) { }
+       };
+
+       const std::list<std::string> &get_args() const { return args; }
+
+       template<typename T>
+       OptBase &add_option(char s, const std::string &l, T &d, ArgType a=NO_ARG)
+       { opts.push_back(new Option<T>(s, l, d, a)); return *opts.back(); }
+       
+       template<typename T>
+       OptBase &add_option(char s, const std::string &l, std::list<T> &d, ArgType a=REQUIRED_ARG)
+       { opts.push_back(new ListOption<std::list<T> >(s, l, d, a)); return *opts.back(); }
+       
+       template<typename T>
+       OptBase &add_option(const std::string &l, T &d, ArgType a)
+       { return add_option(0, l, d, a); }
+
+       std::string generate_usage(const std::string &) const;
+       std::string generate_help() const;
+       void operator()(unsigned, const char *const *);
+
+       ~GetOpt();
+private:
+       template<typename T>
+       class Option: public OptBase
+       {
+       public:
+               Option(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) { }
+
+               virtual void process()
+               {
+                       if(arg_type==REQUIRED_ARG)
+                               throw UsageError("--"+lng+" requires an argument");
+                       process_();
+                       ++seen_count;
+               }
+
+               virtual void process(const std::string &a)
+               {
+                       if(arg_type==NO_ARG)
+                               throw UsageError("--"+lng+" takes no argument");
+
+                       T tmp;
+                       std::istringstream ss(a);
+                       ss>>tmp;
+                       if(ss.fail())
+                               throw UsageError("Invalid argument for --"+lng);
+
+                       data=tmp;
+                       ++seen_count;
+               }
+       private:
+               T &data;
+
+               void process_() { }
+       };
+
+       template<typename T>
+       class ListOption: public OptBase
+       {
+       public:
+               ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d)
+               { if(arg_type!=REQUIRED_ARG) throw Exception("ListOption with arg_type!=REQUIRED makes no sense"); }
+
+               virtual void process()
+               {
+                       throw UsageError("--"+lng+" requires an argument");
+               }
+
+               virtual void process(const std::string &a)
+               {
+                       typename T::value_type tmp;
+                       std::istringstream ss(a);
+                       ss>>tmp;
+                       if(ss.fail())
+                               throw UsageError("Invalid argument for --"+lng);
+
+                       data.push_back(tmp);
+                       ++seen_count;
+               }
+       private:
+               T &data;
+       };
+
+       std::list<OptBase *>   opts;
+       std::list<std::string> args;
+
+       OptBase &get_option(char);
+       OptBase &get_option(const std::string &);
+       unsigned process_long(const char *const *);
+       unsigned process_short(const char *const *);
+};
+
+template<> inline void GetOpt::Option<bool>::process_()     { data=true; }
+template<> inline void GetOpt::Option<unsigned>::process_() { ++data; }
+
+} // namespace Msp
+
+#endif
index de62f75821bf11e0735b6a2d7f2264703d888782..9fdaba297c7ed8ef7c74b5e22e5d1c9eb289669c 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
@@ -10,10 +11,10 @@ Distributed under the LGPL
 #include "application.h"
 
 #ifdef WIN32
-int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+int APIENTRY WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
 { 
        int argc        = 0;
-       LPWSTR *argv    = CommandLineToArgvW(GetCommandLineW(), &argc);
+       LPWSTR *argv=CommandLineToArgvW(GetCommandLineW(), &argc);
        return Msp::Application::run(argc, (char **)argv);
 }
 #endif
index 146b982806671fba20912a88f33af04d93c65b90..8088a2839dbd21a15b8567f3768e850d5c5bb583 100644 (file)
@@ -1,12 +1,13 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_MUTEX_H_
-#define MSP_FRAMEWORK_MUTEX_H_
+#ifndef MSP_CORE_MUTEX_H_
+#define MSP_CORE_MUTEX_H_
 
-#include <msp/refcount.h>
+#include "refptr.h"
 #include "types.h"
 
 namespace Msp {
@@ -33,11 +34,16 @@ private:
        friend class Semaphore;
 };
 
+/**
+Locks the mutex for te lifetime of the object.
+*/
 class MutexLock
 {
 public:
-       MutexLock(Mutex &m): mutex(m) { mutex.lock(); }
-       ~MutexLock()                  { mutex.unlock(); }
+       MutexLock(Mutex &m, bool l=true): mutex(m) { if(l) mutex.lock(); }
+       ~MutexLock() { mutex.unlock(); }
+
+       int lock() { return mutex.lock(); }
 private:
        Mutex &mutex;
 
@@ -45,8 +51,25 @@ private:
        MutexLock &operator=(const MutexLock &);
 };
 
-
+/**
+Protects a pointer with a mutex.  As long as the MutexPtr (or a copy of it)
+exists, the mutex will stay locked.
+*/
 template<typename T>
+class MutexPtr
+{
+public:
+       MutexPtr(T *d, Mutex &m): mutex(new MutexLock(m)), data(d) { }
+
+       T &operator*() const { return *data; }
+       T *operator->() const { return data; }
+       void clear() { mutex=0; data=0; }
+private:
+       RefPtr<MutexLock> mutex;
+       T *data;
+};
+
+/*template<typename T>
 class MutexPtr: public RefCount
 {
 public:
@@ -69,7 +92,7 @@ protected:
                }
                return true;
        }
-};
+};*/
 
 }
 
diff --git a/source/core/refptr.h b/source/core/refptr.h
new file mode 100644 (file)
index 0000000..ee020e0
--- /dev/null
@@ -0,0 +1,66 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#ifndef MSP_CORE_REFPTR_H_
+#define MSP_CORE_REFPTR_H_
+
+namespace Msp {
+
+template<typename T>
+class RefPtr
+{
+public:
+       RefPtr(): data(0), count(0) { }
+       RefPtr(T *d): data(d), count(0) { if(data) count=new unsigned(1); }
+       RefPtr(const RefPtr &p): data(p.data), count(p.count) { incref(); }
+       ~RefPtr() { decref(); }
+
+       RefPtr &operator=(const RefPtr &p)
+       {
+               decref();
+               data=p.data;
+               count=p.count;
+               incref();
+               return *this;
+       }
+
+       T *get() const        { return data; }
+       T &operator*() const  { return *data; }
+       T *operator->() const { return data; }
+       operator bool() const { return data!=0; }
+
+       template<typename U>
+       static RefPtr<T> cast_dynamic(const RefPtr<U> &p)  { return RefPtr<T>(dynamic_cast<T *>(p.get()), p.count); }
+       template<typename U> friend class RefPtr;
+private:
+       T        *data;
+       unsigned *count;
+
+       RefPtr(T *d, unsigned *c): data(d), count(c) { incref(); }
+
+       void  incref()
+       {
+               if(!count) return;
+               ++*count;
+       }
+
+       void  decref()
+       {
+               if(!count) return;
+               --*count;
+               if(!*count)
+               {
+                       delete data;
+                       delete count;
+                       data=0;
+                       count=0;
+               }
+       }
+};
+
+} // namespace Msp
+
+#endif
index 9107a763aa0416e111d47390ffecda7cc0163c77..b9e7080cb04ea2b6e4808de5de658f1400322708 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
@@ -12,6 +13,63 @@ Distributed under the LGPL
 
 namespace Msp {
 
+Semaphore::Semaphore():
+       mutex(new Mutex),
+       own_mutex(true)
+{
+       init();
+}
+
+Semaphore::Semaphore(Mutex &m):
+       mutex(&m),
+       own_mutex(false)
+{
+       init();
+}
+
+#ifdef WIN32
+int Semaphore::signal()
+{
+       if(count==0) 
+               return 0;
+
+       int ret=!ReleaseSemaphore(sem, 1, 0); 
+
+       unsigned old_count=count;
+       mutex->unlock();
+       while(count==old_count)
+               Sleep(0);
+       mutex->lock();
+
+       return ret;
+}
+
+int Semaphore::broadcast()
+{
+       if(count==0)
+               return 0;
+       int ret=!ReleaseSemaphore(sem, count, 0);
+
+       mutex->unlock();
+       while(count)
+               Sleep(0);
+       mutex->lock();
+
+       return ret;
+}
+
+int Semaphore::wait()
+{ 
+       ++count; 
+       mutex->unlock();
+       DWORD ret=WaitForSingleObject(sem, INFINITE); 
+       mutex->lock();
+       --count;
+       
+       return ret==WAIT_OBJECT_0;
+}
+#endif
+
 int Semaphore::wait(const Time::TimeDelta &d)
 {
 #ifndef WIN32
@@ -21,15 +79,40 @@ int Semaphore::wait(const Time::TimeDelta &d)
        timeout.tv_sec=ts.raw()/1000000;
        timeout.tv_nsec=(ts.raw()%1000000)*1000;
 
-       MutexLock l(mutex);
-       int r=pthread_cond_timedwait(&sem, &mutex.mutex, &timeout);
+       int r=pthread_cond_timedwait(&sem, &mutex->mutex, &timeout);
        if(r==ETIMEDOUT)
                return 1;
        else if(r)
                return -1;
        return 0;
 #else
-       return WaitForSingleObject(sem, (DWORD)(d/Time::usec))==WAIT_OBJECT_0;
+       ++count;
+       mutex->lock();
+       DWORD ret=WaitForSingleObject(sem, (DWORD)(d/Time::usec));
+       mutex->unlock();
+       --count;
+       return ret==WAIT_OBJECT_0;
+#endif
+}
+
+Semaphore::~Semaphore()
+{
+       if(own_mutex)
+               delete mutex;
+#ifdef WIN32
+       CloseHandle(sem);
+#else
+       pthread_cond_destroy(&sem);
+#endif
+}
+
+void Semaphore::init()
+{
+#ifdef WIN32
+       count=0;
+       sem=CreateSemaphore(0, 0, 32, 0);
+#else
+       pthread_cond_init(&sem, 0);
 #endif
 }
 
index 1cf3cd6ad11b44402eacca11d415d9df60941916..c55553a6f31d9ffd02b23040621ebb87337feff0 100644 (file)
@@ -1,10 +1,11 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_SEMAPHORE_H_
-#define MSP_FRAMEWORK_SEMAPHORE_H_
+#ifndef MSP_CORE_SEMAPHORE_H_
+#define MSP_CORE_SEMAPHORE_H_
 
 #include "mutex.h"
 #include "types.h"
@@ -15,28 +16,36 @@ namespace Msp {
 class Semaphore
 {
 public:
-#ifndef WIN32
-       Semaphore()        { pthread_cond_init(&sem, 0); }
-       int   signal()     { MutexLock l(mutex); return pthread_cond_signal(&sem); }
-       int   broadcast()  { MutexLock l(mutex); return pthread_cond_broadcast(&sem); }
-       int   wait()       { MutexLock l(mutex); return pthread_cond_wait(&sem, &mutex.mutex); }
+       Semaphore();
+       Semaphore(Mutex &);
+       int   signal();
+       int   broadcast();
+       int   wait();
        int   wait(const Time::TimeDelta &);
-       ~Semaphore()       { pthread_cond_destroy(&sem); }
-#else
-       Semaphore()        { sem=CreateSemaphore(0, 0, 32, 0); }
-       int   signal()     { return !ReleaseSemaphore(sem, 1, 0); }
-       int   broadcast()  { return !ReleaseSemaphore(sem, 32, 0); }
-       int   wait()       { return WaitForSingleObject(sem, INFINITE)==WAIT_OBJECT_0; }
-       int   wait(const Time::TimeDelta &);
-       ~Semaphore()       { CloseHandle(sem); }
-#endif
+       Mutex &get_mutex() { return *mutex; }
+       ~Semaphore();
 private:
-#ifndef WIN32
-       Mutex mutex;
-#endif
+       Mutex *mutex;
+       bool  own_mutex;
        SemaphoreHandle sem;
+#ifdef WIN32
+       unsigned count;
+#endif
+
+       void init();
 };
 
+#ifndef WIN32
+inline int Semaphore::signal()
+{ return pthread_cond_signal(&sem); }
+
+inline int Semaphore::broadcast()
+{ return pthread_cond_broadcast(&sem); }
+
+inline int Semaphore::wait()
+{ return pthread_cond_wait(&sem, &mutex->mutex); }
+#endif
+
 }
 
 #endif
index c7981cc4bcff9e24110d241768bf8e790d1c18a8..8e1134b80fa2e68ade849c5bff6033af3b6a2c25 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
index 937d161938b20aad593653bbe99ed882aeb77156..60a2e83e7154096524c2583e7eccfe57f8cc5c30 100644 (file)
@@ -1,10 +1,11 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_THREAD_H_
-#define MSP_FRAMEWORK_THREAD_H_
+#ifndef MSP_CORE_THREAD_H_
+#define MSP_CORE_THREAD_H_
 
 #include "types.h"
 
@@ -36,13 +37,13 @@ private:
        Thread(const Thread &);
        Thread &operator=(const Thread &);
 
+       static
 #ifdef WIN32
-#      define THREAD_RETURN_ DWORD WINAPI
+       DWORD WINAPI
 #else
-#      define THREAD_RETURN_ void *
+       void *
 #endif
-       static THREAD_RETURN_ main_(void *t) { ((Thread *)t)->main(); return 0; }
-#undef THREAD_RETURN_
+       main_(void *t) { ((Thread *)t)->main(); return 0; }
 };
 
 } // namespace Msp
index 885c5231b81fde3e363a93af16f3b67940fcf8f1..0dace5ace4daa5fd52826a5e0bf5c7a43f1fd395 100644 (file)
@@ -1,10 +1,11 @@
-/*
+/* $Id$
+
 This file is part of libmspcore
 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
-#ifndef MSP_FRAMEWORK_TYPES_H_
-#define MSP_FRAMEWORK_TYPES_H_
+#ifndef MSP_CORE_TYPES_H_
+#define MSP_CORE_TYPES_H_
 
 #ifdef WIN32
 #include <windows.h>
diff --git a/source/debug/backtrace.cpp b/source/debug/backtrace.cpp
new file mode 100644 (file)
index 0000000..2078996
--- /dev/null
@@ -0,0 +1,45 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <execinfo.h>
+#include "backtrace.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Debug {
+
+Backtrace Backtrace::create()
+{
+#ifndef WIN32
+       void *addresses[50];
+       int count=::backtrace(addresses, 50);
+
+       char **symbols=backtrace_symbols(addresses, count);
+
+       Backtrace bt;
+       for(int i=0; i<count; ++i)
+               bt.frames.push_back(StackFrame(addresses[i], symbols[i]));
+
+       free(symbols);
+
+       return bt;
+#else
+       return Backtrace();
+#endif
+}
+
+ostream &operator<<(ostream &out, const Backtrace &bt)
+{
+       const Backtrace::FrameSeq &frames=bt.get_frames();
+       for(Backtrace::FrameSeq::const_iterator i=frames.begin(); i!=frames.end(); ++i)
+               out<<i->address<<" in "<<i->symbol<<'\n';
+
+       return out;
+}
+
+} // namespace Debug
+} // namespace Msp
diff --git a/source/debug/backtrace.h b/source/debug/backtrace.h
new file mode 100644 (file)
index 0000000..c570ce5
--- /dev/null
@@ -0,0 +1,41 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#ifndef MSP_DEBUG_BACKTRACE_H_
+#define MSP_DEBUG_BACKTRACE_H_
+
+#include <list>
+#include <ostream>
+#include <string>
+
+namespace Msp {
+namespace Debug {
+
+class Backtrace
+{
+public:
+       struct StackFrame
+       {
+               void *address;
+               std::string symbol;
+
+               StackFrame(void *a, const std::string &s): address(a), symbol(s) { }
+       };
+       typedef std::list<StackFrame> FrameSeq;
+
+       const FrameSeq &get_frames() const { return frames; }
+
+       static Backtrace create();
+private:
+       FrameSeq frames;
+};
+
+std::ostream &operator<<(std::ostream &, const Backtrace &);
+
+} // namespace Debug
+} // namespace Msp
+
+#endif
diff --git a/source/debug/demangle.cpp b/source/debug/demangle.cpp
new file mode 100644 (file)
index 0000000..58e05ce
--- /dev/null
@@ -0,0 +1,50 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include "demangle.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Debug {
+
+string demangle_gcc3(const string &sym)
+{
+       string result;
+
+       if(sym.compare(0, 2, "_Z"))
+               return result;
+
+       string::const_iterator i=sym.begin()+2;
+
+       bool nested=(*i=='N');
+       bool first=true;
+       while(first || (nested && *i!='E'))
+       {
+               unsigned len=0;
+               for(; isdigit(*i); ++i)
+                       len=len*10+(*i-'0');
+               string::const_iterator j=i+len;
+
+               if(!first)
+                       result.append("::");
+               result.append(i, j);
+
+               first=false;
+       }
+
+       if(nested)
+               ++i;
+
+       for(; i!=sym.end(); ++i)
+       {
+               bool ref=(*i=='R');
+               if(ref) ++i;
+       }
+}
+
+} // namespace Debug
+} // namespace Msp
diff --git a/source/debug/demangle.h b/source/debug/demangle.h
new file mode 100644 (file)
index 0000000..f8cab96
--- /dev/null
@@ -0,0 +1,20 @@
+/* $Id$
+
+This file is part of libmspcore
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#ifndef MSP_DEBUG_DEMANGLE_H_
+#define MSP_DEBUG_DEMANGLE_H_
+
+#include <string>
+
+namespace Msp {
+namespace Debug {
+
+std::string demangle_gcc3(const std::string &);
+
+} // namespace Debug
+} // namespace Msp
+
+#endif
index 4fcec9641f4bf23a2ac25c4c17c5f23c24bd7bd9..d74fc6fbd0be4aef046626224e305830b4450a4e 100644 (file)
@@ -1,7 +1,7 @@
 /* $Id$ */
 #include <sstream>
 #include <iomanip>
-#include <msp/error.h>
+#include "../core/error.h"
 #include "datetime.h"
 #include "timestamp.h"
 
@@ -40,9 +40,6 @@ inline int cmp_(T a, T b)
 
 }
 
-#include <iostream>
-using namespace std;
-
 namespace Msp {
 namespace Time {
 
@@ -68,12 +65,32 @@ DateTime::DateTime(int32_t y, uint8_t m, uint8_t d):
        usec(0)
 { }
 
+DateTime::DateTime(int32_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t n, uint8_t s):
+       year(y),
+       month(m),
+       mday(d),
+       hour(h),
+       minute(n),
+       second(s),
+       usec(0)
+{ }
+
+DateTime::DateTime(int32_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t n, uint8_t s, uint32_t u):
+       year(y),
+       month(m),
+       mday(d),
+       hour(h),
+       minute(n),
+       second(s),
+       usec(u)
+{ }
+
 void DateTime::add_days(int32_t days)
 {
        unsigned new_year=year;
 
        /* Leap years have a 400 year cycle, so any 400 consecutive years have a
-       constant number of days */
+       constant number of days (400*365+97=146097) */
        new_year+=days/146097*400;
        days%=146097;
 
index f7b037ea7d154dac0e7b931106fbd2932a1dbbba..7d3d4bb6d2a2ff706ca898582bc241fb72e1a7e2 100644 (file)
@@ -14,7 +14,7 @@ namespace {
 
 void print_part(ostream &out, int64_t &value, int64_t unit, char sep, bool &first)
 {
-       if(!value || (value<unit && first))
+       if(value<unit && first)
                return;
        
        if(!first)
index 2d4649883088187fffca7994bcb6bcfc2f590397..6ebfcd86afc8b5c042f64b998623251d470aa628 100644 (file)
@@ -51,16 +51,16 @@ public:
        TimeDelta &operator-=(const TimeDelta &t)      { usec-=t.usec; return *this; }
 
        template<typename T>
-       TimeDelta operator*(T a) const                 { return TimeDelta((int64_t)(usec*a)); }
+       TimeDelta operator*(T a) const                 { return TimeDelta(int64_t(usec*a)); }
        template<typename T>
-       TimeDelta &operator*=(T a)                     { usec=(int64_t)(usec*a); return *this; }
+       TimeDelta &operator*=(T a)                     { usec=int64_t(usec*a); return *this; }
 
        template<typename T>
-       TimeDelta operator/(T a) const                 { return TimeDelta((int64_t)(usec/a)); }
+       TimeDelta operator/(T a) const                 { return TimeDelta(int64_t(usec/a)); }
        template<typename T>
-       TimeDelta &operator/=(T a)                     { usec=(int64_t)(usec/a); return *this; }
+       TimeDelta &operator/=(T a)                     { usec=int64_t(usec/a); return *this; }
 
-       double    operator/(const TimeDelta &t) const  { return (double)usec/t.usec; }
+       double    operator/(const TimeDelta &t) const  { return double(usec)/t.usec; }
 
        bool      operator>(const TimeDelta &t) const  { return usec>t.usec; }
        bool      operator>=(const TimeDelta &t) const { return usec>=t.usec; }
index ad0d24550338f7c22117057a2354d42f93e6c09e..f4a5379d44fb0418414d479f800b17d9b97916fc 100644 (file)
@@ -44,12 +44,12 @@ TimeStamp now()
 
                FILETIME ft;
                SystemTimeToFileTime(&st, &ft);
-               epoch=(ft.dwLowDateTime+(int64_t)ft.dwHighDateTime<<32)/10;
+               epoch=(ft.dwLowDateTime+((int64_t)ft.dwHighDateTime<<32))/10;
        }
        
        FILETIME ft;
        GetSystemTimeAsFileTime(&ft);
-       return TimeStamp((ft.dwLowDateTime+(int64_t)ft.dwHighDateTime<<32)/10-epoch);
+       return TimeStamp((ft.dwLowDateTime+((int64_t)ft.dwHighDateTime<<32))/10-epoch);
 #endif
 }
 
index bc04bad8a35e14c88adfbd201ca430eb9b57229a..59fe0c2c0ca1cab816c78f91b28baaeaba6623b0 100644 (file)
@@ -6,6 +6,8 @@ Distributed under the LGPL
 #ifndef MSP_TIME_UTILS_H_
 #define MSP_TIME_UTILS_H_
 
+#include <string>
+
 namespace Msp {
 namespace Time {