shutdown_alerter.cpp

Go to the documentation of this file.
00001 #ifndef SHUTDOWN_ALERTER_IMPLEMENTATION_FILE
00002 #define SHUTDOWN_ALERTER_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : shutdown_alerter                                                  *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2003-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "process_control.h"
00019 #include "process_entry.h"
00020 #include "shutdown_alerter.h"
00021 
00022 #include <basis/array.cpp>
00023 #include <basis/istring.h>
00024 #include <basis/log_base.h>
00025 #include <basis/mutex.h>
00026 #include <basis/portable.h>
00027 #include <basis/set.cpp>
00028 #include <data_struct/static_memory_gremlin.h>
00029 #include <mechanisms/time_stamp.h>
00030 #include <opsystem/filename.h>
00031 #include <opsystem/timer_driver.h>
00032 
00033 #include <signal.h>
00034 
00035 //#define DEBUG_SHUTDOWN_ALERTER
00036   // uncomment for noisy version.
00037 
00038 #undef LOG
00039 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00040 
00042 
00043 SAFE_STATIC(istring_object, shutdown_alerter::_app_name, )
00044 
00045 bool &shutdown_alerter::_defunct() { static bool _defu = false; return _defu; }
00046 
00047 bool &shutdown_alerter::_saw_interrupt()
00048 { static bool _saw = false; return _saw; }
00049 
00050 int &shutdown_alerter::_timer_period() { static int _tim = 0; return _tim; }
00051 
00053 
00054 static shutdown_alerter *_global_shutdown_alerter = NIL;
00055   // this static object is set by the setup() method.  it should only come
00056   // into existence once during a program's lifetime.
00057 
00058 shutdown_alerter::shutdown_alerter()
00059 {
00060 }
00061 
00062 shutdown_alerter::~shutdown_alerter()
00063 {
00064   set_defunct();
00065   if (_global_shutdown_alerter) {
00066     program_wide_timer().zap_timer(_global_shutdown_alerter);
00067   }
00068 }
00069 
00070 void shutdown_alerter::handle_startup() { /* nothing for base class. */ }
00071 
00072 void shutdown_alerter::handle_shutdown() { /* nothing for base class. */ }
00073 
00074 void shutdown_alerter::handle_timer() { /* nothing for base class. */ }
00075 
00076 void shutdown_alerter::handle_timer_callback()
00077 { 
00078   // don't invoke the user's timer unless the object is still alive.
00079   if (!is_defunct()) handle_timer();
00080 }
00081 
00082 void shutdown_alerter::close_this_program()
00083 {
00084   set_defunct();
00085 }
00086 
00087 bool shutdown_alerter::close_application(const istring &app_name)
00088 {
00089   FUNCDEF("close_application");
00090   process_entry_array procs;
00091   process_control querier;
00092 
00093   // lookup process ids of apps.
00094   bool got_list = querier.query_processes(procs);
00095   if (!got_list) {
00096     LOG("couldn't get process list.");
00097     return false;
00098   }
00099   int_set pids;
00100   got_list = querier.find_process_in_list(procs, app_name, pids);
00101   if (!got_list) {
00102     LOG("couldn't find process in the list of active ones.");
00103     return true;
00104   }
00105 
00106   // zap all of them using our signal.
00107   for (int i = 0; i < pids.length(); i++) {
00108 //would linux be better served with sigterm also?
00109 #ifdef __UNIX__
00110     kill(pids[i], SIGHUP);
00111 #endif
00112 #ifdef __WIN32__
00113 //lame--goes to whole program.
00114     raise(SIGTERM);
00115 #endif
00116 //hmmm: check results...
00117   }
00118 
00119   return true;
00120 }
00121 
00122 void shutdown_alerter::handle_OS_signal(int formal(sig_id))
00123 {
00124   _saw_interrupt() = true;  // save the status.
00125   if (_global_shutdown_alerter) {
00126     _global_shutdown_alerter->close_this_program();
00127   }
00128 }
00129 
00130 void shutdown_alerter::set_defunct()
00131 {
00132   _defunct() = true;
00133 }
00134 
00135 bool shutdown_alerter::setup(const istring &app_name, int timer_period)
00136 {
00137 //hmmm: make sure not already initted.
00138 
00139   // simple initializations first...
00140   _timer_period() = timer_period;
00141   _app_name() = app_name;
00142 
00143   _global_shutdown_alerter = this;
00144 
00145   // setup signal handler for HUP signal.  this is the one used to tell us
00146   // to leave.
00147 #ifdef __UNIX__
00148   signal(SIGHUP, handle_OS_signal);
00149 #endif
00150 
00151   // setup a handler for interrupt (e.g. ctrl-C) also.
00152   signal(SIGINT, handle_OS_signal);
00153 #ifdef __WIN32__
00154   signal(SIGBREAK, handle_OS_signal);
00155 #endif
00156 
00157   return true;
00158 }
00159 
00160 bool shutdown_alerter::launch_console(shutdown_alerter &alert,
00161     const istring &app_name, int timer_period)
00162 {
00163   FUNCDEF("launch_console");
00164   if (!alert.setup(app_name, timer_period)) return false;
00165 
00166   alert.handle_startup();  // tell the program it has started up.
00167 
00168   // start a timer if they requested one.
00169   if (_timer_period()) {
00170     program_wide_timer().set_timer(_timer_period(), &alert);
00171   }
00172 
00173 #ifdef DEBUG_SHUTDOWN_ALERTER
00174   time_stamp next_report(10 * SECOND_ms);
00175 #endif
00176 
00177   while (!alert.is_defunct()) {
00178 #ifdef DEBUG_SHUTDOWN_ALERTER
00179     if (time_stamp() >= next_report) {
00180       printf("%s: shout out from my main thread yo.\n", __argv[0]);
00181       next_report.reset(10 * SECOND_ms);
00182     }
00183 #endif
00184     portable::sleep_ms(42);
00185   }
00186   alert.handle_shutdown();
00187   return true;
00188 }
00189 
00190 /*
00191 #ifdef __WIN32__
00192 bool shutdown_alerter::launch_event_loop(shutdown_alerter &alert,
00193     const istring &app_name, int timer_period)
00194 {
00195   if (!alert.setup(app_name, timer_period)) return false;
00196   alert.handle_startup();
00197 
00198   if (timer_period)
00199     program_wide_timer().set_timer(timer_period, this);
00200 
00201   MSG msg;
00202   msg.hwnd = 0; msg.message = 0; msg.wParam = 0; msg.lParam = 0;
00203   while (!alert.is_defunct() && (GetMessage(&msg, NIL, 0, 0)) {
00204     TranslateMessage(&msg);
00205     DispatchMessage(&msg);
00206   }
00207   alert.handle_shutdown();
00208 
00209   return true;
00210 }
00211 #endif
00212 */
00213 
00214 
00215 
00216 #endif //SHUTDOWN_ALERTER_IMPLEMENTATION_FILE
00217 

Generated on Fri Nov 21 04:29:57 2008 for HOOPLE Libraries by  doxygen 1.5.1