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
00021
00022
00023
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
00058
00059
00060
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);
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
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);
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
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
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
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
00204
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))
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
00235
00236
00237 static const int MAX_NORMAL_EXIT_CODES = 99;
00238
00239 ILOG_VAR_DECL;
00240
00241 std::map<int, ProcessData> mProcesses;
00242
00243 };
00244
00245 ILOG_VAR_INIT(Manager4Windows, Impala.Process);
00246
00247 }
00248 }
00249
00250 #endif