diff --git a/checkin_notes b/checkin_notes
index f30126297f..a4a861f5ac 100644
--- a/checkin_notes
+++ b/checkin_notes
@@ -355,3 +355,10 @@ David 23 May 2007
uc2.h
uppercase/
Makefile
+
+David 28 May 2007
+ - Wrapper can handle multiple tasks
+
+ wrapper/
+ job.xml
+ wrapper.C
diff --git a/wrapper/job.xml b/wrapper/job.xml
index 5cd5b164c5..585f80aa5c 100644
--- a/wrapper/job.xml
+++ b/wrapper/job.xml
@@ -5,4 +5,10 @@
stdout
10
+
+ worker2
+ stdin2
+ stdout2
+ 10
+
diff --git a/wrapper/wrapper.C b/wrapper/wrapper.C
index ded71fe2c7..f22ad8ef67 100644
--- a/wrapper/wrapper.C
+++ b/wrapper/wrapper.C
@@ -53,6 +53,9 @@
#include "util.h"
#include "error_numbers.h"
+#define JOB_FILENAME "job.xml"
+#define CHECKPOINT_FILENAME "checkpoint.txt"
+
using std::vector;
using std::string;
@@ -62,6 +65,8 @@ struct TASK {
string stdout_filename;
string stderr_filename;
string command_line;
+ double final_cpu_time;
+ double starting_cpu;
#ifdef _WIN32
HANDLE pid_handle;
HANDLE thread_handle;
@@ -85,6 +90,7 @@ int TASK::parse(XML_PARSER& xp) {
char tag[1024];
bool is_tag;
+ final_cpu_time = 0;
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!is_tag) {
fprintf(stderr, "SCHED_CONFIG::parse(): unexpected text %s\n", tag);
@@ -107,9 +113,12 @@ int parse_job_file() {
char tag[1024], buf[256];
bool is_tag;
- boinc_resolve_filename("job.xml", buf, 1024);
+ boinc_resolve_filename(JOB_FILENAME, buf, 1024);
FILE* f = boinc_fopen(buf, "r");
- if (!f) return ERR_FOPEN;
+ if (!f) {
+ fprintf(stderr, "can't open job file %s\n", buf);
+ return ERR_FOPEN;
+ }
mf.init_file(f);
XML_PARSER xp(&mf);
@@ -284,6 +293,7 @@ int TASK::run(int argct, char** argvt) {
argv[0] = buf;
strlcpy(arglist, command_line.c_str(), sizeof(arglist));
argc = parse_command_line(arglist, argv+1);
+ fprintf(stderr, "wrapper: running %s (%s)\n", buf, arglist);
retval = execv(buf, argv);
exit(ERR_EXEC);
}
@@ -297,14 +307,17 @@ bool TASK::poll(int& status) {
if (GetExitCodeProcess(pid_handle, &exit_code)) {
if (exit_code != STILL_ACTIVE) {
status = exit_code;
+ final_cpu_time = cpu_time();
return true;
}
}
#else
int wpid, stat;
- wpid = waitpid(pid, &stat, WNOHANG);
+ struct rusage ru;
+
+ wpid = wait4(pid, &status, WNOHANG, &ru);
if (wpid) {
- status = stat;
+ final_cpu_time = (float)ru.ru_utime.tv_sec + ((float)ru.ru_utime.tv_usec)/1e+6;
return true;
}
#endif
@@ -369,9 +382,10 @@ double TASK::cpu_time() {
ULARGE_INTEGER tKernel, tUser;
LONGLONG totTime;
- GetProcessTimes(
+ int retval = GetProcessTimes(
pid_handle, &creation_time, &exit_time, &kernel_time, &user_time
);
+ if (retval == 0) return 0;
tKernel.LowPart = kernel_time.dwLowDateTime;
tKernel.HighPart = kernel_time.dwHighDateTime;
@@ -379,20 +393,46 @@ double TASK::cpu_time() {
tUser.HighPart = user_time.dwHighDateTime;
totTime = tKernel.QuadPart + tUser.QuadPart;
- double cpu = totTime / 1.e7;
- return cpu;
+ return totTime / 1.e7;
#else
- return linux_cpu_time(pid);
+ return linux_cpu_time(pid);
#endif
}
-void send_status_message(TASK& task) {
- boinc_report_app_status(task.cpu_time(), 0, 0);
+void send_status_message(TASK& task, double frac_done) {
+ boinc_report_app_status(task.cpu_time(), task.starting_cpu, frac_done);
+}
+
+// Support for multiple tasks.
+// We keep a checkpoint file that says how many tasks we've completed
+// and how much CPU time has been used so far
+//
+void write_checkpoint(int ntasks, double cpu) {
+ FILE* f = fopen(CHECKPOINT_FILENAME, "w");
+ if (!f) return;
+ fprintf(f, "%d %f\n", ntasks, cpu);
+ fclose(f);
+}
+
+void read_checkpoint(int& ntasks, double& cpu) {
+ int nt;
+ double c;
+
+ ntasks = 0;
+ cpu = 0;
+ FILE* f = fopen(CHECKPOINT_FILENAME, "r");
+ if (!f) return;
+ int n = fscanf(f, "%d %lf", &nt, &c);
+ if (n != 2) return;
+ ntasks = nt;
+ cpu = c;
}
int main(int argc, char** argv) {
BOINC_OPTIONS options;
int retval;
+ int ntasks;
+ double cpu;
boinc_init_diagnostics(
BOINC_DIAG_DUMPCALLSTACKENABLED
@@ -413,33 +453,42 @@ int main(int argc, char** argv) {
fprintf(stderr, "can't parse job file: %d\n", retval);
boinc_finish(retval);
}
- if (tasks.size() != 1) {
- fprintf(stderr, "multiple tasks not supported\n");
- boinc_finish(1);
- }
parse_state_file();
- TASK& task = tasks[0];
+ read_checkpoint(ntasks, cpu);
+ if (ntasks > tasks.size()) {
+ fprintf(stderr, "Checkpoint file: ntasks %d too large\n", ntasks);
+ boinc_finish(1);
+ }
+ for (unsigned int i=ntasks; i