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