]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Add missing includes
[libs/core.git] / source / core / application.cpp
1 /* $Id$
2
3 This file is part of libmspcore
4 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <signal.h>
9 #include <iostream>
10 #include <typeinfo>
11 #include "../debug/backtrace.h"
12 #include "../debug/demangle.h"
13 #include "../time/units.h"
14 #include "../time/utils.h"
15 #include "application.h"
16 #include "except.h"
17
18 using namespace std;
19
20 namespace Msp {
21
22 /**
23 Constructs an instance of the registered application class and runs it.  If the
24 application throws a UsageError, the static usage() function is called.
25
26 This function can only be called once.  The global main() function provided by
27 the library normally does it automatically at program startup.
28 */
29 int Application::run(int argc, char **argv, void *data)
30 {
31         static bool called=false;
32         if(called)
33         {
34                 cerr<<"Trying to call Application::run_app twice!\n";
35                 return 125;
36         }
37         called=true;
38
39         if(!reg_app_)
40         {
41                 cerr<<"Trying to run with no application class registered!\n";
42                 return 126;
43         }
44
45         data_=data;
46
47         try
48         {
49                 try
50                 {
51                         app_=reg_app_->create_app(argc, argv);
52                 }
53                 catch(const UsageError &e)
54                 {
55                         reg_app_->usage(e.what(), argv[0], e.get_brief());
56                         return 1;
57                 }
58
59                 int result=app_->main();
60                 delete app_;
61                 return result;
62         }
63         catch(const exception &e)
64         {
65                 cerr<<"An uncaught exception occurred.\n";
66                 cerr<<"  type:   "<<Debug::demangle(typeid(e).name())<<'\n';
67                 cerr<<"  what(): "<<e.what()<<'\n';
68
69                 const Exception *exc=dynamic_cast<const Exception *>(&e);
70                 if(exc && !exc->get_backtrace().get_frames().empty())
71                 {
72                         cerr<<"  backtrace:\n";
73                         const Debug::Backtrace::FrameSeq &frames=exc->get_backtrace().get_frames();
74                         for(Debug::Backtrace::FrameSeq::const_iterator i=frames.begin(); i!=frames.end(); ++i)
75                         {
76                                 cerr<<"    "<<i->address;
77                                 if(!i->symbol.empty())
78                                         cerr<<" in "<<i->symbol;
79                                 cerr<<" from "<<i->file<<'\n';
80                         }
81                 }
82
83                 delete app_;
84                 return 124;
85         }
86 }
87
88 /**
89 Prints a message describing the usage of the application.  The default version
90 will blame the programmer for being lazy.
91
92 @param   reason  Why the function was called
93 @param   argv0   The value of argv[0], to be used in the message
94 @param   brief   Whether to print a brief or long usage message
95 */
96 void Application::usage(const char *reason, const char *, bool)
97 {
98         if(reason)
99                 cerr<<"UsageError: "<<reason<<'\n';
100         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
101 }
102
103 Application::Application():
104         exit_code(0),
105         loop_mode_(TICK_SLEEP)
106 { }
107
108 /**
109 Default main loop.  Behavior depends on loop_mode_.  A custom main loop should
110 monitor the done member variable and return exit_code.
111 */
112 int Application::main()
113 {
114         if(loop_mode_==NONE)
115                 return 0;
116
117         done=false;
118         while(!done)
119         {
120                 if(loop_mode_==SLEEP)
121                 {
122                         sleep_sem_.wait();
123                         if(!done)
124                                 tick();
125                 }
126                 else if(loop_mode_==TICK_SLEEP)
127                 {
128                         tick();
129                         Time::sleep(Time::msec);
130                 }
131                 else if(loop_mode_==TICK_YIELD)
132                 {
133                         tick();
134 #ifdef WIN32
135                         Sleep(0);
136 #else
137                         sched_yield();
138 #endif
139                 }
140                 else if(loop_mode_==TICK_BUSY)
141                         tick();
142         }
143
144         return exit_code;
145 }
146
147 /**
148 Sets the specified signal to be delivered to the sighandler member function.
149 */
150 void Application::catch_signal(int s)
151 {
152         signal(s, &sighandler_);
153 }
154
155 /**
156 Changes the main loop mode.
157 */
158 void Application::set_loop_mode(LoopMode l)
159 {
160         LoopMode old_mode=loop_mode_;
161         loop_mode_=l;
162         if(old_mode==SLEEP)
163                 sleep_sem_.signal();
164 }
165
166 /**
167 Causes the tick() function to be executed once if loop mode is SLEEP.  Has no
168 effect with other loop modes.
169 */
170 void Application::induce_tick()
171 {
172         if(loop_mode_==SLEEP)
173                 sleep_sem_.signal();
174 }
175
176 /**
177 Causes the application to exit gracefully with the given exit code.
178 */
179 void Application::exit(int c)
180 {
181         done=true;
182         exit_code=c;
183         if(loop_mode_==SLEEP)
184                 sleep_sem_.signal();
185 }
186
187 /**
188 Static wrapper function to call a member function of the Application instance.
189 */
190 void Application::sighandler_(int s)
191 {
192         app_->sighandler(s);
193 }
194
195 Application::RegBase::RegBase()
196 {
197         if(reg_app_)
198         {
199                 cerr<<"Warning: registering the application twice\n";
200                 delete reg_app_;
201         }
202
203         reg_app_=this;
204 }
205
206 Application *Application::app_=0;
207 Application::RegBase *Application::reg_app_=0;
208 void *Application::data_=0;
209
210 } // namespace Msp