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

Manager4Posix.h

Go to the documentation of this file.
00001 #ifndef Impala_Process_Manager4Posix_h
00002 #define Impala_Process_Manager4Posix_h
00003 
00004 #include <map>
00005 #include <strstream>
00006 
00007 //Posix specific includes/////
00008 #include <sys/types.h>
00009 #include <sys/time.h>
00010 #include <sys/wait.h>
00011 #include <sys/resource.h>
00012 #include <unistd.h>
00013 #include <signal.h>
00014 #include <errno.h>
00015 #include <string.h>
00017 
00018 #include "Basis/ILog.h"
00019 #include "Basis/String.h"
00020 #include "Basis/StringList.h"
00021 
00022 #include "Process/Manager.h"
00023 
00024 namespace Impala
00025 {
00026 namespace Process
00027 {
00028 
00029 /**************************************************************
00030  Instances of this class are able of starting and 
00031  controlling processes on Posix platforms.
00032 
00033  Note that this class is in itself not thread-safe!
00034 ***************************************************************/
00035 
00036 class Manager4Posix : public Manager
00037 {
00038     typedef struct {int stateCode; int exitCode;} ProcessData;
00039 
00040     ILOG_VAR_DECL;
00041     std::map<int, ProcessData> mProcesses;
00042 
00043 public:
00044 
00045     Manager4Posix()
00046     {
00047         ILOG_DEBUG("Creating instance");
00048     }
00049 
00050     virtual ~Manager4Posix()
00051     {
00052         std::map<int, ProcessData>::iterator iter = mProcesses.begin();
00053         while (iter != mProcesses.end())
00054         {
00055             int pid = iter->first;
00056             Kill(pid);
00057             iter++;
00058         }
00059         ILOG_DEBUG("Destroying instance");
00060     }
00061 
00062     int Create(const std::string& cmdLine, std::string application)
00063     {
00064         ILOG_INFO("Create [" << cmdLine << "][" << application << "]");
00065         pid_t pid = fork();//first fork the process
00066         if(pid==-1)
00067         {
00068             //Handle Error, we couldn't fork
00069             //Use thread safe call(strerror_r) to get error string
00070             char buff[256];
00071             if( strerror_r( errno, buff, 256 ) == 0 ) {
00072                 ILOG_ERROR("Could not fork process"<<buff);
00073             }
00074     
00075         }
00076         else if(pid==0)
00077         {
00078             //This is the child process, we should execute the new program
00079             //inside this process
00080             //call exec()
00081             ILOG_INFO("Child Process Running");
00082             
00084             //POSIX WAY FOR LIMITING CPU TIME
00085             //
00086             //Set the max for CPU Time
00087             //struct rlimit rlim;
00088             //rlim.rlim_cur=rlim.rlim_max = maxSomething;
00089             //setrlimit(RLIMIT_CPU,&rlim);
00091 
00092             
00093             StringList argList(cmdLine,' ');
00094             int argc=argList.size()+1;
00095             if (argc < 2)
00096             {
00097                 ILOG_ERROR("The cmd line must contain at least the name of the application to run");
00098                 abort();
00099             }
00100 
00101             char** argv;
00102             argv = new char*[argc];
00103 
00104             int a=0;
00105             StringList::const_iterator i=argList.begin();
00106             std::string application = *i;
00107             for ( ; i!=argList.end(); i++)
00108             {
00109                 argv[a] = new char[(*i).length() + 1];
00110                 sprintf(argv[a],(*i).c_str());
00111                 a++;
00112 
00113             }
00114             argv[a] = (char*)NULL;
00115             
00116             execvp(application.c_str(),argv);
00117             //exec never returns, if it did, there was an error
00118             char buff[256];
00119             if( strerror_r( errno, buff, 256 ) == 0 ) {
00120                 ILOG_ERROR("Could not start application"<<buff);
00121             }
00122             abort();
00123         }
00124         else
00125         {
00126             //We have the child process id in pid, store it for further control
00127             //of the process
00128             ILOG_INFO("The process is forked, child pid is: "<<pid);
00129             ProcessData data;
00130             data.stateCode = STATE_RUNNING;
00131             mProcesses[pid]  = data;
00132             return pid;
00133         }
00134 
00135     }
00136 
00137     bool 
00138     IsRunning(int pid)
00139     {
00140         //Check only if we think it's still running
00141         if(mProcesses[pid].stateCode == STATE_RUNNING)
00142         {
00143             //Check if the process still exists
00144             int status;
00145             int ret=waitpid(pid, &status, WNOHANG);
00146             //ret will be 0 if process is running
00147             if(ret==0)
00148                 return true;
00149             else
00150             {
00151                 SetExitCode(pid,status,ret);
00152                 return false;
00153             }
00154         }
00155         else//Already finished, and we have collected the exit code before
00156             return false;
00157     }
00158 
00159     int GetManagedProcessCount() const
00160     {
00161         return mProcesses.size();
00162     }
00163 
00164     bool IsTerminated(int pid)
00165     {
00166         return !IsRunning(pid);
00167     }
00168 
00169     void Sleep(int sec)
00170     {
00171         sleep(sec); //seconds
00172     }
00173 
00174     //int WaitFor(int pid)
00175     //{
00176     //    
00177     //    
00178     //    //This can as well be handled by setting the maximum time limits
00179     //    //through setrlimits, but left for now for consistency, 
00180     //    //should be discussed later.
00181     //    //
00182     //    //The following wait will be enough after setting the limits in the
00183     //    //creation of the process
00184     //    //
00185     //    //Wait for the process to finish
00186     //    /*
00187     //    int status;
00188     //    int ret=waitpid(pid, &status, 0);
00189     //    SetExitCode(pid,status,ret);
00190     //    return mProcesses[pid].stateCode;
00191     //    */
00192     //    
00193     //    
00194     //    //an implementation similar to windows version, polls the process
00195     //    //NOTE:the process times are for ALL the CHILD PROCESSES.
00196     //    while (mProcesses[pid].stateCode == STATE_RUNNING)
00197     //    {
00198     //        if (IsRunning( pid ))
00199     //        {
00200     //            Sleep(Manager::WAIT_INTERVAL_SEC);
00201 
00202     //            /*
00203     //            struct rusage buf;
00204     //            if(getrusage(RUSAGE_CHILDREN, &buf)==0)
00205     //            {
00206     //                //for system time use buf.ru_stime
00207     //                if(buf.ru_utime.tv_sec>mProcesses[pid].max)
00208     //                    Kill(pid);
00209     //                else
00210     //            
00211     //                    Sleep(1);
00212     //            }
00213     //            else
00214     //            {
00215     //                char buff[256];
00216     //                if( strerror_r( errno, buff, 256 ) == 0 ) {
00217     //                    ILOG_ERROR("failed to retrieve running times::"<<buff);
00218     //                }
00219     //                Kill(pid);
00220     //            }*/
00221     //        }
00222     //        else
00223     //        {
00224     //            //int ec = GetExitCode(winHandle, handle);
00225     //            //if (ec == 0)
00226     //            //    mProcesses[handle].stateCode = STATE_TERM_SUCCESS;
00227     //            //else
00228     //            //{
00229     //            //    ILOG_ERROR("process has unexpected exit code: " << ec);
00230     //            //    mProcesses[handle].stateCode = STATE_TERM_ERROR;
00231     //            //}
00232 
00233     //            int ec = GetExitCode(pid);
00234     //            if (ec == 0)
00235     //                mProcesses[pid].stateCode=STATE_TERM_SUCCESS;
00236     //            else
00237     //            {
00238     //                ILOG_ERROR("process has unexpected exit code: " << ec);
00239     //                mProcesses[pid].stateCode=STATE_TERM_ERROR;
00240     //            }
00241     //        }
00242     //    }
00243     //    return mProcesses[pid].stateCode;
00244     //}
00245 
00246     void Kill(int pid)
00247     {
00248         if (IsRunning(pid))
00249             kill(pid,SIGTERM);
00250     }
00251 
00252     void Remove(int pid)
00253     {
00254         Kill(pid);
00255         mProcesses.erase(pid);
00256     }
00257 
00258     int GetState(int pid)
00259     {
00260         if (IsRunning(pid))
00261             return STATE_RUNNING;
00262 
00263         return mProcesses[pid].stateCode;
00264     }
00265 
00266     int GetExitCode(int pid)
00267     {
00268         if (IsRunning(pid))
00269         {
00270             ILOG_ERROR("Process is still running; exit code not available (yet)");
00271             throw "process is still running";
00272         }
00273         return mProcesses[pid].exitCode;
00274     }
00275 
00276 private:
00277 
00278 
00279     void 
00280     SetExitCode(int pid,int status,int ret)
00281     {
00282         //If ret==pid, process finished
00283         if(ret==pid)
00284         {
00285             if(WIFEXITED(status))//Process exited normally
00286             {   
00287                 ILOG_DEBUG("Process exited normally!");
00288                 
00289                 //Collect the exit and termcodes
00290                 mProcesses[pid].exitCode = WEXITSTATUS(status);
00291 
00292                 if(WEXITSTATUS(status)==0)
00293                     mProcesses[pid].stateCode = STATE_TERM_SUCCESS;
00294                 else
00295                     mProcesses[pid].stateCode = STATE_TERM_ERROR;
00296             }
00297             else if(WIFSIGNALED(status)) //Process has been signalled
00298             {   
00299                 ILOG_ERROR("Process received a signal!");
00300                 //Add the signal number as exit code.
00301                 mProcesses[pid].stateCode = STATE_TERM_ABNORMAL;
00302                 mProcesses[pid].exitCode = WTERMSIG(status);
00303             }
00304         }else{//ret==-1 ERROR
00305             //This will happen when the process exited already, and this is
00306             //reported by a previous call to waitpid.
00307             //Since SetExitCode should set the stateCode to something other than
00308             //STATE_RUNNING, we should only fall here if there was some
00309             //other error, please see man 2 waitpid
00310             //
00311             char buff[256];
00312             if( strerror_r( errno, buff, 256 ) == 0 ) {
00313                 ILOG_ERROR("waitpid failed:"<<buff);
00314             }
00315         }
00316     }
00317 
00318 
00319 }; // class
00320 
00321 ILOG_VAR_INIT(Manager4Posix, Impala.Process);
00322 
00323 } // namespace 
00324 } // namespace 
00325 
00326 #endif

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