Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

Manager4Windows.h

Go to the documentation of this file.
00001 #ifndef Impala_Process_Manager4Windows_h
00002 #define Impala_Process_Manager4Windows_h
00003 
00004 #include <map>
00005 #include <strstream>
00006 
00007 #include <windows.h>
00008 
00009 #include "Basis/ILog.h"
00010 #include "Basis/String.h"
00011 
00012 #include "Process/Manager.h"
00013 
00014 namespace Impala
00015 {
00016 namespace Process
00017 {
00018 
00019 /********************************************************************
00020  Instances of this class are able of starting and 
00021  controlling processes on the Windows platform(s).
00022 
00023  Note that this class is in itself not thread-safe!
00024 *********************************************************************/
00025 
00026 class Manager4Windows : public Manager
00027 {
00028 
00029 public:
00030 
00031     Manager4Windows()
00032     {
00033         ILOG_DEBUG("Creating instance");
00034     }
00035 
00036     virtual ~Manager4Windows()
00037     {
00038         std::map<int, ProcessData>::iterator iter = mProcesses.begin();
00039         while (iter != mProcesses.end())
00040         {
00041             int handle = iter->first;
00042             Kill(handle);
00043             iter++;
00044         }
00045         ILOG_DEBUG("Destroying instance");
00046     }
00047 
00048     int Create(const std::string& cmdLine, std::string application)
00049     {
00050         STARTUPINFO startupInfo;
00051         ZeroMemory(&startupInfo, sizeof(startupInfo));
00052         startupInfo.cb = sizeof(startupInfo);
00053 
00054         PROCESS_INFORMATION procInfo;
00055         ZeroMemory(&procInfo, sizeof(procInfo));
00056 
00057         //std::ostrstream osAppl;
00058         //if (application != NULL)
00059         //{
00060         //    osAppl << application << std::ends;
00061         //}
00062 
00063         std::ostrstream osCmdLine;
00064         osCmdLine << cmdLine << std::ends;
00065 
00066         int rc = ::CreateProcess((application.empty() ? NULL : application.c_str()), osCmdLine.str(), NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &procInfo);
00067 
00068         osCmdLine.freeze(false); // prevents mem leak
00069 
00070         if (rc == 0)
00071         {
00072             DWORD err = GetLastError();
00073             ILOG_ERROR("Failed to create process (code " + MakeString(err) + ")");
00074             return 0;
00075         }
00076 
00077         // find free handle
00078         int handle = 0;
00079         std::map<int, ProcessData>::const_iterator iter;
00080         do
00081         {
00082              iter = mProcesses.find(++handle);
00083         } while (iter != mProcesses.end());
00084 
00085         ProcessData data;
00086         data.winHandle = procInfo.hProcess;
00087         data.stateCode = STATE_RUNNING;
00088         mProcesses[handle] = data;
00089         return handle;
00090     }
00091 
00092     int GetManagedProcessCount() const
00093     {
00094         return mProcesses.size();
00095     }
00096 
00097     bool IsRunning(int handle)
00098     {
00099         return (GetState(handle) == STATE_RUNNING);
00100     }
00101 
00102     bool IsTerminated(int handle)
00103     {
00104         return !IsRunning(handle);
00105     }
00106 
00107     void Sleep(int sec)
00108     {
00109         ::Sleep(sec * 1000); //millisec's
00110     }
00111 
00112     //int WaitFor(int handle)
00113     //{
00114     //    HANDLE winHandle = GetWinHandle(handle);
00115 
00116     //    while (mProcesses[handle].stateCode == STATE_RUNNING)
00117     //    {
00118     //        if (AssessProcessState(winHandle, handle))
00119     //        {
00120     //            Sleep(Manager::WAIT_INTERVAL_SEC);
00121     //        }
00122     //        else
00123     //        {
00124     //            int ec = GetWinExitCode(winHandle, handle);
00125     //            if (ec == 0)
00126     //                mProcesses[handle].stateCode = STATE_TERM_SUCCESS;
00127     //            else
00128     //            {
00129     //                ILOG_ERROR("process has unexpected exit code: " << ec);
00130     //                mProcesses[handle].stateCode = STATE_TERM_ERROR;
00131     //            }
00132     //        }
00133     //    }
00134 
00135     //    return mProcesses[handle].stateCode;
00136     //}
00137 
00138     void Kill(int handle)
00139     {
00140         if (IsRunning(handle))
00141             Kill(GetWinHandle(handle), handle);
00142     }
00143 
00144     void Remove(int handle)
00145     {
00146         Kill(handle);
00147         mProcesses.erase(handle);
00148     }
00149 
00150     int GetState(int handle)
00151     {
00152         AssessProcessState(GetWinHandle(handle), handle);
00153         return mProcesses[handle].stateCode;
00154     }
00155 
00156     int GetExitCode(int handle)
00157     {
00158         if (IsRunning(handle))
00159         {
00160             // should have checked using IsRunning() first
00161             ILOG_ERROR("Process is still running; no exit code available yet");
00162             throw "process still running";
00163         }
00164 
00165         return (int) GetWinExitCode(GetWinHandle(handle), handle);
00166     }
00167 
00168 private:
00169 
00170     HANDLE GetWinHandle(int handle)
00171     {
00172         std::map<int, ProcessData>::const_iterator iter = mProcesses.find(handle);
00173         if (iter == mProcesses.end())
00174         {
00175             ILOG_ERROR("Unknown process handle: " << handle);
00176             return NULL;
00177         }
00178         return mProcesses[handle].winHandle;
00179     }
00180 
00181     DWORD GetWinExitCode(HANDLE winHandle, int handle)
00182     {
00183         DWORD exitCode = NULL;
00184         if ( ! ::GetExitCodeProcess(winHandle, &exitCode))
00185         {
00186             DWORD err = ::GetLastError();
00187             ILOG_ERROR("Failed at retrieving exit code for process handle " << handle << 
00188                 " (last error code " << err << "); attempting to kill the process");
00189             Kill(winHandle, handle);
00190         }
00191         //ILOG_DEBUG("exitCode (DWORD): " << exitCode);
00192         return exitCode;
00193     }
00194 
00195     void AssessProcessState(HANDLE winHandle, int handle)
00196     {
00197         if (mProcesses[handle].stateCode != STATE_RUNNING)
00198             return;
00199 
00200         DWORD exitCodeWin = GetWinExitCode(winHandle, handle);
00201         if (exitCodeWin == STILL_ACTIVE)
00202         {
00203             // note that we ignore the possibility of the process 
00204             // exiting with exactly this value!
00205             return;
00206         }
00207 
00208         if (exitCodeWin == 0)
00209             mProcesses[handle].stateCode = STATE_TERM_SUCCESS;
00210         else if (exitCodeWin <= MAX_NORMAL_EXIT_CODES)
00211             mProcesses[handle].stateCode = STATE_TERM_ERROR;
00212         else 
00213             mProcesses[handle].stateCode = STATE_TERM_ABNORMAL;
00214         return;
00215     }
00216 
00217     void Kill(HANDLE winHandle, int handle)
00218     {
00219         if (::TerminateProcess(winHandle, MAX_NORMAL_EXIT_CODES+1)) // might compromise global DLL data; see Platform SDK doc
00220         {
00221             mProcesses[handle].stateCode = STATE_TERM_ABNORMAL;
00222         }
00223         else
00224         {
00225             DWORD err = GetLastError();
00226             ILOG_ERROR("Failed to terminate process with handle " << handle << 
00227                 " (erro code " << err << ")");
00228             mProcesses[handle].stateCode = STATE_UNKNOWN;
00229         }
00230     }
00231 
00232     typedef struct {HANDLE winHandle; int stateCode;} ProcessData;
00233 
00234     // Following value is very disputable: a process returning an exit code below
00235     // this value, is assumed to have terminated normally; values beyond it
00236     // are assumed to be exception values indicating abnormal process termination.
00237     static const int MAX_NORMAL_EXIT_CODES = 99;
00238 
00239     ILOG_VAR_DECL;
00240 
00241     std::map<int, ProcessData> mProcesses;
00242 
00243 }; // class
00244 
00245 ILOG_VAR_INIT(Manager4Windows, Impala.Process);
00246 
00247 } // namespace 
00248 } // namespace 
00249 
00250 #endif

Generated on Fri Mar 19 09:31:45 2010 for ImpalaSrc by  doxygen 1.5.1