summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/Task.h1
-rw-r--r--include/TaskMan.h19
-rw-r--r--include/Variables.h1
-rw-r--r--lib/Task.cc16
-rw-r--r--lib/TaskMan.cc111
-rw-r--r--lib/Variables.cc6
-rw-r--r--src/Main.cc102
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();