-/*
-This file is part of libmspframework
+/* $Id$
+
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
+
#include <signal.h>
#include <iostream>
+#include <typeinfo>
+#include "../debug/backtrace.h"
+#include "../debug/demangle.h"
+#include "../time/units.h"
+#include "../time/utils.h"
#include "application.h"
-#include "error.h"
+#include "except.h"
using namespace std;
namespace Msp {
-Poller::Slot &Application::add_pollable(Pollable *obj, short events)
-{
- if(!poller_)
- poller_=new Poller;
-
- Poller::Slot &slot=poller_->add_pollable(obj, events);
- // Interrupt a possible poll in progress
-#ifndef WIN32 //XXX
- pthread_kill(main_tid, SIGALRM);
-#endif
- return slot;
-}
-
-EventManager::Event &Application::create_event()
-{
- if(!ev_mgr_)
- ev_mgr_=new EventManager(*this);
-
- return ev_mgr_->create_event();
-}
-
-Application::~Application()
-{
- if(poller_)
- delete poller_;
- if(ev_mgr_)
- delete ev_mgr_;
-}
+Application::Application():
+ exit_code(0),
+ loop_mode_(TICK_SLEEP)
+{ }
/**
Constructs an instance of the registered application class and runs it. If the
This function can only be called once. The global main() function provided by
the library normally does it automatically at program startup.
*/
-int Application::run(int argc, char **argv)
+int Application::run(int argc, char **argv, void *data)
{
static bool called=false;
if(called)
return 126;
}
-#ifndef WIN32 //XXX
- signal(SIGALRM, &sigalrm_);
-#endif
-
+ data_=data;
+
try
{
- app_=reg_app_->create_app(argc, argv);
+ try
+ {
+ app_=reg_app_->create_app(argc, argv);
+ }
+ catch(const UsageError &e)
+ {
+ reg_app_->usage(e.what(), argv[0], e.get_brief());
+ return 1;
+ }
+
+ int result=app_->main();
+ delete app_;
+ return result;
}
- catch(const UsageError &e)
+ catch(const exception &e)
{
- reg_app_->usage(argv[0], e.get_brief());
- return 1;
- }
+ delete app_;
+
+#ifdef WIN32
+ string msg=Debug::demangle(typeid(e).name())+":\n"+e.what();
+ MessageBoxA(0, msg.c_str(), "Uncaught exception", MB_OK|MB_ICONERROR);
+#else
+ cerr<<"An uncaught exception occurred.\n";
+ cerr<<" type: "<<Debug::demangle(typeid(e).name())<<'\n';
+ cerr<<" what(): "<<e.what()<<'\n';
+
+ const Exception *exc=dynamic_cast<const Exception *>(&e);
+ if(exc && !exc->get_backtrace().get_frames().empty())
+ {
+ cerr<<" backtrace:\n";
+ const list<Debug::Backtrace::StackFrame> &frames=exc->get_backtrace().get_frames();
+ for(list<Debug::Backtrace::StackFrame>::const_iterator i=frames.begin(); i!=frames.end(); ++i)
+ cerr<<" "<<*i<<'\n';
+ }
+#endif
- int result=app_->main();
- delete app_;
- return result;
+ return 124;
+ }
}
/**
Prints a message describing the usage of the application. The default version
will blame the programmer for being lazy.
-@param argv0 The value of argv[0], to be used in the message
-@param brief Whether to print a brief or long usage message
+@param reason Why the function was called
+@param argv0 The value of argv[0], to be used in the message
+@param brief Whether to print a brief or long usage message
*/
-void Application::usage(const char *, bool)
+void Application::usage(const char *reason, const char *, bool)
{
+ if(reason)
+ cerr<<"UsageError: "<<reason<<'\n';
cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
}
-Application::Application():
- exit_code(0),
- tick_mode_(IDLE),
- poller_(0),
- ev_mgr_(0)
-#ifndef WIN32
- //XXX Figure out how to get the current thread on win32
- ,main_tid(pthread_self())
-#endif
-{ }
-
/**
-Default main loop. Calls tick() periodically if do_ticks is true, otherwise
-just sleeps. A custom main loop should monitor the done member variable and
-return exit_code.
+Default main loop. Behavior depends on loop_mode_. A custom main loop should
+monitor the done member variable and return exit_code.
*/
int Application::main()
{
+ if(loop_mode_==NONE)
+ return 0;
+
done=false;
while(!done)
{
- if(tick_mode_==IDLE)
+ if(loop_mode_==SLEEP)
+ {
+ sleep_sem_.wait();
+ if(!done)
+ tick();
+ }
+ else if(loop_mode_==TICK_SLEEP)
{
- if(poller_)
- poller_->poll(0);
tick();
-#ifdef WIN32
- Sleep(0);
-#else
- //sched_yield();
- timespec ts={0,1000000};
- nanosleep(&ts, 0);
-#endif
+ Time::sleep(Time::msec);
}
- else
+ else if(loop_mode_==TICK_YIELD)
{
- if(poller_)
- poller_->poll(-1);
- else
- {
+ tick();
#ifdef WIN32
- Sleep(1);
+ Sleep(0);
#else
- timespec ts={1000,0};
- nanosleep(&ts, 0);
+ sched_yield();
#endif
- }
- if(tick_mode_!=NONE)
- tick();
}
+ else if(loop_mode_==TICK_BUSY)
+ tick();
}
return exit_code;
signal(s, &sighandler_);
}
-void Application::set_tick_mode(TickMode t)
+/**
+Changes the main loop mode.
+*/
+void Application::set_loop_mode(LoopMode l)
{
- tick_mode_=t;
-#ifndef WIN32 //XXX
- pthread_kill(main_tid, SIGALRM);
-#endif
+ LoopMode old_mode=loop_mode_;
+ loop_mode_=l;
+ if(old_mode==SLEEP)
+ sleep_sem_.signal();
+}
+
+/**
+Causes the tick() function to be executed once if loop mode is SLEEP. Has no
+effect with other loop modes.
+*/
+void Application::induce_tick()
+{
+ if(loop_mode_==SLEEP)
+ sleep_sem_.signal();
}
/**
{
done=true;
exit_code=c;
-#ifndef WIN32 //XXX
- pthread_kill(main_tid, SIGALRM);
-#endif
+ if(loop_mode_==SLEEP)
+ sleep_sem_.signal();
}
+/**
+Static wrapper function to call a member function of the Application instance.
+*/
void Application::sighandler_(int s)
{
app_->sighandler(s);
}
+
Application::RegBase::RegBase()
{
if(reg_app_)
Application *Application::app_=0;
Application::RegBase *Application::reg_app_=0;
+void *Application::data_=0;
} // namespace Msp