+++ /dev/null
-package="mspcore"
-version="0.1"
-description="Mikkosoft Productions core library"
-requires=("mspmisc","pthread","sigc++-2.0")
-tarballfile=("License.txt",)
+++ /dev/null
-type="library"
-target="mspcore"
-extradirs=("time",)
-installheaders="core"
-installtarget=1
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include <signal.h>
#include <iostream>
+#include "../time/units.h"
#include "application.h"
#include "error.h"
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_;
-}
-
/**
Constructs an instance of the registered application class and runs it. If the
application throws a UsageError, the static usage() function is called.
return 126;
}
-#ifndef WIN32 //XXX
- signal(SIGALRM, &sigalrm_);
-#endif
-
try
{
app_=reg_app_->create_app(argc, argv);
}
catch(const UsageError &e)
{
- reg_app_->usage(argv[0], e.get_brief());
+ reg_app_->usage(e.what(), argv[0], e.get_brief());
return 1;
}
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<<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
+ loop_mode_(TICK_SLEEP)
{ }
/**
-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
+ 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();
}
}
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);
/*
-This file is part of libmspframework
+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_
-#include "event.h"
-#include "poller.h"
-#include "types.h"
+#include "semaphore.h"
namespace Msp {
class Application
{
public:
- Poller::Slot &add_pollable(Pollable *, short);
- EventManager::Event &create_event();
- virtual ~Application();
+ virtual ~Application() { }
static int run(int, char **);
- static void usage(const char *, bool);
+ static void usage(const char *, const char *, bool);
protected:
- enum TickMode
+ enum LoopMode
{
- NONE, /// No ticks
- AFTER_POLL, /// One tick after each poll
- IDLE /// Constant torrent of ticks
+ NONE, /// No main loop - main() will just return
+ SLEEP, /// Only sleep in the main loop - useful for servers
+ 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:
virtual Application *create_app(int, char **)=0;
- virtual void usage(const char *, bool)=0;
+ virtual void usage(const char *, const char *, bool)=0;
virtual ~RegBase() { }
protected:
RegBase();
{
public:
Application *create_app(int argc, char **argv) { return new T(argc, argv); }
- void usage(const char *a, bool b) { T::usage(a,b); }
+ void usage(const char *r, const char *a, bool b) { T::usage(r, a, b); }
};
bool done;
Application();
virtual int main();
void catch_signal(int);
- void set_tick_mode(TickMode);
+ void set_loop_mode(LoopMode);
+ void induce_tick();
void exit(int);
virtual void tick() { }
virtual void sighandler(int) { }
private:
- TickMode tick_mode_;
- Poller *poller_;
- EventManager *ev_mgr_;
- ThreadHandle main_tid;
+ LoopMode loop_mode_;
+ Semaphore sleep_sem_;
Application(const Application &);
Application &operator=(const Application &);
- static RegBase *reg_app_;
+ static RegBase *reg_app_;
static Application *app_;
static void sighandler_(int);
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
class UsageError: public Msp::Exception
{
public:
- UsageError(bool b=true): Exception(""), brief(b) { }
+ UsageError(const std::string &r, bool b=true): Exception(r), brief(b) { }
bool get_brief() const { return brief; }
private:
bool brief;
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifdef WIN32
-#include <io.h>
-#include <fcntl.h>
-#endif
-
-#include "application.h"
-#include "event.h"
-
-using namespace std;
-
-namespace Msp {
-
-EventManager::EventManager(Application &a):
- app(a),
- next_id(1)
-{
- app.add_pollable(&pipe, POLLIN).signal_event.connect(sigc::mem_fun(this, &EventManager::data_available));
-}
-
-EventManager::Event &EventManager::create_event()
-{
- events.push_back(Event(*this, next_id++));
- return events.back();
-}
-
-void EventManager::data_available(short)
-{
- unsigned buf[1024];
- int len=pipe.read((char *)buf, sizeof(buf));
- for(unsigned i=0; i*sizeof(unsigned)<(unsigned)len; ++i)
- {
- for(list<Event>::iterator j=events.begin(); j!=events.end(); ++j)
- if(j->get_id()==buf[i])
- j->signal_triggered.emit();
- }
-}
-
-void EventManager::Event::trigger()
-{
- mgr.pipe.write((char *)&id, sizeof(id));
-}
-
-EventManager::Pipe::Pipe()
-{
-#ifdef WIN32
- _pipe(fd, 1024, _O_BINARY);
-#else
- ::pipe(fd);
-#endif
-}
-
-int EventManager::Pipe::write(char *buf, unsigned len)
-{
-#ifdef WIN32
- return _write(fd[1], buf, len);
-#else
- return ::write(fd[1], buf, len);
-#endif
-}
-
-int EventManager::Pipe::read(char *buf, unsigned len)
-{
-#ifdef WIN32
- return _read(fd[0], buf, len);
-#else
- return ::read(fd[0], buf, len);
-#endif
-}
-
-} // namespace Msp
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifndef MSP_FRAMEWORK_EVENT_H_
-#define MSP_FRAMEWORK_EVENT_H_
-
-#include <sigc++/sigc++.h>
-#include "pollable.h"
-
-namespace Msp {
-
-class Application;
-
-/**
-Events can be used in multi-threaded applictions to trigger actions in the main
-thread.
-*/
-class EventManager
-{
-public:
- class Event
- {
- public:
- sigc::signal<void> signal_triggered;
-
- Event(EventManager &m, unsigned i): mgr(m), id(i) { }
- unsigned get_id() const { return id; }
- void trigger();
- private:
- EventManager &mgr;
- unsigned id;
- };
-
- EventManager(Application &);
- Event &create_event();
-private:
- class Pipe: public Pollable
- {
- public:
- Pipe();
- int write(char *, unsigned);
- int read(char *, unsigned);
- private:
- int fd[2];
-
- int get_fd() { return fd[0]; }
- };
-
- Application &app;
- Pipe pipe;
- unsigned next_id;
- std::list<Event> events;
-
- void data_available(short);
-};
-
-} // namespace Msp
-
-#endif
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifdef WIN32
-#include <winsock2.h>
-#include "win32poll.h"
-#else
-#include <poll.h>
-#endif
-#include "pollable.h"
-
-namespace Msp {
-
-short Pollable::poll(short events, int timeout)
-{
-#ifdef WIN32
- return 0;
-#else
- pollfd pfd={get_fd(), events, 0};
- int result=::poll(&pfd, 1, timeout);
- if(result<=0)
- return result;
- return pfd.revents;
-#endif
-}
-
-}
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifndef MSP_FRAMEWORK_POLLABLE_H_
-#define MSP_FRAMEWORK_POLLABLE_H_
-
-#ifdef WIN32
-#include "win32poll.h"
-#endif
-
-#include <sigc++/sigc++.h>
-
-namespace Msp {
-
-class Pollable
-{
-public:
- sigc::signal<void> signal_deleted;
-
- virtual short poll(short, int =0);
- virtual ~Pollable() { signal_deleted.emit(); }
-protected:
- virtual int get_fd()=0;
-
- friend class Poller;
-};
-
-}
-
-#endif
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#include "pollable.h"
-#include "poller.h"
-
-using namespace std;
-
-namespace Msp {
-
-Poller::Slot &Poller::add_pollable(Pollable *obj, short events)
-{
- MutexLock sl(slots_mutex);
-
- slots.push_back(new Slot(obj, events));
- if(!pfd_mutex.trylock())
- {
- rebuild_pfd();
- pfd_mutex.unlock();
- }
- else
- dirty=true;
- return *slots.back();
-}
-
-int Poller::poll(int timeout)
-{
-#ifdef WIN32
- return 0;
-#else
- slots_mutex.lock();
- for(list<Slot *>::iterator i=slots.begin(); i!=slots.end();)
- {
- if((*i)->get_object())
- ++i;
- else
- {
- delete *i;
- i=slots.erase(i);
- dirty=true;
- }
- }
-
- pfd_mutex.lock();
- if(dirty)
- {
- rebuild_pfd();
- dirty=false;
- }
- slots_mutex.unlock();
-
- int result=::poll(&pfd[0], pfd.size(), timeout);
-
- if(result>0)
- {
- list<Slot *>::iterator j=slots.begin();
- for(vector<pollfd>::iterator i=pfd.begin(); i!=pfd.end(); ++i)
- {
- if(i->revents&POLLNVAL)
- dirty=true;
- else if(i->revents)
- {
- while(j!=slots.end() && (!(*j)->get_object() || (*j)->get_object()->get_fd()!=i->fd))
- ++j;
- if(j==slots.end())
- break;
- (*j)->signal_event.emit(i->revents);
- }
- }
- }
-
- pfd_mutex.unlock();
-
- return result;
-#endif
-}
-
-void Poller::rebuild_pfd()
-{
- pfd.clear();
- pfd.reserve(slots.size());
- for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
- {
- if(!(*i)->get_object() || (*i)->get_object()->get_fd()<0)
- continue;
-
- pfd.push_back(pollfd());
- pfd.back().fd=(*i)->get_object()->get_fd();
- pfd.back().events=(*i)->get_events();
- }
-}
-
-Poller::Slot::Slot(Pollable *o, short e):
- obj(o),
- events(e)
-{
- obj->signal_deleted.connect(sigc::mem_fun(this, &Slot::obj_deleted));
-}
-
-} // namespace Msp
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifndef MSP_FRAMEWORK_POLLER_H_
-#define MSP_FRAMEWORK_POLLER_H_
-
-#ifdef WIN32
-#include "win32poll.h"
-#else
-#include <sys/poll.h>
-#endif
-#include <vector>
-#include <sigc++/sigc++.h>
-#include "mutex.h"
-
-namespace Msp {
-
-class Pollable;
-
-class Poller
-{
-public:
- class Slot
- {
- public:
- sigc::signal<void, short> signal_event;
-
- Slot(Pollable *, short);
- Pollable *get_object() const { return obj; }
- short get_events() const { return events; }
- private:
- Pollable *obj;
- short events;
-
- void obj_deleted() { obj=0; }
- };
-
- Slot &add_pollable(Pollable *, short);
- int poll(int =0);
-private:
- std::list<Slot *> slots;
- std::vector<pollfd> pfd;
- Mutex slots_mutex;
- Mutex pfd_mutex;
- bool dirty;
-
- void remove_stale_slots();
- void rebuild_pfd();
- void pollable_deleted(Pollable *);
-};
-
-};
-
-#endif
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
+++ /dev/null
-/*
-This file is part of libmspframework
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#ifndef MSP_FRAMEWORK_WIN32POLL_H_
-#define MSP_FRAMEWORK_WIN32POLL_H_
-
-#ifdef WIN32
-// From Linux sys/poll.h
-struct pollfd
-{
- int fd; /* File descriptor to poll. */
- short int events; /* Types of events poller cares about. */
- short int revents; /* Types of events that actually occurred. */
-};
-
-#ifndef POLLIN
-// From Linux pth.h
-#define POLLIN 0x0001 /* any readable data available */
-#endif
-
-#ifndef POLLNVAL
-// From Linux pth.h
-#define POLLNVAL 0x0020 /* requested events "invalid" */
-#endif
-
-#endif // Win32
-#endif
+++ /dev/null
-installheaders="time"
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
/*
-This file is part of libmspframework
+This file is part of libmspcore
Copyright © 2006 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/