00001
00002
00003
00004
00005
00006
00007 #include "wvsubproc.h"
00008 #include <stdio.h>
00009 #include <unistd.h>
00010 #include <sys/types.h>
00011 #include <sys/wait.h>
00012 #include <sys/time.h>
00013 #include <stdarg.h>
00014 #include <errno.h>
00015 #include <assert.h>
00016
00017
00018 WvSubProc::WvSubProc()
00019 {
00020 pid = -1;
00021 running = false;
00022 estatus = 0;
00023 }
00024
00025
00026 WvSubProc::~WvSubProc()
00027 {
00028
00029
00030 stop(100);
00031 }
00032
00033
00034 int WvSubProc::start(const char cmd[], ...)
00035 {
00036 va_list ap;
00037 int nargs, count, retval;
00038 char *cptr;
00039 char **argv;
00040
00041 assert(!running);
00042
00043
00044 va_start(ap, cmd);
00045 for (nargs = 0; (cptr = va_arg(ap, char *)) != NULL; nargs++)
00046 ;
00047 va_end(ap);
00048
00049
00050 argv = new char* [nargs+1];
00051
00052
00053 va_start(ap, cmd);
00054 for (count = 0; count < nargs; count++)
00055 argv[count] = va_arg(ap, char *);
00056 argv[nargs] = NULL;
00057
00058 retval = startv(cmd, argv);
00059
00060 delete[] argv;
00061
00062 return retval;
00063 }
00064
00065
00066 int WvSubProc::startv(const char cmd[], const char * const *argv)
00067 {
00068 running = false;
00069 estatus = 0;
00070
00071 pid = fork();
00072
00073
00074 if (!pid)
00075 {
00076
00077
00078
00079
00080 setpgid(0,0);
00081
00082
00083 WvStringList::Iter i(env);
00084 for (i.rewind(); i.next(); )
00085 putenv(i().edit());
00086
00087
00088 execvp(cmd, (char * const *)argv);
00089
00090
00091
00092
00093 _exit(242);
00094 }
00095 else if (pid > 0)
00096 {
00097
00098 running = true;
00099 }
00100 else if (pid < 0)
00101 return -errno;
00102
00103 return 0;
00104 }
00105
00106
00107 void WvSubProc::kill(int sig)
00108 {
00109 assert(!running || pid > 1);
00110
00111 if (running)
00112 {
00113
00114 if (::kill(-pid, sig) < 0 && errno == ESRCH)
00115 kill_primary(sig);
00116 }
00117 }
00118
00119
00120 void WvSubProc::kill_primary(int sig)
00121 {
00122 assert(!running || pid > 1);
00123
00124 if (running)
00125 ::kill(pid, sig);
00126 }
00127
00128
00129 void WvSubProc::stop(time_t msec_delay)
00130 {
00131 if (!running) return;
00132
00133 wait(0);
00134
00135 if (running)
00136 {
00137 kill(SIGTERM);
00138 wait(msec_delay);
00139 }
00140
00141 if (running)
00142 {
00143 kill(SIGKILL);
00144 wait(-1);
00145 }
00146 }
00147
00148
00149 static long msecdiff(struct timeval &a, struct timeval &b)
00150 {
00151 long secdiff, usecdiff;
00152
00153 secdiff = a.tv_sec - b.tv_sec;
00154 usecdiff = a.tv_usec - b.tv_usec;
00155
00156 return secdiff*1000 + usecdiff/1000;
00157 }
00158
00159
00160 void WvSubProc::wait(time_t msec_delay)
00161 {
00162 int status;
00163 pid_t dead_pid;
00164 struct timeval tv1, tv2;
00165 struct timezone tz;
00166
00167 assert(!running || pid > 1);
00168
00169 if (!running) return;
00170
00171 gettimeofday(&tv1, &tz);
00172 tv2 = tv1;
00173
00174 do
00175 {
00176
00177
00178
00179
00180
00181
00182
00183
00184 dead_pid = waitpid(-pid, &status,
00185 (msec_delay >= 0) ? WNOHANG : 0);
00186 if (dead_pid < 0 && errno == ECHILD)
00187 dead_pid = waitpid(pid, &status,
00188 (msec_delay >= 0) ? WNOHANG : 0);
00189
00190
00191
00192 if (dead_pid < 0)
00193 {
00194
00195 if (errno == ECHILD)
00196 {
00197 if (::kill(-pid, 0) && errno == ESRCH)
00198 {
00199 running = false;
00200 pid = -1;
00201 }
00202 }
00203 else
00204 perror("WvSubProc::wait");
00205 }
00206 else if (dead_pid == pid)
00207 {
00208
00209 estatus = status;
00210 }
00211
00212 if (running && msec_delay != 0)
00213 {
00214
00215 usleep(50*1000);
00216 }
00217
00218 gettimeofday(&tv2, &tz);
00219
00220 } while (running && msec_delay
00221 && (msec_delay < 0 || msecdiff(tv2, tv1) < msec_delay));
00222 }