process_manager.cpp

Go to the documentation of this file.
00001 #ifndef PROCESS_MANAGER_IMPLEMENTATION_FILE
00002 #define PROCESS_MANAGER_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : process_manager                                                   *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2000-$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 "anchor_window.h"
00019 #include "application_config.h"
00020 #include "process_control.h"
00021 #include "process_entry.h"
00022 #include "process_manager.h"
00023 
00024 #include <basis/auto_synch.h>
00025 #include <basis/istring.h>
00026 #include <basis/log_base.h>
00027 #include <basis/mutex.h>
00028 #include <basis/portable.h>
00029 #include <basis/set.cpp>
00030 #include <basis/version_record.h>
00031 #include <data_struct/configurator.h>
00032 #include <data_struct/section_manager.h>
00033 #include <data_struct/string_table.h>
00034 #include <data_struct/unique_id.h>
00035 #include <mechanisms/ithread.h>
00036 #include <mechanisms/time_stamp.h>
00037 #include <opsystem/filename.h>
00038 
00039 #define DEBUG_PROCESS_MANAGER
00040   // uncomment for verbose diagnostics.
00041 
00042 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00043 
00044 const int CHECK_INTERVAL = 4 * SECOND_ms;
00045   // this is how frequently the checking thread executes to ensure that
00046   // processes are gone when they should be.
00047 
00048 const int GRACEFUL_SLACK = 90 * SECOND_ms;
00049   // the length of time before a graceful shutdown devolves into a forced
00050   // shutdown.
00051 
00052 const int MAXIMUM_INITIAL_APP_WAIT = 4 * SECOND_ms;
00053   // this is the longest we bother to wait for a process we just started.
00054   // if it hasn't begun by then, we decide it will never do so.
00055 
00056 const int STARTUP_APPS_DELAY_PERIOD = 2 * SECOND_ms;
00057   // we delay for this long before the initial apps are started.
00058 
00059 const int MAXIMUM_REQUEST_PAUSE = 42 * SECOND_ms;
00060   // the longest we will ever wait for a response to be generated based on
00061   // our last request.
00062 
00063 // these are concurrency control macros for the lists managed here.
00064 #define LOCK_CONFIG auto_synchronizer l(*_config_lock)
00065 #define LOCK_ZOMBIES auto_synchronizer l(*_zombie_lock)
00066 #define LOCK_KIDS auto_synchronizer l(*_scamp_lock)
00067 
00068 // error messages.
00069 #ifdef DEBUG_PROCESS_MANAGER
00070   #define COMPLAIN_APPLICATION \
00071     LOG(istring("the application called ") + app_name + " could not be found.")
00072   #define COMPLAIN_PRODUCT \
00073     LOG(istring("the section for ") + product + " could not be found.")
00074 #else
00075   #define COMPLAIN_APPLICATION {}
00076   #define COMPLAIN_PRODUCT {}
00077 #endif
00078 
00080 
00081 class process_manager_thread : public ithread
00082 {
00083 public:
00084   process_manager_thread(process_manager &parent)
00085   : ithread(CHECK_INTERVAL, ithread::SLACK_INTERVAL),
00086     _parent(parent) {}
00087   virtual ~process_manager_thread() {}
00088 
00089   virtual void perform_activity(void *)
00090       { _parent.push_timed_activities(_processes); }
00091 
00092 private:
00093   process_manager &_parent;  // the owner of the object.
00094   process_entry_array _processes;  // will be filled as needed.
00095 };
00096 
00098 
00099 class graceful_record
00100 {
00101 public:
00102   istring _product;  // the product name the app is listed under.
00103   istring _app_name;  // the application's name.
00104   time_stamp _started;  // when the graceful shutdown started.
00105   int _pid;  // the particular process id for this app.
00106   int _level;  // the shutdown ordering specifier.
00107 
00108   graceful_record(int pid = 0, const istring &product = "",
00109           const istring &app_name = "", int level = 0)
00110   : _product(product), _app_name(app_name), _pid(pid), _level(level) {}
00111 };
00112 
00113 class graceful_array : public array<graceful_record> {};
00114 
00116 
00117 process_manager::process_manager(application_config &config)
00118 : _configs(config),
00119   _started_initial_apps(false),
00120   _checker(new process_manager_thread(*this)),
00121   _config_lock(new mutex),
00122   _going_down(new graceful_array),
00123   _zombie_lock(new mutex),
00124   _our_kids(new graceful_array),
00125   _scamp_lock(new mutex),
00126   _stop_launching(false),
00127   _startup_time(new time_stamp(STARTUP_APPS_DELAY_PERIOD)),
00128   _procs(new process_control),
00129   _gag_exclusions(new string_set),
00130   _tracking_exclusions(new string_set)
00131 {
00132   FUNCDEF("constructor");
00133 
00134   // start the application checking thread.
00135   _checker->start(NIL);
00136 
00137   _checker->reschedule(200);  // make it start pretty quickly.
00138 }
00139 
00140 process_manager::~process_manager()
00141 {
00142   FUNCDEF("destructor");
00143   stop_everything();
00144 
00145   WHACK(_checker);
00146   WHACK(_going_down);
00147   WHACK(_our_kids);
00148   WHACK(_scamp_lock);
00149   WHACK(_zombie_lock);
00150   WHACK(_config_lock);
00151   WHACK(_startup_time);
00152   WHACK(_procs);
00153   WHACK(_gag_exclusions);
00154   WHACK(_tracking_exclusions);
00155   LOG("process_manager is now stopped.");
00156 }
00157 
00158 void process_manager::add_gag_exclusion(const istring &exclusion)
00159 { *_gag_exclusions += exclusion; }
00160 
00161 void process_manager::add_tracking_exclusion(const istring &exclusion)
00162 { *_tracking_exclusions += exclusion; }
00163 
00164 const char *process_manager::outcome_name(const outcome &to_name)
00165 {
00166   switch (to_name.value()) {
00167     case FILE_NOT_FOUND: return "FILE_NOT_FOUND";
00168     case NO_ANCHOR: return "NO_ANCHOR";
00169     case NO_PRODUCT: return "NO_PRODUCT";
00170     case NO_APPLICATION: return "NO_APPLICATION";
00171     case BAD_PROGRAM: return "BAD_PROGRAM";
00172     case LAUNCH_FAILED: return "LAUNCH_FAILED";
00173     case NOT_RUNNING: return "NOT_RUNNING";
00174     case FROZEN: return "FROZEN";
00175     default: return common::outcome_name(to_name);
00176   }
00177 }
00178 
00179 void process_manager::stop_everything()
00180 {
00181   _stop_launching = true;  // at least deny any connected clients.
00182   stop_all_kids();  // shut down all programs that we started.
00183   _checker->stop();  // stop our thread.
00184 }
00185 
00186 void process_manager::stop_all_kids()
00187 {
00188   FUNCDEF("stop_all_kids");
00189   _stop_launching = true;  // set this for good measure to keep clients out.
00190   LOG("zapping any active sub-processes prior to exit.");
00191 
00192   // now we wait for the process closures to take effect.  we are relying on
00193   // the graceful shutdown devolving to a process zap and the timing is
00194   // rooted around that assumption.
00195 
00196   for (int lev = 100; lev >= 0; lev--) {
00197     // loop from our highest level to our lowest for the shutdown.
00198 #ifdef DEBUG_PROCESS_MANAGER
00199     LOG(isprintf("level %d", lev));
00200 #endif
00201     bool zapped_any = false;
00202     {
00203       // this shuts down all the child processes we've started at this level.
00204       LOCK_KIDS;  // lock within this scope.
00205       for (int i = _our_kids->length() - 1; i >= 0; i--) {
00206         // now check each record and see if it's at the appropriate level.
00207         graceful_record &grace = (*_our_kids)[i];
00208         if (lev == grace._level) {
00209           // start a graceful shutdown.
00210           zap_process(grace._product, grace._app_name, true);
00211           // remove it from our list.
00212           _our_kids->zap(i, i);
00213           zapped_any = true;  // set our flag.
00214         }
00215       }
00216     }
00217     int num_dying = 1;  // go into the loop once at least.
00218 
00219 #ifdef DEBUG_PROCESS_MANAGER
00220     time_stamp next_print(4 * SECOND_ms);
00221 #endif
00222 
00223     while (num_dying) {
00224 #ifdef DEBUG_PROCESS_MANAGER
00225       if (time_stamp() >= next_print) {
00226         LOG("waiting...");
00227         next_print.reset(4 * SECOND_ms);
00228       }
00229 #endif
00230 
00231       // while there are any pending process zaps, we will wait here.  this
00232       // will hose us but good if the processes aren't eventually cleared up,
00233       // but that shouldn't happen.
00234 
00235       {
00236         LOCK_ZOMBIES;
00237         num_dying = _going_down->length();
00238       }
00239 
00240       if (!num_dying) break;  // jump out of loop.
00241 
00242       _checker->reschedule(0);  // make thread check as soon as possible.
00243 
00244       portable::sleep_ms(40);
00245     }
00246 #ifdef DEBUG_PROCESS_MANAGER
00247     LOG("done waiting...");
00248 #endif
00249   }
00250 }
00251 
00252 void process_manager::launch_startup_apps()
00253 {
00254   FUNCDEF("launch_startup_apps");
00255 
00256   // read the startup section.
00257   string_table startup_info;
00258   {
00259     LOCK_CONFIG;
00260     if (!_configs.find_section(_configs.STARTUP_SECTION(), startup_info)) {
00261       // if there's no startup section, we do nothing right now.
00262       LOG("the startup section was not found!");
00263       return;
00264     }
00265   }
00266 #ifdef DEBUG_PROCESS_MANAGER
00267   LOG(istring("table has: ") + startup_info.text_form());
00268 #endif
00269 
00270   for (int i = 0; i < startup_info.symbols(); i++) {
00271     istring app = startup_info.name(i);
00272     if (app == application_config::STARTUP_APP_NAME()) continue;
00273       // skip bogus name that keeps the section present.
00274     istring info = startup_info[i];
00275     LOG(istring("launching application ") + app + "...");
00276     // parse the items that are in the entry for this program.
00277     istring product, parms;
00278     bool one_shot;
00279     if (!application_config::parse_startup_entry(info, product, parms,
00280         one_shot)) {
00281       LOG("the startup entry was not malformed; we could not parse it!");
00282       continue;
00283     }
00284 
00285     LOG(app + isprintf(" is %ssingle shot.", one_shot? "" : "not "));
00286 
00287     // now try to send the program off on its way.
00288     launch_now(product, app, parms);
00289 
00290     if (one_shot) {
00291       // it's only supposed to be started once, so now toss out the entry.
00292       remove_from_startup(product, app);
00293     }
00294   }
00295 }
00296 
00297 outcome process_manager::launch_now(const istring &product,
00298     const istring &app_name, const istring &parameters)
00299 {
00300   FUNCDEF("launch_now");
00301   LOG(istring("product \"") + product + "\", application \"" + app_name
00302       + (parameters.length() ? istring("\"")
00303             : istring("\", parms=") + parameters));
00304 
00305   if (_stop_launching) {
00306     // if the application is one of the exceptions to the gag rule, then
00307     // we will still launch it.  otherwise, we'll ignore this request.
00308     if (_gag_exclusions->member(app_name)) {
00309       // this is one of the apps that can still be launched when gagged.
00310     } else {
00311       LOG(istring("application \"") + app_name + "\" cannot be launched;"
00312          + log_base::platform_ending() + "launching services have been "
00313          "shut down.");
00314       return LAUNCH_FAILED;
00315     }
00316   }
00317 
00318   istring entry_found;
00319   int level;
00320   {
00321     LOCK_CONFIG;
00322 
00323     // get the specific entry for the program they want.
00324     entry_found = _configs.find_program(product, app_name, level);
00325     if (!entry_found) {
00326       if (!_configs.product_exists(product)) {
00327         // return more specific error for missing product.
00328         COMPLAIN_PRODUCT;
00329         return NO_PRODUCT;
00330       }
00331       COMPLAIN_APPLICATION;
00332       return NO_APPLICATION;
00333     }
00334   }
00335 
00336   filename existence_check(entry_found);
00337   if (!existence_check.exists()) {
00338     LOG(istring("file or path wasn't found for ") + entry_found + ".");
00339     return FILE_NOT_FOUND;
00340   }
00341 
00342   u_int kid = 0;
00343   int ret = portable::launch_process(entry_found, parameters,
00344       portable::RETURN_IMMEDIATELY | portable::HIDE_APP_WINDOW, kid);
00345   if (!ret) {
00346     // hey, it worked!  so now make sure we track its lifetime...
00347 
00348     if (_tracking_exclusions->member(app_name)) {
00349       // this is one of the apps that we don't track.  if it's still
00350       // running when we're shutting down, it's not our problem.
00351       return OKAY;
00352     }
00353 
00354     if (kid) {
00355       // we were told the specific id for the process we started.
00356       LOCK_KIDS;
00357       LOG(isprintf("adding given process id %d for app %s at level %d.",
00358           kid, app_name.s(), level));
00359       graceful_record to_add(kid, product, app_name, level);
00360       *_our_kids += to_add;
00361       return OKAY;
00362     }
00363 #ifdef DEBUG_PROCESS_MANAGER
00364     LOG("was not told child process id!!!");
00365 #endif
00366     // we weren't told the process id; let's see if we can search for it.
00367     int_set pids;
00368     time_stamp give_it_up(MAXIMUM_INITIAL_APP_WAIT);
00369     while (give_it_up > time_stamp()) {
00370       // find the process id for the program we just started.
00371       if (find_process(app_name, pids)) break;
00372       portable::sleep_ms(10);  // pause to see if we can find it yet.
00373     }
00374 
00375     if (time_stamp() >= give_it_up) {
00376       // we could not launch it for some reason, or our querier has failed.
00377       // however, as far as we know, it launched successfully.  if the id is
00378       // missing, then that's not really our fault.  we will just not be able
00379       // to track the program, possibly because it's already gone.
00380       LOG(istring("no process found for product \"") + product
00381           + "\", application \"" + app_name + "\"; not adding "
00382           "tracking record.");
00383       return OKAY;
00384     }
00385   
00386     LOCK_KIDS;
00387 
00388     // add all the processes we found under that name.
00389     for (int i = 0; i < pids.elements(); i++) {
00390       LOG(isprintf("adding process id %d for app %s at level %d.",
00391           pids[i], app_name.s(), level));
00392       graceful_record to_add(pids[i], product, app_name, level);
00393       *_our_kids += to_add;
00394     }
00395     return OKAY;
00396   }
00397 
00398   // if we reached here, things are not good.  we must not have been able to
00399   // start the process.
00400 
00401 #ifdef __WIN32__
00402   if (ret == NO_ERROR) return OKAY;  // how would that happen?
00403   else if ( (ret == ERROR_FILE_NOT_FOUND) || (ret == ERROR_PATH_NOT_FOUND) ) {
00404     LOG(istring("file or path wasn't found for ") + app_name + ".");
00405     return FILE_NOT_FOUND;
00406   } else if (ret == ERROR_BAD_FORMAT) {
00407     LOG(istring(app_name) + " was not in EXE format.");
00408     return BAD_PROGRAM;
00409   } else {
00410     LOG(istring("there was an unknown error while trying to run ")
00411         + app_name + "; the error is:" + log_base::platform_ending()
00412         + portable::system_error_text(ret));
00413     return LAUNCH_FAILED;
00414   }
00415 #else
00416   LOG(istring("error ") + portable::system_error_text(ret)
00417       + " occurred attempting to run: " + app_name + " " + parameters);
00418   return FILE_NOT_FOUND;
00419 #endif
00420 }
00421 
00422 outcome process_manager::launch_at_startup(const istring &product,
00423     const istring &app_name, const istring &parameters, int one_shot)
00424 {
00425   FUNCDEF("launch_at_startup");
00426   LOCK_CONFIG;  // this whole function modifies the config file.
00427 
00428 #ifdef DEBUG_PROCESS_MANAGER
00429   LOG(istring("product \"") + product + "\", application \"" + app_name
00430       + (one_shot? istring("\", OneShot") : istring("\", MultiUse")));
00431 #endif
00432 
00433   // get the specific entry for the program they want.
00434   int level;
00435   istring entry_found = _configs.find_program(product, app_name, level);
00436   if (!entry_found) {
00437     if (!_configs.product_exists(product)) {
00438       // return more specific error for missing product.
00439       COMPLAIN_PRODUCT;
00440       return NO_PRODUCT;
00441     }
00442     COMPLAIN_APPLICATION;
00443     return NO_APPLICATION;
00444   }
00445 
00446   if (!_configs.add_startup_entry(product, app_name, parameters, one_shot)) {
00447     // most likely problem is that it was already there.
00448     return EXISTING;
00449   }
00450 
00451   return OKAY;
00452 }
00453 
00454 outcome process_manager::remove_from_startup(const istring &product,
00455     const istring &app_name)
00456 {
00457   FUNCDEF("remove_from_startup");
00458   LOCK_CONFIG;  // this whole function modifies the config file.
00459 
00460 #ifdef DEBUG_PROCESS_MANAGER
00461   LOG(istring("product \"") + product + "\", application \"" + app_name + "\"");
00462 #endif
00463 
00464   // get the specific entry for the program they want.
00465   int level;
00466   istring entry_found = _configs.find_program(product, app_name, level);
00467   if (!entry_found) {
00468     if (!_configs.product_exists(product)) {
00469       // return more specific error for missing product.
00470       COMPLAIN_PRODUCT;
00471       return NO_PRODUCT;
00472     }
00473     COMPLAIN_APPLICATION;
00474     return NO_APPLICATION;
00475   }
00476 //hmmm: is product required for this for real?
00477 
00478   if (!_configs.remove_startup_entry(product, app_name)) {
00479     // the entry couldn't be removed, probably doesn't exist.
00480     return NO_APPLICATION;
00481   }
00482 
00483   return OKAY;
00484 }
00485 
00486 outcome process_manager::query_application(const istring &product,
00487     const istring &app_name)
00488 {
00489   FUNCDEF("query_application");
00490 #ifdef DEBUG_PROCESS_MANAGER
00491   LOG(istring("product \"") + product + "\", application \"" + app_name + "\"");
00492 #endif
00493 
00494   {
00495     LOCK_CONFIG;
00496     // get the specific entry for the program they want.
00497     int level;
00498     istring entry_found = _configs.find_program(product, app_name, level);
00499     if (!entry_found) {
00500       if (!_configs.product_exists(product)) {
00501         // return more specific error for missing product.
00502         COMPLAIN_PRODUCT;
00503         return NO_PRODUCT;
00504       }
00505       COMPLAIN_APPLICATION;
00506       return NO_APPLICATION;
00507     }
00508   }
00509 
00510   // now seek that program name in the current list of processes.
00511   istring program_name(app_name);
00512   program_name.to_lower();
00513 
00514   int_set pids;
00515   if (!find_process(app_name, pids))
00516     return NOT_RUNNING;
00517   return OKAY;
00518 }
00519 
00520 outcome process_manager::start_graceful_close(const istring &product,
00521     const istring &app_name)
00522 {
00523   FUNCDEF("start_graceful_close");
00524 //hmmm: record this app as one we need to watch.
00525 
00526   {
00527     // find that program name to make sure it's not already shutting down.
00528     LOCK_ZOMBIES;
00529 
00530     for (int i = _going_down->length() - 1; i >= 0; i--) {
00531       graceful_record &grace = (*_going_down)[i];
00532       if (grace._app_name.iequals(app_name)) {
00533         return OKAY;
00534       }
00535     }
00536   }
00537 
00538   if (!anchor_window::close_app_window(app_name))
00539     return NO_ANCHOR;
00540 
00541   int_set pids;
00542   if (!find_process(app_name, pids)) {
00543     LOG(istring("Failed to find process id for [") + app_name
00544         + istring("], assuming it has already exited."));
00545     return OKAY;
00546   }
00547 
00548   {
00549     // add all the process ids, just in case there were multiple instances
00550     // of the application somehow.
00551     LOCK_ZOMBIES;
00552     for (int i = 0; i < pids.elements(); i++) {
00553       graceful_record to_add(pids[i], product, app_name);
00554       *_going_down += to_add;
00555     }
00556   }
00557 
00558   return OKAY;
00559 }
00560 
00561 bool process_manager::get_processes(process_entry_array &processes)
00562 {
00563   FUNCDEF("get_processes");
00564   if (!_procs->query_processes(processes)) {
00565     LOG("failed to query processes!");
00566     return false;
00567   }
00568   return true;
00569 }
00570 
00571 bool process_manager::find_process(const istring &app_name_in, int_set &pids)
00572 {
00573   FUNCDEF("find_process");
00574   pids.clear();
00575   process_entry_array processes;
00576   if (!get_processes(processes)) return false;
00577   return process_control::find_process_in_list(processes, app_name_in, pids);
00578 }
00579 
00580 outcome process_manager::zap_process(const istring &product,
00581     const istring &app_name, bool graceful)
00582 {
00583   FUNCDEF("zap_process");
00584 
00585 #ifdef DEBUG_PROCESS_MANAGER
00586   LOG(istring("product \"") + product + "\", application \"" + app_name
00587       + (graceful? "\", Graceful Close" : "\", Brutal Close"));
00588 #endif
00589 
00590   if (_tracking_exclusions->member(app_name)) {
00591     // the non-tracked applications are never reported as running since they're
00592     // not allowed to be zapped anyhow.
00593     return NOT_RUNNING;
00594   }
00595 
00596   istring entry_found;
00597   {
00598     LOCK_CONFIG;
00599 
00600     // get the specific entry for the program they want.
00601     int level;
00602     istring entry_found = _configs.find_program(product, app_name, level);
00603     if (!entry_found) {
00604       if (!_configs.product_exists(product)) {
00605         // return more specific error for missing product.
00606         COMPLAIN_PRODUCT;
00607         return NO_PRODUCT;
00608       }
00609       COMPLAIN_APPLICATION;
00610       return NO_APPLICATION;
00611     }
00612   }
00613 
00614   // if they want a graceful close, start by trying that.  if it appears to
00615   // have succeeded, then we exit and let the thread take care of ensuring
00616   // the app goes down.
00617   outcome to_return = NOT_RUNNING;
00618   if (graceful)
00619     to_return = start_graceful_close(product, app_name);
00620   if (to_return == OKAY)
00621     return OKAY;  // maybe finished the close.
00622 
00623   // they want a harsh close of this application or the graceful close failed.
00624   istring program_name(app_name);
00625   int_set pids;
00626   if (!find_process(program_name, pids)) {
00627 #ifdef DEBUG_PROCESS_MANAGER
00628     LOG(program_name + " process was not running.")
00629 #endif
00630     return NOT_RUNNING;
00631   }
00632 
00633   // search for the application in the process list.
00634   bool failed = false;
00635   for (int i = 0; i < pids.elements(); i++) {
00636     bool ret = _procs->zap_process(pids[i]);
00637     if (ret) {
00638       LOG(istring(istring::SPRINTF, "Killed process %d [",
00639           pids[i]) + program_name + istring("]"));
00640     } else {
00641       LOG(istring(istring::SPRINTF, "Failed to zap process %d [",
00642           pids[i]) + program_name + istring("]"));
00643     }
00644     if (!ret) failed = true;
00645   }
00646 // kind of a bizarre return, but whatever.  it really should be some
00647 // failure result since the zap failed.
00648   return failed? ACCESS_DENIED : OKAY;
00649 }
00650 
00651 outcome process_manager::shut_down_launching_services(const istring &secret_word)
00652 {
00653   FUNCDEF("shut_down_launching_services");
00654   LOG("checking secret word...");
00655   if (secret_word == "KrustyDoesn'tDoThat.") {
00656     LOG("it's correct; ending launch capabilities.");
00657   } else {
00658     LOG("the secret word is wrong.  continuing normal operation.");
00659     return BAD_PROGRAM;
00660   }
00661   _stop_launching = true;
00662   return OKAY;
00663 }
00664 
00665 outcome process_manager::reenable_launching_services(const istring &secret_word)
00666 {
00667   FUNCDEF("reenable_launching_services");
00668   LOG("checking secret word...");
00669   if (secret_word == "KrustyDoesn'tDoThat.") {
00670     LOG("it's correct; resuming launch capabilities.");
00671   } else {
00672     LOG("the secret word is wrong.  continuing with prior mode.");
00673     return BAD_PROGRAM;
00674   }
00675   _stop_launching = false;
00676   return OKAY;
00677 }
00678 
00679 #define GET_PROCESSES \
00680   if (!retrieved_processes) { \
00681     retrieved_processes = true; \
00682     if (!get_processes(processes)) { \
00683       LOG("failed to retrieve process list from OS!"); \
00684       return;  /* badness. */ \
00685     } \
00686   }
00687 
00688 void process_manager::push_timed_activities(process_entry_array &processes)
00689 {
00690   FUNCDEF("push_timed_activities");
00691 
00692   // make sure we started the applications that were slated for execution at
00693   // system startup time.  we wait on this until the first thread activation
00694   // to give other processes some breathing room right at startup time.
00695   // also, it then doesn't block the main service thread.
00696   if (!_started_initial_apps && (*_startup_time <= time_stamp()) ) {
00697     // launch all the apps that are listed for system startup.
00698     LOG("starting up the tasks registered for system initiation.");
00699     launch_startup_apps();
00700     _started_initial_apps = true;
00701   }
00702 
00703   if (!_started_initial_apps) {
00704     _checker->reschedule(200);
00705       // keep hitting this function until we know we can relax since the
00706       // startup apps have been sent off.
00707   }
00708 
00709   bool retrieved_processes = false;
00710 
00711   {
00712     // loop over the death records we've got and check on the soon to be gone.
00713     LOCK_ZOMBIES;
00714 
00715     for (int i = _going_down->length() - 1; i >= 0; i--) {
00716       graceful_record &grace = (*_going_down)[i];
00717 
00718       GET_PROCESSES;  // load them if they hadn't been.
00719 
00720       int_set pids;
00721       if (!process_control::find_process_in_list(processes, grace._app_name,
00722           pids)) {
00723         // the app can't be found as running, so whack the record for it.
00724 #ifdef DEBUG_PROCESS_MANAGER
00725         LOG(istring("cannot find app ") + grace._app_name
00726             + " as running still; removing its dying record");
00727 #endif
00728         _going_down->zap(i, i);
00729         continue;
00730       }
00731       if (!pids.member(grace._pid)) {
00732         // that particular instance exited on its own, so whack the record.
00733 #ifdef DEBUG_PROCESS_MANAGER
00734         LOG(istring("app ") + grace._app_name
00735             + " exited on its own; removing its dying record");
00736 #endif
00737         _going_down->zap(i, i);
00738         continue;
00739       }
00740 
00741       if (grace._started <= time_stamp(-GRACEFUL_SLACK)) {
00742         // time to force it.
00743         LOG(istring("Application ") + grace._app_name + " is unresponsive to "
00744             "the graceful shutdown request.  Now zapping it instead.");
00745         if (!_procs->zap_process(grace._pid))
00746           LOG("Devolved graceful shutdown failed as zap_process also.");
00747         _going_down->zap(i, i);
00748         continue;
00749       }
00750 
00751       // it's not time to dump this one yet, so keep looking at others.
00752     }
00753   }
00754 
00755   {
00756     // now loop over the list of our active kids and make sure that they are
00757     // all still running.  if they aren't, then toss the record out.
00758     LOCK_KIDS;
00759 
00760     for (int i = _our_kids->length() - 1; i >= 0; i--) {
00761       graceful_record &grace = (*_our_kids)[i];
00762 
00763       GET_PROCESSES;  // load them if they hadn't been.
00764 
00765       int_set pids;
00766       if (!process_control::find_process_in_list(processes, grace._app_name,
00767           pids)) {
00768         // the app can't be found as running, so whack the record for it.
00769 #ifdef DEBUG_PROCESS_MANAGER
00770         LOG(istring("cannot find kid ") + grace._app_name
00771             + " as still running; removing its normal record");
00772 #endif
00773         _our_kids->zap(i, i);
00774         continue;
00775       }
00776       if (!pids.member(grace._pid)) {
00777         // that particular instance exited on its own, so whack the record.
00778 #ifdef DEBUG_PROCESS_MANAGER
00779         LOG(istring("kid ") + grace._app_name
00780             + " exited on its own; removing its normal record");
00781 #endif
00782         _our_kids->zap(i, i);
00783         continue;
00784       }
00785 
00786       // this kid is still going, so keep its record.
00787     }
00788   }
00789 }
00790 
00791 
00792 #endif //PROCESS_MANAGER_IMPLEMENTATION_FILE
00793 

Generated on Tue Aug 19 04:29:49 2008 for HOOPLE Libraries by  doxygen 1.5.1