first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / application / hoople_service.cpp
1 //////////////
2 // Name   : hoople_service
3 // Author : Chris Koeritz
4 //////////////
5 // Copyright (c) 2000-$now By Author.  This program is free software; you can
6 // redistribute it and/or modify it under the terms of the GNU General Public
7 // License as published by the Free Software Foundation:
8 //     http://www.gnu.org/licenses/gpl.html
9 // or under the terms of the GNU Library license:
10 //     http://www.gnu.org/licenses/lgpl.html
11 // at your preference.  Those licenses describe your legal rights to this
12 // software, and no other rights or warranties apply.
13 // Please send updates for this code to: fred@gruntose.com -- Thanks, fred.
14 //////////////
15
16 #include "hoople_service.h"
17
18 #include <basis/array.h>
19 #include <basis/mutex.h>
20 #include <filesystem/filename.h>
21 #include <loggers/program_wide_logger.h>
22 #include <loggers/critical_events.h>
23 #include <processes/process_control.h>
24 #include <processes/process_entry.h>
25 #include <structures/set.h>
26 #include <structures/static_memory_gremlin.h>
27 #include <timely/time_control.h>
28 #include <timely/time_stamp.h>
29 #include <timely/timer_driver.h>
30
31 #include <signal.h>
32
33 using namespace basis;
34 using namespace filesystem;
35 using namespace loggers;
36 using namespace processes;
37 using namespace structures;
38 using namespace timely;
39
40 //#define DEBUG_HOOPLE_SERVICE
41   // uncomment for noisy version.
42
43 #undef LOG
44 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
45
46 namespace application {
47
48 //////////////
49
50 SAFE_STATIC(astring, hoople_service::_app_name, )
51
52 bool &hoople_service::_defunct() { static bool _defu = false; return _defu; }
53
54 bool &hoople_service::_saw_interrupt()
55 { static bool _saw = false; return _saw; }
56
57 int &hoople_service::_timer_period() { static int _tim = 0; return _tim; }
58
59 //////////////
60
61 static hoople_service *_global_hoople_service = NIL;
62   // this static object is set by the setup() method.  it should only come
63   // into existence once during a program's lifetime.
64
65 hoople_service::hoople_service()
66 {
67 }
68
69 hoople_service::~hoople_service()
70 {
71   make_defunct();
72   if (_global_hoople_service) {
73     program_wide_timer().zap_timer(_global_hoople_service);
74   }
75 }
76
77 void hoople_service::handle_startup() { /* nothing for base class. */ }
78
79 void hoople_service::handle_shutdown() { /* nothing for base class. */ }
80
81 void hoople_service::handle_timer() { /* nothing for base class. */ }
82
83 void hoople_service::handle_timer_callback()
84
85   // don't invoke the user's timer unless the object is still alive.
86   if (!is_defunct()) handle_timer();
87 }
88
89 void hoople_service::close_this_program()
90 {
91   make_defunct();
92 }
93
94 bool hoople_service::close_application(const astring &app_name)
95 {
96   FUNCDEF("close_application");
97   process_entry_array procs;
98   process_control querier;
99
100   // lookup process ids of apps.
101   bool got_list = querier.query_processes(procs);
102   if (!got_list) {
103     LOG(astring("couldn't get process list."));
104     return false;
105   }
106   int_set pids;
107   got_list = querier.find_process_in_list(procs, app_name, pids);
108   if (!got_list) {
109     LOG(astring("couldn't find process in the list of active ones."));
110     return true;
111   }
112
113   // zap all of them using our signal.
114   for (int i = 0; i < pids.length(); i++) {
115 //would linux be better served with sigterm also?
116 #ifdef __UNIX__
117     kill(pids[i], SIGHUP);
118 #endif
119 #ifdef __WIN32__
120 //lame--goes to whole program.
121     raise(SIGTERM);
122 #endif
123 //hmmm: check results...
124   }
125
126   return true;
127 }
128
129 void hoople_service::handle_OS_signal(int formal(sig_id))
130 {
131   _saw_interrupt() = true;  // save the status.
132   if (_global_hoople_service) {
133     _global_hoople_service->close_this_program();
134   }
135 }
136
137 void hoople_service::make_defunct()
138 {
139   _defunct() = true;
140 }
141
142 bool hoople_service::setup(const astring &app_name, int timer_period)
143 {
144 //hmmm: make sure not already initted.
145
146   // simple initializations first...
147   _timer_period() = timer_period;
148   _app_name() = app_name;
149
150   _global_hoople_service = this;
151
152   // setup signal handler for HUP signal.  this is the one used to tell us
153   // to leave.
154 #ifdef __UNIX__
155   signal(SIGHUP, handle_OS_signal);
156 #endif
157
158   // setup a handler for interrupt (e.g. ctrl-C) also.
159   signal(SIGINT, handle_OS_signal);
160 #ifdef __WIN32__
161   signal(SIGBREAK, handle_OS_signal);
162 #endif
163
164   return true;
165 }
166
167 bool hoople_service::launch_console(hoople_service &alert,
168     const astring &app_name, int timer_period)
169 {
170 #ifdef DEBUG_HOOPLE_SERVICE
171   FUNCDEF("launch_console");
172 #endif
173   if (!alert.setup(app_name, timer_period)) return false;
174
175   alert.handle_startup();  // tell the program it has started up.
176
177   // start a timer if they requested one.
178   if (_timer_period()) {
179     program_wide_timer().set_timer(_timer_period(), &alert);
180   }
181
182 #ifdef DEBUG_HOOPLE_SERVICE
183   time_stamp next_report(10 * SECOND_ms);
184 #endif
185
186   while (!alert.is_defunct()) {
187 #ifdef DEBUG_HOOPLE_SERVICE
188     if (time_stamp() >= next_report) {
189       printf("%s: shout out from my main thread yo.\n", _global_argv[0]);
190       next_report.reset(10 * SECOND_ms);
191     }
192 #endif
193     time_control::sleep_ms(42);
194   }
195   alert.handle_shutdown();
196   return true;
197 }
198
199 /*
200 #ifdef __WIN32__
201 bool hoople_service::launch_event_loop(hoople_service &alert,
202     const astring &app_name, int timer_period)
203 {
204   if (!alert.setup(app_name, timer_period)) return false;
205   alert.handle_startup();
206
207   if (timer_period)
208     program_wide_timer().set_timer(timer_period, this);
209
210   MSG msg;
211   msg.hwnd = 0; msg.message = 0; msg.wParam = 0; msg.lParam = 0;
212   while (!alert.is_defunct() && (GetMessage(&msg, NIL, 0, 0)) {
213     TranslateMessage(&msg);
214     DispatchMessage(&msg);
215   }
216   alert.handle_shutdown();
217
218   return true;
219 }
220 #endif
221 */
222
223 } //namespace.
224