- wrapper: add "daemon" feature.

A task descriptor may contain <daemon>.
    Daemons are started before regular tasks,
    run concurrently with them, and are killed on exit.


svn path=/trunk/boinc/; revision=23101
This commit is contained in:
David Anderson 2011-02-24 21:39:07 +00:00
parent f30812355d
commit d331ca86ed
2 changed files with 66 additions and 17 deletions

View File

@ -1125,3 +1125,12 @@ David 24 Feb 2011
html/user/ html/user/
friend.php friend.php
David 24 Feb 2011
- wrapper: add "daemon" feature.
A task descriptor may contain <daemon>.
Daemons are started before regular tasks,
run concurrently with them, and are killed on exit.
samples/wrapper/
wrapper.cpp

View File

@ -74,6 +74,9 @@ struct TASK {
string command_line; string command_line;
double weight; double weight;
// contribution of this task to overall fraction done // contribution of this task to overall fraction done
bool is_daemon;
// dynamic stuff follows
double final_cpu_time; double final_cpu_time;
double starting_cpu; double starting_cpu;
// how much CPU time was used by tasks before this in the job file // how much CPU time was used by tasks before this in the job file
@ -164,6 +167,7 @@ struct TASK {
}; };
vector<TASK> tasks; vector<TASK> tasks;
vector<TASK> daemons;
APP_INIT_DATA aid; APP_INIT_DATA aid;
bool graphics = false; bool graphics = false;
@ -193,6 +197,7 @@ int TASK::parse(XML_PARSER& xp) {
weight = 1; weight = 1;
final_cpu_time = 0; final_cpu_time = 0;
stat_first = true; stat_first = true;
pid = 0;
while (!xp.get(tag, sizeof(tag), is_tag)) { while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!is_tag) { if (!is_tag) {
@ -226,6 +231,7 @@ int TASK::parse(XML_PARSER& xp) {
else if (xp.parse_string(tag, "checkpoint_filename", checkpoint_filename)) continue; else if (xp.parse_string(tag, "checkpoint_filename", checkpoint_filename)) continue;
else if (xp.parse_string(tag, "fraction_done_filename", fraction_done_filename)) continue; else if (xp.parse_string(tag, "fraction_done_filename", fraction_done_filename)) continue;
else if (xp.parse_double(tag, "weight", weight)) continue; else if (xp.parse_double(tag, "weight", weight)) continue;
else if (xp.parse_bool(tag, "daemon", is_daemon)) continue;
} }
return ERR_XML_PARSE; return ERR_XML_PARSE;
} }
@ -264,7 +270,11 @@ int parse_job_file() {
TASK task; TASK task;
int retval = task.parse(xp); int retval = task.parse(xp);
if (!retval) { if (!retval) {
tasks.push_back(task); if (task.is_daemon) {
daemons.push_back(task);
} else {
tasks.push_back(task);
}
} }
} }
} }
@ -272,6 +282,25 @@ int parse_job_file() {
return ERR_XML_PARSE; return ERR_XML_PARSE;
} }
int start_daemons(int argc, char** argv) {
for (unsigned int i=0; i<daemons.size(); i++) {
TASK& task = daemons[i];
int retval = task.run(argc, argv);
if (retval) return retval;
}
}
void kill_daemons() {
vector<int> daemon_pids;
for (unsigned int i=0; i<daemons.size(); i++) {
TASK& task = daemons[i];
if (task.pid) {
daemon_pids.push_back(task.pid);
}
}
kill_all(daemon_pids);
}
#ifdef _WIN32 #ifdef _WIN32
// CreateProcess() takes HANDLEs for the stdin/stdout. // CreateProcess() takes HANDLEs for the stdin/stdout.
// We need to use CreateFile() to get them. Ugh. // We need to use CreateFile() to get them. Ugh.
@ -478,7 +507,6 @@ int TASK::run(int argct, char** argvt) {
} else { } else {
retval = execv(app_path, argv); retval = execv(app_path, argv);
} }
if (env_vars) delete [] env_vars; // never really gets here after the execve
perror("execv() failed: "); perror("execv() failed: ");
exit(ERR_EXEC); exit(ERR_EXEC);
} // pid = 0 i.e. child proc of the fork } // pid = 0 i.e. child proc of the fork
@ -512,7 +540,10 @@ bool TASK::poll(int& status) {
return false; return false;
} }
// kill this task (gracefully if possible) and any other subprocesses
//
void TASK::kill() { void TASK::kill() {
kill_daemons();
#ifdef _WIN32 #ifdef _WIN32
// on Win, just kill all our descendants // on Win, just kill all our descendants
// //
@ -556,6 +587,21 @@ void TASK::resume() {
suspended = false; suspended = false;
} }
double TASK::cpu_time() {
#ifdef _WIN32
double x;
int retval = boinc_process_cpu_time(pid_handle, x);
if (retval) return wall_cpu_time;
return x;
#elif defined(__APPLE__)
// There's no easy way to get another process's CPU time in Mac OS X
//
return wall_cpu_time;
#else
return linux_cpu_time(pid);
#endif
}
void poll_boinc_messages(TASK& task) { void poll_boinc_messages(TASK& task) {
BOINC_STATUS status; BOINC_STATUS status;
boinc_get_status(&status); boinc_get_status(&status);
@ -582,21 +628,6 @@ void poll_boinc_messages(TASK& task) {
} }
} }
double TASK::cpu_time() {
#ifdef _WIN32
double x;
int retval = boinc_process_cpu_time(pid_handle, x);
if (retval) return wall_cpu_time;
return x;
#elif defined(__APPLE__)
// There's no easy way to get another process's CPU time in Mac OS X
//
return wall_cpu_time;
#else
return linux_cpu_time(pid);
#endif
}
void send_status_message( void send_status_message(
TASK& task, double frac_done, double checkpoint_cpu_time TASK& task, double frac_done, double checkpoint_cpu_time
) { ) {
@ -679,6 +710,13 @@ int main(int argc, char** argv) {
total_weight += tasks[i].weight; total_weight += tasks[i].weight;
} }
retval = start_daemons(argc, argv);
if (retval) {
fprintf(stderr, "start_daemons(): %d\n", retval);
kill_daemons();
boinc_finish(retval);
}
// loop over tasks // loop over tasks
// //
for (i=0; i<tasks.size(); i++) { for (i=0; i<tasks.size(); i++) {
@ -705,6 +743,7 @@ int main(int argc, char** argv) {
// as recoverable, and restart us. // as recoverable, and restart us.
// We don't want this, so return an 8-bit error code. // We don't want this, so return an 8-bit error code.
// //
kill_daemons();
boinc_finish(EXIT_CHILD_FAILED); boinc_finish(EXIT_CHILD_FAILED);
} }
break; break;
@ -723,6 +762,7 @@ int main(int argc, char** argv) {
write_checkpoint(i+1, checkpoint_cpu_time); write_checkpoint(i+1, checkpoint_cpu_time);
weight_completed += task.weight; weight_completed += task.weight;
} }
kill_daemons();
boinc_finish(0); boinc_finish(0);
} }