diff --git a/api/boinc_api.C b/api/boinc_api.C
index 056e38192a..0ec32f88ec 100644
--- a/api/boinc_api.C
+++ b/api/boinc_api.C
@@ -58,12 +58,24 @@ using namespace std;
#include "app_ipc.h"
#include "boinc_api.h"
-static APP_INIT_DATA aid;
-APP_CLIENT_SHM *app_client_shm;
+// The BOINC API communicates CPU time and fraction done to the core client.
+// Currently this is done using a timer.
+// Remember that the processing of a result can be divided
+// into multiple "episodes" (executions of the app),
+// each of which resumes from the checkpointed state of the previous episode.
+// Unless otherwise noted, "CPU time" refers to the sum over all episodes
+// (not counting the part after the last checkpoint in an episode).
-static double timer_period = 1.0/50.0; // 50 Hz timer
+static APP_INIT_DATA aid;
+APP_CLIENT_SHM *app_client_shm;
+static double timer_period = 1.0; // period of API timer
+ // This determines the resolution of fraction done and CPU time reporting
+ // to the core client, and of checkpoint enabling.
+ // It doesn't influence graphics, so 1 sec is enough.
static double time_until_checkpoint;
+ // countdown timer until enable checkpoint
static double time_until_fraction_done_update;
+ // countdown timer until report fraction done to core
static double fraction_done;
static double last_checkpoint_cpu_time;
static bool ready_to_checkpoint = false;
@@ -84,24 +96,16 @@ HANDLE worker_thread_handle;
MMRESULT timer_id;
#endif
-
-//
-// Forward declare implementation functions.
-//
-static void setup_shared_mem();
+static int setup_shared_mem();
static void cleanup_shared_mem();
-static int update_app_progress(double frac_done, double cpu_t, double cp_cpu_t, double ws_t);
+static int update_app_progress(double cpu_t, double cp_cpu_t, double ws_t);
static int set_timer(double period);
-// Standard BOINC APIs
-//
-
int boinc_init(bool standalone_ /* = false */) {
FILE* f;
int retval;
#ifdef _WIN32
-
DuplicateHandle(
GetCurrentProcess(),
GetCurrentThread(),
@@ -111,29 +115,30 @@ int boinc_init(bool standalone_ /* = false */) {
FALSE,
DUPLICATE_SAME_ACCESS
);
-
#endif
- // Store startup mode for later use.
standalone = standalone_;
- // Parse initial data file.
retval = boinc_parse_init_data_file();
if (retval) return retval;
+ retval = setup_shared_mem();
+ if (retval) {
+ standalone = true;
+ }
+
// copy the WU CPU time to a separate var,
// since we may reread the structure again later.
//
initial_wu_cpu_time = aid.wu_cpu_time;
- if (boinc_file_exists(FD_INIT_FILE)) {
- f = boinc_fopen(FD_INIT_FILE, "r");
- if (f) {
- parse_fd_init_file(f);
- fclose(f);
- }
+ f = boinc_fopen(FD_INIT_FILE, "r");
+ if (f) {
+ parse_fd_init_file(f);
+ fclose(f);
}
+ fraction_done = -1;
time_until_checkpoint = aid.checkpoint_period;
last_checkpoint_cpu_time = aid.wu_cpu_time;
time_until_fraction_done_update = aid.fraction_done_update_period;
@@ -141,7 +146,6 @@ int boinc_init(bool standalone_ /* = false */) {
last_wu_cpu_time = aid.wu_cpu_time;
set_timer(timer_period);
- setup_shared_mem();
return 0;
}
@@ -152,7 +156,7 @@ int boinc_finish(int status) {
boinc_thread_cpu_time(last_checkpoint_cpu_time, cur_mem);
last_checkpoint_cpu_time += aid.wu_cpu_time;
- update_app_progress(fraction_done, last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem);
+ update_app_progress(last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem);
#ifdef _WIN32
// Stop the timer
timeKillEvent(timer_id);
@@ -220,19 +224,23 @@ int boinc_parse_init_data_file() {
// the current CPU time and fraction done
//
static int update_app_progress(
- double frac_done, double cpu_t, double cp_cpu_t, double ws_t
+ double cpu_t, double cp_cpu_t, double ws_t
) {
- char msg_buf[SHM_SEG_SIZE];
+ char msg_buf[SHM_SEG_SIZE], buf[256];
if (!app_client_shm) return 0;
sprintf(msg_buf,
- "%2.8f\n"
"%10.4f\n"
"%.15e\n"
"%f\n",
- frac_done, cpu_t, cp_cpu_t, ws_t
+ cpu_t, cp_cpu_t, ws_t
);
+ if (fraction_done >= 0) {
+ sprintf(buf, "%2.8f\n", fraction_done);
+ strcat(msg_buf, buf);
+ }
+
if (have_new_trickle_up) {
strcat(msg_buf, "\n");
have_new_trickle_up = false;
@@ -338,7 +346,7 @@ static void on_timer(int a) {
double cur_mem;
boinc_worker_thread_cpu_time(cur_cpu, cur_mem);
last_wu_cpu_time = cur_cpu + initial_wu_cpu_time;
- update_app_progress(fraction_done, last_wu_cpu_time, last_checkpoint_cpu_time, cur_mem);
+ update_app_progress(last_wu_cpu_time, last_checkpoint_cpu_time, cur_mem);
time_until_fraction_done_update = aid.fraction_done_update_period;
}
}
@@ -387,10 +395,10 @@ static int set_timer(double period) {
return retval;
}
-static void setup_shared_mem() {
+static int setup_shared_mem() {
if (standalone) {
fprintf(stderr, "Standalone mode, so not using shared memory.\n");
- return;
+ return 0;
}
app_client_shm = new APP_CLIENT_SHM;
@@ -402,16 +410,14 @@ static void setup_shared_mem() {
delete app_client_shm;
app_client_shm = NULL;
}
-#endif
-
-#ifdef HAVE_SYS_SHM_H
-#ifdef HAVE_SYS_IPC_H
+#else
if (attach_shmem(aid.shm_key, (void**)&app_client_shm->shm)) {
delete app_client_shm;
app_client_shm = NULL;
}
#endif
-#endif
+ if (app_client_shm == NULL) return -1;
+ return 0;
}
static void cleanup_shared_mem() {
@@ -419,18 +425,13 @@ static void cleanup_shared_mem() {
#ifdef _WIN32
detach_shmem(hSharedMem, app_client_shm->shm);
-#endif
-
-#ifdef HAVE_SYS_SHM_H
-#ifdef HAVE_SYS_IPC_H
+#else
detach_shmem(app_client_shm->shm);
-#endif
#endif
delete app_client_shm;
app_client_shm = NULL;
}
-
int boinc_send_trickle_up(char* p) {
FILE* f = boinc_fopen(TRICKLE_UP_FILENAME, "wb");
if (!f) return ERR_FOPEN;
@@ -441,8 +442,6 @@ int boinc_send_trickle_up(char* p) {
return 0;
}
-
-
bool boinc_time_to_checkpoint() {
#ifdef _WIN32
DWORD eventState;
@@ -471,7 +470,7 @@ int boinc_checkpoint_completed() {
boinc_thread_cpu_time(cur_cpu, cur_mem);
last_wu_cpu_time = cur_cpu + aid.wu_cpu_time;
last_checkpoint_cpu_time = last_wu_cpu_time;
- update_app_progress(fraction_done, last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem);
+ update_app_progress(last_checkpoint_cpu_time, last_checkpoint_cpu_time, cur_mem);
ready_to_checkpoint = false;
time_until_checkpoint = aid.checkpoint_period;
diff --git a/checkin_notes b/checkin_notes
index 82dbba83b1..357bf498ad 100755
--- a/checkin_notes
+++ b/checkin_notes
@@ -12441,8 +12441,30 @@ David May 20 2004
cs_benchmark.C
David May 21 2004
- - changed variable names in app.C:
+ - API: changed timer period from 50 Hz to 1 Hz.
+ This timer is used only for reporting progress and CPU,
+ not for doing graphics, to 1 Hz is enough
+ - API: if setup_shared_mem() returns error, set standalone = true.
+ This means that if you run an app standalone,
+ it will be detected automatically,
+ so no need for command-line args or even
+ standalone argument to boinc_init()
+ (but leave that arg in for now)
+ - API: initialize fraction_done to -1,
+ and only report it to core client if >= 0
+ (i.e. don't report it unless app specifies it)
+ - API: removed
+ #ifdef HAVE_SYS_SHM_H
+ #ifdef HAVE_SYS_IPC_H
+ around calls to attach_shmem in non-Win case.
+ This not an appropriate place for these ifdefs.
+ - core client: ACTIVE_TASK_SET::check_app_exited():
+ skip tasks in state PROCESS_IN_LIMBO.
+ This avoid core client spinning when apps misbehave.
+ - core client: changed variable names in app.C:
starting_cpu_time -> episode_start_cpu_time
+ api/
+ boinc_api.C
client/
app.C,h
diff --git a/client/app.C b/client/app.C
index 26a1378109..a78b3a797c 100644
--- a/client/app.C
+++ b/client/app.C
@@ -662,6 +662,7 @@ bool ACTIVE_TASK_SET::check_app_exited() {
for (i=0; istate == PROCESS_IN_LIMBO) continue;
if (GetExitCodeProcess(atp->pid_handle, &exit_code)) {
if (exit_code != STILL_ACTIVE) {
scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): Process exited with code %d\n", exit_code);