diff options
-rw-r--r-- | include/Task.h | 1 | ||||
-rw-r--r-- | include/TaskMan.h | 19 | ||||
-rw-r--r-- | include/Variables.h | 1 | ||||
-rw-r--r-- | lib/Task.cc | 16 | ||||
-rw-r--r-- | lib/TaskMan.cc | 111 | ||||
-rw-r--r-- | lib/Variables.cc | 6 | ||||
-rw-r--r-- | src/Main.cc | 102 |
7 files changed, 208 insertions, 48 deletions
diff --git a/include/Task.h b/include/Task.h index b4d8b68..b6f9b2e 100644 --- a/include/Task.h +++ b/include/Task.h @@ -22,6 +22,7 @@ class Task : public Base { virtual ~Task(); virtual String GetName(); int Run(); + int DryRun(); int GetState(); void Suspend(int = -1) throw (GeneralException); void WaitFor(Task *); diff --git a/include/TaskMan.h b/include/TaskMan.h index 8cd8e66..e61aa3f 100644 --- a/include/TaskMan.h +++ b/include/TaskMan.h @@ -2,9 +2,16 @@ #define __TASKMAN_H__ #ifdef __cplusplus +#include <signal.h> #include <Task.h> #include <vector.h> +#define E_BURST 0 +#define E_HANDLE 1 +#define E_PROCESS 2 +#define E_TIMEOUT 3 +#define E_TASK 4 + class TaskMan : public Base { public: static void AddTask(Task *); @@ -13,10 +20,15 @@ class TaskMan : public Base { static void Init() throw (GeneralException); static void MainLoop() throw (GeneralException); static void WaitFor(Handle *, Task *, int = 0); - static void WaitFor(pid_t, Task *); + static void WaitFor(pid_t, Task *, int = 0); static void WaitFor(timeval, Task *, int = 0); static int GotChild(pid_t, int); static void Stop(); + static int Event(); + static Task * Etask(); + static Handle * Ehandle(); + static int Eprocess(); + static int Estatus(); class w4ha_t { public: @@ -53,6 +65,11 @@ class TaskMan : public Base { static vector<w4pr_t> w4pr; static vector<w4to_t> w4to; static bool stopped; + static int event; + static Task * etask; + static Handle * ehandle; + static int eprocess, estatus; + static sigset_t sigchildset; }; #else diff --git a/include/Variables.h b/include/Variables.h index f3471bd..f4eb6db 100644 --- a/include/Variables.h +++ b/include/Variables.h @@ -10,6 +10,7 @@ class Variables : public Base { public: Variables(int = 0); + Variables(const Variables &); ~Variables(); void SetTo(int i, const String &); String operator[](const String &); diff --git a/lib/Task.cc b/lib/Task.cc index 839c003..3cac327 100644 --- a/lib/Task.cc +++ b/lib/Task.cc @@ -33,6 +33,22 @@ int Task::Run() { return state; } +int Task::DryRun() { + while (state != TASK_DONE) { + try { + state = Do(); + } + catch (TaskSwitch) { + } + catch (GeneralException e) { + cerr << _("Task ") << GetName() << _(" caused an unexpected exception during dry-run: \"") << e.GetMsg() << _("\". Terminating.\n"); + state = TASK_DONE; + } + } + + return state; +} + int Task::GetState() { return state; } diff --git a/lib/TaskMan.cc b/lib/TaskMan.cc index 3169f88..4d58be9 100644 --- a/lib/TaskMan.cc +++ b/lib/TaskMan.cc @@ -22,6 +22,12 @@ bool TaskMan::stopped = false; int TaskMan::number = 0; bool TaskMan::inited = false; +int TaskMan::event, TaskMan::eprocess, TaskMan::estatus; +Task * TaskMan::etask; +Handle * TaskMan::ehandle; + +sigset_t TaskMan::sigchildset; + static int got_sigchild = 0; void taskman_sigchild(int sig) { @@ -30,13 +36,17 @@ void taskman_sigchild(int sig) { pid = wait(&status); if (TaskMan::GotChild(pid, status)) { - got_sigchild = 1; + got_sigchild++; + } else { + TaskMan::WaitFor(pid, 0, status); } + + cerr << "Got SIGCHILD, pid = " << pid << " and status = " << status << endl; signal(SIGCHLD, taskman_sigchild); } -void taskman_sigpipe(int sig) { - signal(SIGPIPE, taskman_sigpipe); +void taskman_sighole(int sig) { + signal(sig, taskman_sighole); } int TaskMan::GotChild(pid_t pid, int status) { @@ -59,7 +69,12 @@ void TaskMan::Init() throw (GeneralException) { } signal(SIGCHLD, taskman_sigchild); - signal(SIGPIPE, taskman_sigpipe); + signal(SIGPIPE, taskman_sighole); + signal(SIGHUP, taskman_sighole); + + sigemptyset(&sigchildset); + sigaddset(&sigchildset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigchildset, 0); inited = true; number = 0; @@ -69,6 +84,26 @@ void TaskMan::Stop() { stopped = true; } +int TaskMan::Event() { + return event; +} + +Task * TaskMan::Etask() { + return etask; +} + +Handle * TaskMan::Ehandle() { + return ehandle; +} + +int TaskMan::Eprocess() { + return eprocess; +} + +int TaskMan::Estatus() { + return estatus; +} + void TaskMan::AddTask(Task * t) { if (!inited) { Init(); @@ -132,8 +167,19 @@ void TaskMan::WaitFor(Handle * h, Task * t, int flags) { w4ha.push_back(w4ha_t(h, flags, t)); } -void TaskMan::WaitFor(pid_t p, Task * t) { - w4pr.push_back(w4pr_t(p, t)); +void TaskMan::WaitFor(pid_t pid, Task * t, int status) { + if (status == -1) { + for (vector<w4pr_t>::iterator p = w4pr.begin(); p && (p != w4pr.end()); p++) { + if (p->pr == pid) { + p->T = t; + p->flag = true; + got_sigchild++; + return; + } + } + } + w4pr.push_back(w4pr_t(pid, t)); + w4pr[w4pr.size() - 1].status = status; } void TaskMan::WaitFor(timeval t, Task * T, int flags) { @@ -163,19 +209,24 @@ void TaskMan::MainLoop() throw (GeneralException) { while (!no_burst) { no_burst = 1; /* First, we will check for any burning task and run 'em */ + event = E_BURST; for (TaskList_t::iterator p = TaskList.begin(); p && (p != TaskList.end()); p++) { Task * t = *p; -// cerr << "-=- TaskMan: task " << t->GetName() << endl; - + cerr << "-=- TaskMan: task " << t->GetName() << endl; + + if (t->IsStopped()) { + continue; + } + if (t->GetState() == TASK_BURST) { - cerr << "-=- TaskMan: running burning task " << t->GetName() << endl; +// cerr << "-=- TaskMan: running burning task " << t->GetName() << endl; t->Run(); /* if the task added some new tasks, we have to rerun the loop */ no_burst = 0; break; } - + if (t->GetState() == TASK_DONE) { TaskList.erase(p); number--; @@ -185,6 +236,10 @@ void TaskMan::MainLoop() throw (GeneralException) { } } + /* Now is time to check all the handle and enters into a wait state. */ + + event = E_HANDLE; + nfds = w4ha.size(); no_burst = 1; @@ -223,7 +278,9 @@ void TaskMan::MainLoop() throw (GeneralException) { } } - r = poll(ufsd, nfds, (no_burst) && !(Zombies.size()) ? -1: 0); + sigprocmask(SIG_UNBLOCK, &sigchildset, 0); + r = poll(ufsd, nfds, (no_burst) && !(Zombies.size()) && !(got_sigchild) ? -1: 0); + sigprocmask(SIG_BLOCK, &sigchildset, 0); #else FD_ZERO(readfds); FD_ZERO(writefds); @@ -241,14 +298,16 @@ void TaskMan::MainLoop() throw (GeneralException) { FD_SET(p->ha->GetHandle(), exceptfds); } + sigprocmask(SIG_UNBLOCK, &sigchildset, 0); r = select(highest + 1, &readfds, &writefds, &exceptfds, NULL); + sigprocmask(SIG_BLOCK, &sigchildset, 0); #endif if (r < 0) { if (errno != EINTR) { throw GeneralException(String(_("Error during poll: ")) + strerror(errno)); } } else if (r == 0) { - // timeout... + // timeout or child. // **FIXME** #warning FIXME } else { @@ -294,6 +353,7 @@ void TaskMan::MainLoop() throw (GeneralException) { touched = true; + ehandle = p->ha; w4.T->Run(); if (w4.T->GetState() == TASK_DONE) { @@ -316,9 +376,13 @@ void TaskMan::MainLoop() throw (GeneralException) { #endif } + /* And finally, let's clean-up all the zombies around here. */ + int no_zombies; no_zombies = 0; + event = E_TASK; + while (!no_zombies) { no_zombies = 1; while (Zombies.size()) { @@ -331,6 +395,7 @@ void TaskMan::MainLoop() throw (GeneralException) { if ((o = t->WaitedBy())) { cerr << "-=- TaskMan: running task " << o->GetName() << " for task " << t->GetName() << endl; + etask = t; o->Run(); if (o->GetState() == TASK_DONE) { @@ -350,9 +415,27 @@ void TaskMan::MainLoop() throw (GeneralException) { } } + /* To end up the loop, let's recall task waiting for processes */ + + event = E_PROCESS; + if (got_sigchild) { - // **FIXME** -#warning FIXME + for (vector<w4pr_t>::iterator p = w4pr.begin(); p && (p != w4pr.end()); p++) { + if (p->flag) { + Task * t; + if (p->T->IsStopped()) { + continue; + } + eprocess = p->pr; + estatus = p->status; + cerr << "-=- TaskMan: running task " << p->T->GetName() << " for process " << p->pr << " (" << p->status << ")\n"; + t = p->T; + w4pr.erase(p); + got_sigchild--; + t->Run(); + break; + } + } } } } diff --git a/lib/Variables.cc b/lib/Variables.cc index 274a4ed..d96cad8 100644 --- a/lib/Variables.cc +++ b/lib/Variables.cc @@ -5,6 +5,12 @@ Variables::Variables(int nb) : Vars(nb), nbvars(nb) { } +Variables::Variables(const Variables & v) : nbvars(v.nbvars) { + for (int i = 0; i < nbvars; i++) { + Vars.push_back(v.Vars[i]); + } +} + Variables::~Variables() { } void Variables::SetTo(int i, const String & s) { diff --git a/src/Main.cc b/src/Main.cc index 1436f84..caba9b6 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -21,45 +21,81 @@ InPipe * in; -class ad_t : public Action { +class ad_run : public Task { public: - ad_t() : Action("menu6") { } - virtual ~ad_t() { } - virtual String GetTitle() { return "Action dynamique"; } - virtual Task * Do(Variables * v, Variables * hds, Handle * h) { - String ut, un, shds; - - if (!fork()) { - execlp("uptime", "uptime", NULL); - } - (*in) >> ut; - wait(NULL); - - if (!fork()) { - execlp("uname", "uname", "-a", NULL); - } - (*in) >> un; - wait(NULL); - - for (int i = 0; i < hds->GetNb(); i++) { - shds += (*hds)[i] + "<BR>\n"; - } - - Action * m = new Message("Action dynamique", - String("Vous avez choisi l'action dynamique. L'uptime de la machine est '") + - ut + "' et sa définition complète est '" + un + "'<BR><BR><BR>Voici la liste des entêtes:<BR><BR>" + shds, ""); + ad_run(Variables * av, Variables * ahds, Handle * ah) : v(*av), hds(*ahds), h(ah) { + SetBurst(); + } + virtual ~ad_run() {} + virtual String GetName() { return "Action dynamique"; } + protected: + virtual int Do() throw (GeneralException) { + pid_t p; + + switch (current) { + case 0: + if (!(p = fork())) { + execlp("uptime", "uptime", NULL); + } + current = 1; + WaitFor(p); + Suspend(TASK_ON_HOLD); + + case 1: + (*in) >> ut; + if (!(p = fork())) { + execlp("uname", "uname", "-a", NULL); + } + current = 2; + WaitFor(p); + Suspend(TASK_ON_HOLD); - Task * t = m->Do(v, hds, h); + case 2: + (*in) >> un; + for (int i = 0; i < hds.GetNb(); i++) { + shds += hds[i] + "<BR>\n"; + } - Image * testimg = new Image(100, 100); - testimg->Prepare(); + m = new Message("Action dynamique", + String("Vous avez choisi l'action dynamique. L'uptime de la machine est '") + + ut + "' et sa définition complète est '" + un + "'<BR><BR><BR>Voici la liste des entêtes:<BR><BR>" + shds, ""); - Output * testoutput = new Output("TestImg.tga"); + current = 3; + WaitFor(m->Do(&v, &hds, h)); + Suspend(TASK_ON_HOLD); + + case 3: + delete m; + testimg = new Image(100, 100); + testimg->Prepare(); - new CopyJob(testimg, testoutput, -1, true, true); + testoutput = new Output("TestImg.tga"); - delete m; - return t; + current = 4; + WaitFor(new CopyJob(testimg, testoutput, -1, true, true)); + Suspend(TASK_ON_HOLD); + + case 4: + return TASK_DONE; + } + return TASK_DONE; + } + private: + Variables v, hds; + Handle * h; + String ut, un, shds; + Action * m; + Image * testimg; + Output * testoutput; +}; + +class ad_t : public Action { + public: + ad_t() : Action("menu6") { } + virtual ~ad_t() { } + virtual String GetTitle() { return "Action dynamique"; } + virtual Task * Do(Variables * v, Variables * hds, Handle * h) { + return new ad_run(v, hds, h); } }; Action * ad = new ad_t(); |