summaryrefslogtreecommitdiff
path: root/lib/TaskMan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/TaskMan.cc')
-rw-r--r--lib/TaskMan.cc228
1 files changed, 215 insertions, 13 deletions
diff --git a/lib/TaskMan.cc b/lib/TaskMan.cc
index bab9380..97fd1bd 100644
--- a/lib/TaskMan.cc
+++ b/lib/TaskMan.cc
@@ -1,7 +1,16 @@
#include <signal.h>
#include <wait.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <vector.h>
#include "TaskMan.h"
+#include "config.h"
+
+#define USE_POLL 1
TaskMan::TaskList_t TaskMan::TaskList;
TaskMan::TaskList_t TaskMan::Zombies;
@@ -34,18 +43,58 @@ void TaskMan::Init() throw (GeneralException) {
number = 0;
}
-int TaskMan::AddTask(Task * t) {
+void TaskMan::AddTask(Task * t) {
if (!inited) {
Init();
}
- TaskList.push_back(t);
- number++;
+
+ if (t) {
+ TaskList.push_back(t);
+ number++;
+ }
+}
- return 0;
+vector<Task *>::iterator TaskMan::FindTask(Task * t) {
+ if (!inited) {
+ Init();
+ }
+
+ for (TaskList_t::iterator p = TaskList.begin(); p && (p != TaskList.end()); p++) {
+ if (*p == t) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+void TaskMan::RemoveFromWatches(Task * t) {
+ for (vector<w4ha_t>::iterator p = w4ha.begin(); p && (p != w4ha.end()); p++) {
+ if (p->T == t) {
+ w4ha.erase(p);
+ p--;
+ }
+ }
+
+ for (vector<w4pr_t>::iterator p = w4pr.begin(); p && (p != w4pr.end()); p++) {
+ if (p->T == t) {
+ w4pr.erase(p);
+ p--;
+ }
+ }
+
+ for (vector<w4to_t>::iterator p = w4to.begin(); p && (p != w4to.end()); p++) {
+ if (p->T == t) {
+ w4to.erase(p);
+ p--;
+ }
+ }
}
void TaskMan::WaitFor(Handle * h, Task * t, int flags) {
- w4ha.push_back(w4ha_t(h, flags, t));
+ if (h->GetHandle() >= 0) {
+ w4ha.push_back(w4ha_t(h, flags, t));
+ }
}
void TaskMan::WaitFor(pid_t p, Task * t) {
@@ -57,8 +106,8 @@ void TaskMan::WaitFor(timeval t, Task * T, int flags) {
}
void TaskMan::MainLoop() throw (GeneralException) {
- TaskList_t::iterator p;
- Task * t;
+ struct pollfd * ufsd;
+ unsigned int nfds;
int no_burst;
@@ -67,8 +116,6 @@ void TaskMan::MainLoop() throw (GeneralException) {
}
while (1) {
- cerr << "TaskMan: Begin of main loop with " << number << " task to handle.\n";
-
if (number == 0) {
throw GeneralException("TaskMan: No more task to manage.");
}
@@ -77,11 +124,14 @@ void TaskMan::MainLoop() throw (GeneralException) {
while (!no_burst) {
no_burst = 1;
/* First, we will check for any burning task and run 'em */
- for (p = TaskList.begin(); p && (p != TaskList.end()); p++) {
- t = *p;
+ for (TaskList_t::iterator p = TaskList.begin(); p && (p != TaskList.end()); p++) {
+ Task * t = *p;
if (t->GetState() == TASK_BURST) {
t->Run();
+ /* if the task added some new tasks, we have to rerun the loop */
+ no_burst = 0;
+ break;
}
if (t->GetState() == TASK_BURST) {
@@ -98,10 +148,162 @@ void TaskMan::MainLoop() throw (GeneralException) {
}
}
}
- }
+
+ nfds = w4ha.size();
-#ifdef HAVE_POLL
+ if (nfds != 0) {
+ int r;
+ vector<w4ha_t>::iterator p;
+#ifdef USE_POLL
+ struct pollfd * q;
#else
+ int highest;
+ fd_set readfds, writefds, exceptfds;
#endif
+#ifdef USE_POLL
+ ufsd = (struct pollfd *) malloc(nfds * sizeof(struct pollfd));
+ for (q = ufsd, p = w4ha.begin(); p && (p != w4ha.end()); p++, q++) {
+ if (p->T->IsStopped()) {
+ q->fd = 0;
+ q->events = 0;
+ } else {
+ q->fd = p->ha->GetHandle();
+ q->events = (p->flags & W4_READING ? POLLIN : 0) | (p->flags & W4_WRITING ? POLLOUT : 0);
+ }
+ }
+
+ r = poll(ufsd, nfds, -1);
+#else
+ FD_ZERO(readfds);
+ FD_ZERO(writefds);
+ FD_ZERO(exceptfds);
+
+ highest = -1;
+ for (p = w4ha.begin(); p && (p != w4ha.end()); p++) {
+ if (p->T->IsStopped()) continue;
+ if (p->flags & W4_READING) {
+ FD_SET(p->ha->GetHandle(), readfds);
+ }
+ if (p->flags & W4_WRITING) {
+ FD_SET(p->ha->GetHandle(), writefds);
+ }
+ FD_SET(p->ha->GetHandle(), exceptfds);
+ }
+
+ r = select(highest + 1, &readfds, &writefds, &exceptfds, NULL);
+#endif
+ if (r == -1) {
+ throw GeneralException(String("Error during poll: ") + strerror(errno));
+ } else if (r == 0) {
+ // timeout...
+ } else {
+ int fd;
+#ifdef USE_POLL
+ struct pollfd * q;
+ int i;
+ for (q = ufsd, i = 0; i < nfds; i++, q++) {
+
+ if (q->revents & POLLNVAL) {
+ throw GeneralException(String("Error with poll, handle ") + q->fd + " invalid.");
+ }
+
+ if (q->revents & POLLERR) {
+ throw GeneralException(String("Error condition whith poll, handle ") + q->fd);
+ }
+
+ if (q->revents & POLLHUP) {
+ cerr << "Handle " << q->fd << " hung up.";
+ // What should I do now?
+ }
+
+ fd = q->fd;
+ if (q->revents & (POLLIN | POLLOUT)) {
+#else
+ /* Later perhaps... Let's use poll for now.
+ The following is independant of the use of select or poll.
+ Just have to set 'fd' to the changed handle. Two '{' to open with
+ the first as the loop through the handles and the second with
+ the test "if handle has changed" */
+#endif
+ // We have to look into the handle structure now...
+ for (vector<w4ha_t>::iterator p = w4ha.begin(); p && (p != w4ha.end()); p++) {
+ if ((p->ha->GetHandle() == fd) && (!p->T->IsStopped())) {
+ // We've got one, launch it.
+ bool erased;
+
+ erased = false;
+ p->T->Run();
+
+ if (p->T->GetState() == TASK_DONE) {
+ // This task died, remove it.
+ TaskList_t::iterator q = FindTask(p->T);
+ if (q) {
+ TaskList.erase(q);
+ number--;
+ if (p->T->HasToClean()) {
+ delete p->T;
+ } else {
+ Zombies.push_back(p->T);
+ }
+ w4ha.erase(p);
+ p--;
+ erased = true;
+ } else {
+ // Hu-ho, something wrong...
+ throw GeneralException("TaskMan: internal error (task not found)");
+ }
+ }
+
+ if (!erased && !(p->flags & W4_STICKY)) {
+ w4ha.erase(p);
+ p--;
+ }
+ }
+ }
+ }
+ }
+ }
+#ifdef USE_POLL
+ free((void *) ufsd);
+#endif
+ }
+
+ int no_zombies;
+ no_zombies = 0;
+
+ while (!no_zombies) {
+ no_zombies = 1;
+ while (Zombies.size()) {
+ Task * t = Zombies[0], * o;
+
+ if (!t) {
+ cerr << "!?!?!? We have t = NULL ?!?!?! WTF\n";
+ break;
+ }
+
+ if ((o = t->WaitedBy())) {
+ o->Run();
+
+ if (o->GetState() == TASK_DONE) {
+ TaskList_t::iterator f = FindTask(o);
+ if (!f) {
+ throw GeneralException("TaskMan: internal error (task not found)");
+ }
+ TaskList.erase(f);
+ number--;
+ if (o->HasToClean()) {
+ delete o;
+ } else {
+ Zombies.push_back(o);
+ no_zombies = 0;
+ }
+ }
+ } else {
+ delete t;
+ }
+ Zombies.erase(Zombies.begin());
+ }
+ }
+ }
}