mirror of https://github.com/BOINC/boinc.git
parent
ae9cfdebb0
commit
ac1f13f2a8
|
@ -15,15 +15,17 @@ CC = @CC@ $(CFLAGS)
|
|||
|
||||
PROGS = api_app api_test
|
||||
|
||||
all: $(PROGS)
|
||||
#all: $(PROGS)
|
||||
all: mfile.o boinc_api.o
|
||||
|
||||
APP_OBJS = \
|
||||
api_app.o \
|
||||
api.o \
|
||||
mfile.o \
|
||||
boinc_api.o \
|
||||
../lib/parse.o
|
||||
|
||||
TEST_OBJS = \
|
||||
api.o \
|
||||
boinc_api.o \
|
||||
api_test.o \
|
||||
../lib/parse.o
|
||||
|
||||
|
|
367
api/api.C
367
api/api.C
|
@ -1,367 +0,0 @@
|
|||
// The contents of this file are subject to the Mozilla Public License
|
||||
// Version 1.0 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS"
|
||||
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing rights and limitations
|
||||
// under the License.
|
||||
//
|
||||
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
||||
//
|
||||
// The Initial Developer of the Original Code is the SETI@home project.
|
||||
// Portions created by the SETI@home project are Copyright (C) 2002
|
||||
// University of California at Berkeley. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
//
|
||||
|
||||
#include "windows_cpp.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include "parse.h"
|
||||
#include "api.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
int MFILE::open(char* path, char* mode) {
|
||||
buf = 0;
|
||||
len = 0;
|
||||
f = fopen(path, mode);
|
||||
if (!f) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFILE::printf(char* format, ...) {
|
||||
va_list ap;
|
||||
char buf2[4096];
|
||||
int n, k;
|
||||
|
||||
va_start(ap, format);
|
||||
k = vsprintf(buf2, format, ap);
|
||||
va_end(ap);
|
||||
n = strlen(buf2);
|
||||
buf = (char*)realloc(buf, len+n);
|
||||
strncpy(buf+len, buf2, n);
|
||||
len += n;
|
||||
return k;
|
||||
}
|
||||
|
||||
size_t MFILE::write(const void *ptr,size_t size,size_t nitems) {
|
||||
buf = (char *)realloc( buf, len+(size*nitems) );
|
||||
memcpy( buf+len, ptr, size*nitems );
|
||||
len += size*nitems;
|
||||
return nitems;
|
||||
}
|
||||
|
||||
int MFILE::_putchar(char c) {
|
||||
buf = (char*)realloc(buf, len+1);
|
||||
buf[len] = c;
|
||||
len++;
|
||||
return c;
|
||||
}
|
||||
|
||||
int MFILE::puts(char* p) {
|
||||
int n = strlen(p);
|
||||
buf = (char*)realloc(buf, len+n);
|
||||
strncpy(buf+len, p, n);
|
||||
len += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFILE::close() {
|
||||
fwrite(buf, 1, len, f);
|
||||
free(buf);
|
||||
buf = 0;
|
||||
return fclose(f);
|
||||
}
|
||||
|
||||
int MFILE::flush() {
|
||||
fwrite(buf, 1, len, f);
|
||||
len = 0;
|
||||
return fflush(f);
|
||||
}
|
||||
|
||||
static void write_core_file(FILE* f, APP_IN& ai) {
|
||||
fprintf(f,
|
||||
"<graphics_xsize>%d</graphics_xsize>\n"
|
||||
"<graphics_ysize>%d</graphics_ysize>\n"
|
||||
"<graphics_refresh_period>%f</graphics_refresh_period>\n"
|
||||
"<checkpoint_period>%f</checkpoint_period>\n"
|
||||
"<poll_period>%f</poll_period>\n"
|
||||
"<checkpoint_period>%f</checkpoint_period>\n"
|
||||
"<cpu_time>%f</cpu_time>\n",
|
||||
ai.graphics.xsize,
|
||||
ai.graphics.ysize,
|
||||
ai.graphics.refresh_period,
|
||||
ai.checkpoint_period,
|
||||
ai.poll_period,
|
||||
ai.checkpoint_period,
|
||||
ai.cpu_time
|
||||
);
|
||||
}
|
||||
|
||||
static void parse_core_file(FILE* f, APP_IN& ai) {
|
||||
char buf[256];
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (match_tag(buf, "<app_specific_prefs>")) {
|
||||
strcpy(ai.app_preferences, "");
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (match_tag(buf, "</app_specific_prefs>")) break;
|
||||
strcat(ai.app_preferences, buf);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (parse_int(buf, "<graphics_xsize>", ai.graphics.xsize)) continue;
|
||||
else if (parse_int(buf, "<graphics_ysize>", ai.graphics.ysize)) continue;
|
||||
else if (parse_double(buf, "<graphics_refresh_period>", ai.graphics.refresh_period)) continue;
|
||||
else if (parse_double(buf, "<checkpoint_period>", ai.checkpoint_period)) continue;
|
||||
else if (parse_double(buf, "<poll_period>", ai.poll_period)) continue;
|
||||
else if (parse_double(buf, "<checkpoint_period>", ai.checkpoint_period)) continue;
|
||||
else if (parse_double(buf, "<cpu_time>", ai.cpu_time)) continue;
|
||||
else fprintf(stderr, "parse_core_file: unrecognized %s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_app_file(FILE* f, APP_OUT& ao) {
|
||||
fprintf(f,
|
||||
"<percent_done>%f</percent_done>\n"
|
||||
"<cpu_time_at_checkpoint>%f</cpu_time_at_checkpoint>\n",
|
||||
ao.percent_done,
|
||||
ao.cpu_time_at_checkpoint
|
||||
);
|
||||
if (ao.checkpointed) {
|
||||
fprintf(f, "<checkpointed/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_app_file(FILE* f, APP_OUT& ao) {
|
||||
char buf[256];
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (parse_double(buf, "<percent_done>", ao.percent_done)) continue;
|
||||
else if (parse_double(buf, "<cpu_time_at_checkpoint>",
|
||||
ao.cpu_time_at_checkpoint)) continue;
|
||||
else if (match_tag(buf, "<checkpointed/>")) ao.checkpointed = true;
|
||||
else fprintf(stderr, "parse_app_file: unrecognized %s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_init_file(FILE* f, char *file_name, int fdesc, int input_file ) {
|
||||
if( input_file ) {
|
||||
fprintf( f, "<fdesc_dup_infile>%s</fdesc_dup_infile>\n", file_name );
|
||||
fprintf( f, "<fdesc_dup_innum>%d</fdesc_dup_innum>\n", fdesc );
|
||||
} else {
|
||||
fprintf( f, "<fdesc_dup_outfile>%s</fdesc_dup_outfile>\n", file_name );
|
||||
fprintf( f, "<fdesc_dup_outnum>%d</fdesc_dup_outnum>\n", fdesc );
|
||||
}
|
||||
}
|
||||
|
||||
void parse_init_file(FILE* f) {
|
||||
char buf[256],filename[256];
|
||||
int filedesc,fd,retval;
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (parse_str(buf, "<fdesc_dup_infile>", filename)) {
|
||||
if (fgets(buf, 256, f)) {
|
||||
if (parse_int(buf, "<fdesc_dup_innum>", filedesc)) {
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd != filedesc) {
|
||||
retval = dup2(fd, filedesc);
|
||||
if (retval < 0) {
|
||||
fprintf(stderr, "dup2 %d %d returned %d\n", fd, filedesc, retval);
|
||||
exit(retval);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (parse_str(buf, "<fdesc_dup_outfile>", filename)) {
|
||||
if (fgets(buf, 256, f)) {
|
||||
if (parse_int(buf, "<fdesc_dup_outnum>", filedesc)) {
|
||||
fd = open(filename, O_WRONLY|O_CREAT, 0660);
|
||||
if (fd != filedesc) {
|
||||
retval = dup2(fd, filedesc);
|
||||
if (retval < 0) {
|
||||
fprintf(stderr, "dup2 %d %d returned %d\n", fd, filedesc, retval);
|
||||
exit(retval);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else fprintf(stderr, "parse_init_file: unrecognized %s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read the BOINC_INIT_FILE and CORE_TO_APP_FILE files
|
||||
// and performs the necessary initialization
|
||||
//
|
||||
void boinc_init(APP_IN& ai) {
|
||||
FILE* f;
|
||||
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
f = fopen(CORE_TO_APP_FILE, "r");
|
||||
if (f) {
|
||||
parse_core_file(f, ai);
|
||||
unlink(CORE_TO_APP_FILE);
|
||||
}
|
||||
|
||||
f = fopen( BOINC_INIT_FILE, "r" );
|
||||
if (f) {
|
||||
parse_init_file(f);
|
||||
unlink(BOINC_INIT_FILE);
|
||||
}
|
||||
set_timer(ai.checkpoint_period);
|
||||
}
|
||||
|
||||
void boinc_poll(APP_IN& ai, APP_OUT& ao) {
|
||||
FILE* f;
|
||||
|
||||
f = fopen("_app_temp", "w");
|
||||
write_app_file(f, ao);
|
||||
rename("_app_temp", APP_TO_CORE_FILE);
|
||||
}
|
||||
|
||||
// resolve XML soft links
|
||||
//
|
||||
int boinc_resolve_link(char *file_name, char *resolved_name) {
|
||||
FILE *fp;
|
||||
char buf[512];
|
||||
|
||||
// Open the file and load the first line
|
||||
fp = fopen( file_name, "r" );
|
||||
if (!fp) {
|
||||
strcpy( resolved_name, file_name );
|
||||
return -1;
|
||||
}
|
||||
rewind( fp );
|
||||
fgets(buf, 512, fp);
|
||||
fclose( fp );
|
||||
|
||||
// If it's the <soft_link> XML tag, return it's value,
|
||||
// otherwise, return the original file name
|
||||
//
|
||||
if( !parse_str( buf, "<soft_link>", resolved_name ) ) {
|
||||
strcpy( resolved_name, file_name );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _checkpoint = false;
|
||||
|
||||
double get_cpu_time() {
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
int retval, pid = getpid();
|
||||
struct rusage ru;
|
||||
retval = getrusage(RUSAGE_SELF, &ru);
|
||||
if(retval) fprintf(stderr, "error: could not get cpu time for %d\n", pid);
|
||||
return (double)ru.ru_utime.tv_sec + (
|
||||
((double)ru.ru_utime.tv_usec) / ((double)1000000.0)
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int checkpoint_completed(APP_OUT &ao) {
|
||||
int retval;
|
||||
FILE *f = fopen(APP_TO_CORE_FILE, "w");
|
||||
ao.cpu_time_at_checkpoint = get_cpu_time();
|
||||
write_app_file(f, ao);
|
||||
retval = fflush(f);
|
||||
if(retval) {
|
||||
fprintf(stderr,"error: could not flush %s\n", APP_TO_CORE_FILE);
|
||||
return retval;
|
||||
}
|
||||
retval = fclose(f);
|
||||
if(retval) {
|
||||
fprintf(stderr, "error: could not close %s\n", APP_TO_CORE_FILE);
|
||||
return retval;
|
||||
}
|
||||
_checkpoint = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_completed(APP_OUT& ao) {
|
||||
int retval;
|
||||
FILE* f=fopen(APP_TO_CORE_FILE, "w");
|
||||
ao.cpu_time_at_checkpoint = get_cpu_time();
|
||||
write_app_file(f, ao);
|
||||
retval=fflush(f);
|
||||
if(retval) {
|
||||
fprintf(stderr, "error: could not flush %s\n", APP_TO_CORE_FILE);
|
||||
return retval;
|
||||
}
|
||||
retval=fclose(f);
|
||||
if(retval) {
|
||||
fprintf(stderr, "error: could not close %s\n", APP_TO_CORE_FILE);
|
||||
return retval;
|
||||
}
|
||||
_checkpoint = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void CALLBACK on_timer( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) {
|
||||
_checkpoint = true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void on_timer(int a) {
|
||||
_checkpoint = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int set_timer(double period) {
|
||||
int retval=0;
|
||||
if(period<0) {
|
||||
fprintf(stderr, "error: set_timer: negative period\n");
|
||||
return ERR_NEG;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
retval = SetTimer( NULL, 0, (int)(period*1000), on_timer );
|
||||
#endif
|
||||
|
||||
#if HAVE_SIGNAL_H
|
||||
#if HAVE_SYS_TIME_H
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = on_timer;
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGVTALRM, &sa, NULL);
|
||||
itimerval value;
|
||||
value.it_value.tv_sec = (int)period;
|
||||
value.it_value.tv_usec = ((int)(period*1000000))%1000000;
|
||||
value.it_interval = value.it_value;
|
||||
retval = setitimer(ITIMER_VIRTUAL, &value, NULL);
|
||||
#endif
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
117
api/api.h
117
api/api.h
|
@ -1,117 +0,0 @@
|
|||
// The contents of this file are subject to the Mozilla Public License
|
||||
// Version 1.0 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS"
|
||||
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing rights and limitations
|
||||
// under the License.
|
||||
//
|
||||
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
||||
//
|
||||
// The Initial Developer of the Original Code is the SETI@home project.
|
||||
// Portions created by the SETI@home project are Copyright (C) 2002
|
||||
// University of California at Berkeley. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifndef BOINC_API
|
||||
#define BOINC_API
|
||||
|
||||
// MFILE supports a primitive form of checkpointing.
|
||||
// Write all your output (and restart file) to MFILEs.
|
||||
// The output is buffered in memory.
|
||||
// Then close all the MFILEs;
|
||||
// all the buffers will be flushed to disk, almost atomically.
|
||||
|
||||
class MFILE {
|
||||
char* buf;
|
||||
int len;
|
||||
FILE* f;
|
||||
public:
|
||||
int open(char* path, char* mode);
|
||||
int _putchar(char);
|
||||
int puts(char*);
|
||||
int printf(char* format, ...);
|
||||
size_t write(const void *,size_t,size_t);
|
||||
int close();
|
||||
int flush();
|
||||
};
|
||||
|
||||
// An application that wants to be well-behaved should do the following:
|
||||
//
|
||||
// - call boinc_init(APP_IN&) at startup
|
||||
// - call time_to_checkpoint() often.
|
||||
// This is cheap - it returns true if time to checkpoint.
|
||||
// - checkpoint if time_to_checkpoint() returns true
|
||||
// - call checkpoint_completed() when checkpoint is complete
|
||||
// The only member of APP_OUT that needs to be filled in is percent_done
|
||||
// - boinc_poll():
|
||||
// Call this as often as requested by core
|
||||
// - call app_completed() when the application is completed
|
||||
// The only member of APP_OUT that needs to be filled in is percent_done
|
||||
|
||||
struct APP_IN_GRAPHICS {
|
||||
int xsize;
|
||||
int ysize;
|
||||
double refresh_period;
|
||||
char shmem_seg_name[32];
|
||||
};
|
||||
|
||||
struct APP_OUT_GRAPHICS {
|
||||
};
|
||||
|
||||
struct APP_IN {
|
||||
char app_preferences[4096];
|
||||
APP_IN_GRAPHICS graphics;
|
||||
double checkpoint_period; // recommended checkpoint period
|
||||
double poll_period; // recommended poll period
|
||||
double cpu_time; // cpu time from previous sessions
|
||||
};
|
||||
|
||||
struct APP_OUT {
|
||||
double percent_done; //percent of work unit completed
|
||||
double cpu_time_at_checkpoint; //cpu time of current process
|
||||
bool checkpointed; // true iff checkpointed since last call
|
||||
};
|
||||
|
||||
//void write_core_file(FILE* f, APP_IN &ai);
|
||||
//void parse_core_file(FILE* f, APP_IN&);
|
||||
//void write_init_file(FILE* f, char *file_name, int fdesc, int input_file );
|
||||
//void parse_init_file(FILE* f);
|
||||
void boinc_init(APP_IN&);
|
||||
//void parse_app_file(FILE* f, APP_OUT&);
|
||||
//void write_app_file(FILE* f, APP_OUT&);
|
||||
void boinc_poll(APP_IN&, APP_OUT&);
|
||||
double boinc_cpu_time();
|
||||
int boinc_resolve_link(char *file_name, char *resolved_name);
|
||||
|
||||
#define CORE_TO_APP_FILE "core_to_app.xml"
|
||||
#define APP_TO_CORE_FILE "app_to_core.xml"
|
||||
#define BOINC_INIT_FILE "boinc_init.xml"
|
||||
|
||||
//the following are provided for implementation of the checkpoint system
|
||||
int checkpoint_completed(APP_OUT& ao); //call this when checkpoint is completed
|
||||
int app_completed(APP_OUT& ao); //call this when app is completed
|
||||
|
||||
extern bool _checkpoint;
|
||||
#define time_to_checkpoint() _checkpoint
|
||||
int set_timer(double period); //period is seconds spent in process
|
||||
#ifdef _WIN32
|
||||
void CALLBACK on_timer( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
|
||||
#else
|
||||
void on_timer(int not_used); //sets _checkpoint to true
|
||||
#endif
|
||||
double get_cpu_time(); //return cpu time for this process
|
||||
|
||||
#endif
|
|
@ -24,7 +24,7 @@
|
|||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
int recover(char* file, unsigned long int* i);
|
||||
int timer(int secs, int usecs);
|
||||
|
|
|
@ -22,7 +22,7 @@ Contributor(s): See ACKNOWLEDGEMENTS.
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
int get_run_info(double& time, unsigned long int& counter);
|
||||
void run_api_test(char* args);
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
// The contents of this file are subject to the Mozilla Public License
|
||||
// Version 1.0 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS"
|
||||
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing rights and limitations
|
||||
// under the License.
|
||||
//
|
||||
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
||||
//
|
||||
// The Initial Developer of the Original Code is the SETI@home project.
|
||||
// Portions created by the SETI@home project are Copyright (C) 2002
|
||||
// University of California at Berkeley. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
//
|
||||
|
||||
#include "windows_cpp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
#include "boinc_api.h"
|
||||
|
||||
static APP_INIT_DATA aid;
|
||||
static double timer_period = 0.1;
|
||||
static double time_until_checkpoint;
|
||||
static double time_until_fraction_done_update;
|
||||
static double fraction_done;
|
||||
static bool ready_to_checkpoint = false;
|
||||
static bool this_process_active;
|
||||
|
||||
// read the INIT_DATA and FD_INIT files
|
||||
//
|
||||
int boinc_init() {
|
||||
FILE* f;
|
||||
int retval;
|
||||
|
||||
f = fopen(INIT_DATA_FILE, "r");
|
||||
if (!f) return ERR_FOPEN;
|
||||
retval = parse_init_data_file(f, aid);
|
||||
if (retval) return retval;
|
||||
fclose(f);
|
||||
|
||||
f = fopen(FD_INIT_FILE, "r");
|
||||
if (f) {
|
||||
parse_fd_init_file(f);
|
||||
fclose(f);
|
||||
}
|
||||
time_until_checkpoint = aid.checkpoint_period;
|
||||
time_until_fraction_done_update = aid.fraction_done_update_period;
|
||||
this_process_active = true;
|
||||
set_timer(timer_period);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int boinc_finish(int status) {
|
||||
write_checkpoint_cpu_file(boinc_cpu_time());
|
||||
exit(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// resolve XML soft links
|
||||
//
|
||||
int boinc_resolve_filename(char *virtual_name, char *physical_name) {
|
||||
FILE *fp;
|
||||
char buf[512];
|
||||
|
||||
strcpy( physical_name, virtual_name );
|
||||
|
||||
// Open the file and load the first line
|
||||
fp = fopen(virtual_name, "r");
|
||||
if (!fp) return 0;
|
||||
|
||||
fgets(buf, 512, fp);
|
||||
fclose(fp);
|
||||
|
||||
// If it's the <soft_link> XML tag, return its value,
|
||||
// otherwise, return the original file name
|
||||
//
|
||||
parse_str( buf, "<soft_link>", physical_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool boinc_time_to_checkpoint() {
|
||||
return ready_to_checkpoint;
|
||||
}
|
||||
|
||||
int boinc_checkpoint_completed() {
|
||||
write_checkpoint_cpu_file(boinc_cpu_time());
|
||||
ready_to_checkpoint = false;
|
||||
time_until_checkpoint = aid.checkpoint_period;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int boinc_fraction_done(double x) {
|
||||
fraction_done = x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int boinc_child_start() {
|
||||
this_process_active = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int boinc_child_done(double cpu) {
|
||||
this_process_active = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double boinc_cpu_time() {
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
int retval, pid = getpid();
|
||||
struct rusage ru;
|
||||
retval = getrusage(RUSAGE_SELF, &ru);
|
||||
if(retval) fprintf(stderr, "error: could not get cpu time for %d\n", pid);
|
||||
return (double)ru.ru_utime.tv_sec + (
|
||||
((double)ru.ru_utime.tv_usec) / ((double)1000000.0)
|
||||
);
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#ifndef WINNT_CLOCK
|
||||
return UtilGetCPUClock();
|
||||
#else
|
||||
HANDLE hProcess;
|
||||
FILETIME creationTime,exitTime,kernelTime,userTime;
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, GetCurrentProcessId());
|
||||
if (GetProcessTimes(
|
||||
hProcess, &creationTime, &exitTime, &kernelTime, &userTime)
|
||||
){
|
||||
ULARGE_INTEGER tKernel, tUser;
|
||||
LONGLONG totTime;
|
||||
|
||||
CloseHandle(hProcess);
|
||||
|
||||
tKernel.LowPart = kernelTime.dwLowDateTime;
|
||||
tKernel.HighPart = kernelTime.dwHighDateTime;
|
||||
tUser.LowPart = userTime.dwLowDateTime;
|
||||
tUser.HighPart = userTime.dwHighDateTime;
|
||||
|
||||
// Runtimes in 100-nanosecond units
|
||||
totTime = tKernel.QuadPart + tUser.QuadPart;
|
||||
|
||||
// Convert to seconds and return
|
||||
return(totTime / 10000000.0);
|
||||
} else {
|
||||
CloseHandle(hProcess);
|
||||
return ((double)clock())/CLOCKS_PER_SEC;
|
||||
}
|
||||
#endif // WINNT_CLOCK
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
|
||||
#ifdef macintosh
|
||||
return (double) GetCPUTime() / CLOCKS_PER_SEC;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "boinc_cpu_time(): not implemented\n");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void CALLBACK on_timer( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) {
|
||||
#else
|
||||
void on_timer(int a) {
|
||||
#endif
|
||||
|
||||
if (!ready_to_checkpoint) {
|
||||
time_until_checkpoint -= timer_period;
|
||||
if (time_until_checkpoint <= 0) {
|
||||
ready_to_checkpoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_process_active) {
|
||||
time_until_fraction_done_update -= timer_period;
|
||||
if (time_until_fraction_done_update < 0) {
|
||||
FILE* f = fopen(FRACTION_DONE_FILE, "w");
|
||||
write_fraction_done_file(f, boinc_cpu_time(), fraction_done);
|
||||
fclose(f);
|
||||
time_until_fraction_done_update = aid.fraction_done_update_period;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int set_timer(double period) {
|
||||
int retval=0;
|
||||
#ifdef _WIN32
|
||||
retval = SetTimer( NULL, 0, (int)(period*1000), on_timer );
|
||||
#endif
|
||||
|
||||
#if HAVE_SIGNAL_H
|
||||
#if HAVE_SYS_TIME_H
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = on_timer;
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGVTALRM, &sa, NULL);
|
||||
itimerval value;
|
||||
value.it_value.tv_sec = (int)period;
|
||||
value.it_value.tv_usec = ((int)(period*1000000))%1000000;
|
||||
value.it_interval = value.it_value;
|
||||
retval = setitimer(ITIMER_VIRTUAL, &value, NULL);
|
||||
#endif
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
int write_init_data_file(FILE* f, APP_INIT_DATA& ai) {
|
||||
if (strlen(ai.app_preferences)) {
|
||||
fprintf(f, "<app_preferences>\n%s</app_preferences>\n", ai.app_preferences);
|
||||
}
|
||||
if (strlen(ai.team_name)) {
|
||||
fprintf(f, "<team_name>\n%s</team_name>\n", ai.team_name);
|
||||
}
|
||||
if (strlen(ai.user_name)) {
|
||||
fprintf(f, "<user_name>\n%s</user_name>\n", ai.user_name);
|
||||
}
|
||||
fprintf(f,
|
||||
"<wu_cpu_time>%f</wu_cpu_time>\n"
|
||||
"<total_cobblestones>%f</total_cobblestones>\n"
|
||||
"<recent_avg_cobblestones>%f</recent_avg_cobblestones>\n"
|
||||
"<checkpoint_period>%f</checkpoint_period>\n"
|
||||
"<fraction_done_update_period>%f</fraction_done_update_period>\n",
|
||||
ai.wu_cpu_time,
|
||||
ai.total_cobblestones,
|
||||
ai.recent_avg_cobblestones,
|
||||
ai.checkpoint_period,
|
||||
ai.fraction_done_update_period
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_init_data_file(FILE* f, APP_INIT_DATA& ai) {
|
||||
char buf[256];
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (match_tag(buf, "<app_preferences>")) {
|
||||
strcpy(ai.app_preferences, "");
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (match_tag(buf, "</app_specific_prefs>")) break;
|
||||
strcat(ai.app_preferences, buf);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (parse_str(buf, "<user_name>", ai.user_name)) continue;
|
||||
else if (parse_str(buf, "<team_name>", ai.team_name)) continue;
|
||||
else if (parse_double(buf, "<total_cobblestones>", ai.total_cobblestones)) continue;
|
||||
else if (parse_double(buf, "<recent_avg_cobblestones>", ai.recent_avg_cobblestones)) continue;
|
||||
else if (parse_double(buf, "<wu_cpu_time>", ai.wu_cpu_time)) continue;
|
||||
else if (parse_double(buf, "<checkpoint_period>", ai.checkpoint_period)) continue;
|
||||
else if (parse_double(buf, "<fraction_done_update_period>", ai.fraction_done_update_period)) continue;
|
||||
else fprintf(stderr, "parse_init_data_file: unrecognized %s", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_checkpoint_cpu_file(double cpu) {
|
||||
FILE *f = fopen(CHECKPOINT_CPU_FILE, "w");
|
||||
if (!f) return ERR_FOPEN;
|
||||
fprintf(f, "<checkpoint_cpu_time>%f</checkpoint_cpu_time>\n", cpu);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_checkpoint_cpu_file(FILE* f, double& checkpoint_cpu) {
|
||||
char buf[256];
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (parse_double(buf, "<checkpoint_cpu_time>", checkpoint_cpu)) continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_fraction_done_file(FILE* f, double pct, double cpu) {
|
||||
fprintf(f,
|
||||
"<fraction_done>%f</fraction_done>\n"
|
||||
"<cpu_time>%f</cpu_time>\n",
|
||||
pct,
|
||||
cpu
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_fraction_done_file(FILE* f, double& pct, double& cpu) {
|
||||
char buf[256];
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (parse_double(buf, "<fraction_done>", pct)) continue;
|
||||
else if (parse_double(buf, "<cpu_time>", cpu)) continue;
|
||||
else fprintf(stderr, "parse_fraction_done_file: unrecognized %s", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: this should handle arbitrarily many fd/filename pairs.
|
||||
// Also, give the tags better names
|
||||
int write_fd_init_file(FILE* f, char *file_name, int fdesc, int input_file ) {
|
||||
if (input_file) {
|
||||
fprintf(f, "<fdesc_dup_infile>%s</fdesc_dup_infile>\n", file_name);
|
||||
fprintf(f, "<fdesc_dup_innum>%d</fdesc_dup_innum>\n", fdesc);
|
||||
} else {
|
||||
fprintf(f, "<fdesc_dup_outfile>%s</fdesc_dup_outfile>\n", file_name);
|
||||
fprintf(f, "<fdesc_dup_outnum>%d</fdesc_dup_outnum>\n", fdesc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: this should handle arbitrarily many fd/filename pairs.
|
||||
// Also, this shouldn't be doing the actual duping!
|
||||
//
|
||||
int parse_fd_init_file(FILE* f) {
|
||||
char buf[256],filename[256];
|
||||
int filedesc,fd,retval;
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (parse_str(buf, "<fdesc_dup_infile>", filename)) {
|
||||
if (fgets(buf, 256, f)) {
|
||||
if (parse_int(buf, "<fdesc_dup_innum>", filedesc)) {
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd != filedesc) {
|
||||
retval = dup2(fd, filedesc);
|
||||
if (retval < 0) {
|
||||
fprintf(stderr, "dup2 %d %d returned %d\n", fd, filedesc, retval);
|
||||
exit(retval);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (parse_str(buf, "<fdesc_dup_outfile>", filename)) {
|
||||
if (fgets(buf, 256, f)) {
|
||||
if (parse_int(buf, "<fdesc_dup_outnum>", filedesc)) {
|
||||
fd = open(filename, O_WRONLY|O_CREAT, 0660);
|
||||
if (fd != filedesc) {
|
||||
retval = dup2(fd, filedesc);
|
||||
if (retval < 0) {
|
||||
fprintf(stderr, "dup2 %d %d returned %d\n", fd, filedesc, retval);
|
||||
exit(retval);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else fprintf(stderr, "parse_fd_init_file: unrecognized %s", buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// The contents of this file are subject to the Mozilla Public License
|
||||
// Version 1.0 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
// http://www.mozilla.org/MPL/
|
||||
//
|
||||
// Software distributed under the License is distributed on an "AS IS"
|
||||
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing rights and limitations
|
||||
// under the License.
|
||||
//
|
||||
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
||||
//
|
||||
// The Initial Developer of the Original Code is the SETI@home project.
|
||||
// Portions created by the SETI@home project are Copyright (C) 2002
|
||||
// University of California at Berkeley. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifndef _BOINC_API
|
||||
#define _BOINC_API
|
||||
|
||||
#define DEFAULT_FRACTION_DONE_UPDATE_PERIOD 10
|
||||
#define DEFAULT_CHECKPOINT_PERIOD 300
|
||||
|
||||
// MFILE supports a primitive form of checkpointing.
|
||||
// Write all your output (and restart file) to MFILEs.
|
||||
// The output is buffered in memory.
|
||||
// Then close or flush all the MFILEs;
|
||||
// all the buffers will be flushed to disk, almost atomically.
|
||||
|
||||
class MFILE {
|
||||
char* buf;
|
||||
int len;
|
||||
FILE* f;
|
||||
public:
|
||||
int open(char* path, char* mode);
|
||||
int _putchar(char);
|
||||
int puts(char*);
|
||||
int printf(char* format, ...);
|
||||
size_t write(const void *, size_t size, size_t nitems);
|
||||
int close();
|
||||
int flush();
|
||||
};
|
||||
|
||||
struct APP_INIT_DATA {
|
||||
char app_preferences[4096];
|
||||
char user_name[256];
|
||||
char team_name[256];
|
||||
double wu_cpu_time; // cpu time from previous sessions
|
||||
double total_cobblestones;
|
||||
double recent_avg_cobblestones;
|
||||
double checkpoint_period; // recommended checkpoint period
|
||||
double fraction_done_update_period;
|
||||
};
|
||||
|
||||
extern int boinc_init();
|
||||
extern int boinc_get_init_data(APP_INIT_DATA&);
|
||||
extern int boinc_finish(int);
|
||||
extern int boinc_resolve_filename(char*, char*);
|
||||
extern bool boinc_time_to_checkpoint();
|
||||
extern int boinc_checkpoint_completed();
|
||||
extern int boinc_fraction_done();
|
||||
extern int boinc_child_start();
|
||||
extern int boinc_child_done(double);
|
||||
extern double boinc_cpu_time(); // CPU time for this process
|
||||
|
||||
/////////// API ENDS HERE - IMPLEMENTATION STUFF FOLLOWS
|
||||
|
||||
int write_init_data_file(FILE* f, APP_INIT_DATA&);
|
||||
int parse_init_data_file(FILE* f, APP_INIT_DATA&);
|
||||
int write_percent_done_file(FILE* f, double, double);
|
||||
int parse_percent_done_file(FILE* f, double&, double&);
|
||||
int write_fd_init_file(FILE*, char*, int, int);
|
||||
int parse_fd_init_file(FILE*);
|
||||
int write_checkpoint_cpu_file(double);
|
||||
int parse_checkpoint_cpu_file(FILE*, double&);
|
||||
int write_fraction_done_file(FILE*, double, double);
|
||||
int parse_fraction_done_file(FILE*, double&, double&);
|
||||
|
||||
#define INIT_DATA_FILE "init_data.xml"
|
||||
#define FD_INIT_FILE "fd_init.xml"
|
||||
#define CHECKPOINT_CPU_FILE "checkpoint_cpu.xml"
|
||||
#define FRACTION_DONE_FILE "fraction_done.xml"
|
||||
|
||||
int set_timer(double period);
|
||||
#ifdef _WIN32
|
||||
void CALLBACK on_timer( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
|
||||
#else
|
||||
void on_timer(int not_used); //sets _checkpoint to true
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
void write_graphics_file(FILE* f, GRAPHICS_INFO& gi) {
|
||||
fprintf(f,
|
||||
"<graphics_xsize>%d</graphics_xsize>\n"
|
||||
"<graphics_ysize>%d</graphics_ysize>\n"
|
||||
"<graphics_refresh_period>%f</graphics_refresh_period>\n",
|
||||
gi.graphics.xsize,
|
||||
gi.graphics.ysize,
|
||||
gi.graphics.refresh_period,
|
||||
);
|
||||
}
|
||||
|
||||
int parse_graphics_file(FILE* f, GRAPHICS_INFO& gi) {
|
||||
char buf[256];
|
||||
while (fgets(buf, 256, f)) {
|
||||
if (match_tag(buf, "<graphics_info>")) return 0;
|
||||
else if (parse_int(buf, "<graphics_xsize>", gi.graphics.xsize)) continue;
|
||||
else if (parse_int(buf, "<graphics_ysize>", gi.graphics.ysize)) continue;
|
||||
else if (parse_double(buf, "<graphics_refresh_period>", gi.graphics.refresh_period)) continue;
|
||||
else fprintf(stderr, "parse_core_file: unrecognized %s", buf);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
struct APP_IN_GRAPHICS {
|
||||
int xsize;
|
||||
int ysize;
|
||||
double refresh_period;
|
||||
char shmem_seg_name[32];
|
||||
};
|
||||
|
||||
struct APP_OUT_GRAPHICS {
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "boinc_api.h"
|
||||
|
||||
int MFILE::open(char* path, char* mode) {
|
||||
buf = 0;
|
||||
len = 0;
|
||||
f = fopen(path, mode);
|
||||
if (!f) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFILE::printf(char* format, ...) {
|
||||
va_list ap;
|
||||
char buf2[4096];
|
||||
int n, k;
|
||||
|
||||
va_start(ap, format);
|
||||
k = vsprintf(buf2, format, ap);
|
||||
va_end(ap);
|
||||
n = strlen(buf2);
|
||||
buf = (char*)realloc(buf, len+n);
|
||||
strncpy(buf+len, buf2, n);
|
||||
len += n;
|
||||
return k;
|
||||
}
|
||||
|
||||
size_t MFILE::write(const void *ptr, size_t size, size_t nitems) {
|
||||
buf = (char *)realloc( buf, len+(size*nitems) );
|
||||
memcpy( buf+len, ptr, size*nitems );
|
||||
len += size*nitems;
|
||||
return nitems;
|
||||
}
|
||||
|
||||
int MFILE::_putchar(char c) {
|
||||
buf = (char*)realloc(buf, len+1);
|
||||
buf[len] = c;
|
||||
len++;
|
||||
return c;
|
||||
}
|
||||
|
||||
int MFILE::puts(char* p) {
|
||||
int n = strlen(p);
|
||||
buf = (char*)realloc(buf, len+n);
|
||||
strncpy(buf+len, p, n);
|
||||
len += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFILE::close() {
|
||||
fwrite(buf, 1, len, f);
|
||||
free(buf);
|
||||
buf = 0;
|
||||
return fclose(f);
|
||||
}
|
||||
|
||||
int MFILE::flush() {
|
||||
fwrite(buf, 1, len, f);
|
||||
len = 0;
|
||||
return fflush(f);
|
||||
}
|
|
@ -13,7 +13,7 @@ CFLAGS = -g -Wall @DEFS@ \
|
|||
|
||||
CC = @CC@ $(CFLAGS) -I @top_srcdir@/api
|
||||
|
||||
LIBS = ../api/api.o ../lib/parse.o
|
||||
LIBS = ../api/boinc_api.o ../api/mfile.o ../lib/parse.o
|
||||
|
||||
CLIBS = @LIBS@
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
void file_append(FILE* in, FILE* out) {
|
||||
char buf[1024];
|
||||
|
@ -40,14 +40,13 @@ int main(int argc, char** argv) {
|
|||
FILE* in, *out;
|
||||
char file_name[512];
|
||||
int i;
|
||||
APP_IN ai;
|
||||
|
||||
boinc_init(ai);
|
||||
boinc_init();
|
||||
fprintf(stderr, "APP: concat: starting, argc %d\n", argc);
|
||||
for (i=0; i<argc; i++) {
|
||||
fprintf(stderr, "APP: concat: argv[%d] is %s\n", i, argv[i]);
|
||||
}
|
||||
boinc_resolve_link( argv[argc-1], file_name );
|
||||
boinc_resolve_filename( argv[argc-1], file_name );
|
||||
fprintf( stderr, "res: %s\n", file_name );
|
||||
out = fopen(file_name, "w");
|
||||
if (!out) {
|
||||
|
@ -55,7 +54,7 @@ int main(int argc, char** argv) {
|
|||
exit(1);
|
||||
}
|
||||
for (i=1; i<argc-1; i++) {
|
||||
boinc_resolve_link( argv[i], file_name );
|
||||
boinc_resolve_filename( argv[i], file_name );
|
||||
fprintf( stderr, "res: %s\n", file_name );
|
||||
in = fopen(file_name, "r");
|
||||
if (!in) {
|
||||
|
@ -67,5 +66,6 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
fclose(out);
|
||||
fprintf(stderr, "APP: concat: done\n");
|
||||
boinc_finish(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
#define CHECKPOINT_FILE "concat_slow_state"
|
||||
|
||||
|
@ -32,7 +32,7 @@ int do_checkpoint(MFILE& mf, int filenum, int nchars ) {
|
|||
int retval;
|
||||
char resolved_name[512],res_name2[512];
|
||||
|
||||
boinc_resolve_link( "temp", resolved_name );
|
||||
boinc_resolve_filename( "temp", resolved_name );
|
||||
FILE* f = fopen(resolved_name, "w");
|
||||
if (!f) return 1;
|
||||
fprintf(f, "%d %d", filenum, nchars);
|
||||
|
@ -43,7 +43,7 @@ int do_checkpoint(MFILE& mf, int filenum, int nchars ) {
|
|||
// hopefully atomic part starts here
|
||||
retval = mf.flush();
|
||||
if (retval) return retval;
|
||||
boinc_resolve_link( CHECKPOINT_FILE, res_name2 );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, res_name2 );
|
||||
retval = rename(resolved_name, res_name2);
|
||||
if (retval) return retval;
|
||||
// hopefully atomic part ends here
|
||||
|
@ -54,7 +54,6 @@ int do_checkpoint(MFILE& mf, int filenum, int nchars ) {
|
|||
void file_append(FILE* in, MFILE &out, int skip, int filenum) {
|
||||
char buf[1];
|
||||
int n,nread,retval;
|
||||
APP_OUT ao;
|
||||
|
||||
fseek( in, skip, SEEK_SET );
|
||||
nread = skip;
|
||||
|
@ -71,15 +70,14 @@ void file_append(FILE* in, MFILE &out, int skip, int filenum) {
|
|||
if( retval == 0 )
|
||||
n = 1;
|
||||
|
||||
if( time_to_checkpoint() ) {
|
||||
if( boinc_time_to_checkpoint() ) {
|
||||
fprintf( stderr, "Checkpoint.\n" );
|
||||
retval = do_checkpoint( out, filenum, nread );
|
||||
if( retval ) {
|
||||
fprintf( stderr, "APP: concat_slow checkpoint failed %d\n", retval );
|
||||
exit(1);
|
||||
}
|
||||
ao.percent_done = 1;
|
||||
checkpoint_completed(ao);
|
||||
boinc_checkpoint_completed();
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
@ -91,16 +89,14 @@ int main(int argc, char** argv) {
|
|||
char file_name[512];
|
||||
int i;
|
||||
int file_num,nchars,retval;
|
||||
APP_IN ai;
|
||||
char *mode;
|
||||
|
||||
boinc_init(ai);
|
||||
fprintf( stderr, "%f\n", ai.checkpoint_period );
|
||||
boinc_init();
|
||||
fprintf(stderr, "APP: concat: starting, argc %d\n", argc);
|
||||
for (i=0; i<argc; i++) {
|
||||
fprintf(stderr, "APP: concat: argv[%d] is %s\n", i, argv[i]);
|
||||
}
|
||||
boinc_resolve_link( CHECKPOINT_FILE, file_name );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, file_name );
|
||||
state = fopen( file_name, "r" );
|
||||
if( state ) {
|
||||
fscanf( state, "%d %d", &file_num, &nchars );
|
||||
|
@ -110,7 +106,7 @@ int main(int argc, char** argv) {
|
|||
nchars = 0;
|
||||
mode = "w";
|
||||
}
|
||||
boinc_resolve_link( argv[argc-1], file_name );
|
||||
boinc_resolve_filename( argv[argc-1], file_name );
|
||||
fprintf( stderr, "res: %s\n", file_name );
|
||||
retval = out.open(file_name, mode);
|
||||
if (retval) {
|
||||
|
@ -118,7 +114,7 @@ int main(int argc, char** argv) {
|
|||
exit(1);
|
||||
}
|
||||
for (i=file_num; i<argc-1; i++) {
|
||||
boinc_resolve_link( argv[i], file_name );
|
||||
boinc_resolve_filename( argv[i], file_name );
|
||||
fprintf( stderr, "res: %s\n", file_name );
|
||||
in = fopen(file_name, "r");
|
||||
if (!in) {
|
||||
|
@ -131,5 +127,6 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
out.close();
|
||||
fprintf(stderr, "APP: concat: done\n");
|
||||
boinc_finish(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
#define CHECKPOINT_FILE "uc_slow_state"
|
||||
|
||||
|
@ -34,7 +34,7 @@ int do_checkpoint(MFILE& mf, int nchars) {
|
|||
int retval;
|
||||
char resolved_name[512],res_name2[512];
|
||||
|
||||
boinc_resolve_link( "temp", resolved_name );
|
||||
boinc_resolve_filename( "temp", resolved_name );
|
||||
FILE* f = fopen(resolved_name, "w");
|
||||
if (!f) return 1;
|
||||
fprintf(f, "%d", nchars);
|
||||
|
@ -45,7 +45,7 @@ int do_checkpoint(MFILE& mf, int nchars) {
|
|||
// hopefully atomic part starts here
|
||||
retval = mf.flush();
|
||||
if (retval) return retval;
|
||||
boinc_resolve_link( CHECKPOINT_FILE, res_name2 );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, res_name2 );
|
||||
retval = rename(resolved_name, res_name2);
|
||||
if (retval) return retval;
|
||||
// hopefully atomic part ends here
|
||||
|
@ -59,23 +59,21 @@ int main() {
|
|||
char resolved_name[512];
|
||||
MFILE out, time_file;
|
||||
FILE* state, *in;
|
||||
APP_IN ai;
|
||||
APP_OUT ao;
|
||||
|
||||
boinc_init( ai );
|
||||
boinc_init();
|
||||
|
||||
boinc_resolve_link( "in", resolved_name );
|
||||
boinc_resolve_filename( "in", resolved_name );
|
||||
in = fopen(resolved_name, "r");
|
||||
boinc_resolve_link( CHECKPOINT_FILE, resolved_name );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, resolved_name );
|
||||
state = fopen(resolved_name, "r");
|
||||
if (state) {
|
||||
fscanf(state, "%d", &nchars);
|
||||
printf("nchars %d\n", nchars);
|
||||
fseek(in, nchars, SEEK_SET);
|
||||
boinc_resolve_link( "out", resolved_name );
|
||||
boinc_resolve_filename( "out", resolved_name );
|
||||
retval = out.open(resolved_name, "a");
|
||||
} else {
|
||||
boinc_resolve_link( "out", resolved_name );
|
||||
boinc_resolve_filename( "out", resolved_name );
|
||||
retval = out.open(resolved_name, "w");
|
||||
}
|
||||
fprintf(stderr, "APP: uc_slow starting\n");
|
||||
|
@ -99,13 +97,12 @@ int main() {
|
|||
j /= (float)n;
|
||||
}
|
||||
|
||||
if (time_to_checkpoint()) {
|
||||
if (boinc_time_to_checkpoint()) {
|
||||
retval = do_checkpoint(out, nchars);
|
||||
if (retval) {
|
||||
fprintf(stderr, "APP: uc_slow checkpoint failed %d\n", retval);
|
||||
}
|
||||
ao.percent_done = 1;
|
||||
checkpoint_completed(ao);
|
||||
boinc_checkpoint_completed();
|
||||
}
|
||||
}
|
||||
retval = out.flush();
|
||||
|
@ -114,10 +111,9 @@ int main() {
|
|||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "APP: uc_slow ending, wrote %d chars\n", nchars);
|
||||
ao.percent_done = 1;
|
||||
app_completed(ao);
|
||||
time_file.printf("%f\n", ao.cpu_time_at_checkpoint);
|
||||
time_file.printf("%f\n", boinc_cpu_time());
|
||||
time_file.flush();
|
||||
time_file.close();
|
||||
boinc_finish(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
#define CHECKPOINT_FILE "uc_slow_state"
|
||||
|
||||
|
@ -34,7 +34,7 @@ int do_checkpoint(MFILE& mf, int nchars) {
|
|||
int retval;
|
||||
char resolved_name[512],res_name2[512];
|
||||
|
||||
boinc_resolve_link( "temp", resolved_name );
|
||||
boinc_resolve_filename( "temp", resolved_name );
|
||||
FILE* f = fopen(resolved_name, "w");
|
||||
if (!f) return 1;
|
||||
fprintf(f, "%d", nchars);
|
||||
|
@ -45,7 +45,7 @@ int do_checkpoint(MFILE& mf, int nchars) {
|
|||
// hopefully atomic part starts here
|
||||
retval = mf.flush();
|
||||
if (retval) return retval;
|
||||
boinc_resolve_link( CHECKPOINT_FILE, res_name2 );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, res_name2 );
|
||||
retval = rename(resolved_name, res_name2);
|
||||
if (retval) return retval;
|
||||
// hopefully atomic part ends here
|
||||
|
@ -58,23 +58,21 @@ int main() {
|
|||
char resolved_name[512];
|
||||
MFILE out, time_file;
|
||||
FILE* state, *in;
|
||||
APP_IN ai;
|
||||
APP_OUT ao;
|
||||
|
||||
boinc_init( ai );
|
||||
boinc_init();
|
||||
|
||||
boinc_resolve_link( "in", resolved_name );
|
||||
boinc_resolve_filename( "in", resolved_name );
|
||||
in = fopen(resolved_name, "r");
|
||||
boinc_resolve_link( CHECKPOINT_FILE, resolved_name );
|
||||
boinc_resolve_filename( CHECKPOINT_FILE, resolved_name );
|
||||
state = fopen(resolved_name, "r");
|
||||
if (state) {
|
||||
fscanf(state, "%d", &nchars);
|
||||
printf("nchars %d\n", nchars);
|
||||
fseek(in, nchars, SEEK_SET);
|
||||
boinc_resolve_link( "out", resolved_name );
|
||||
boinc_resolve_filename( "out", resolved_name );
|
||||
retval = out.open(resolved_name, "a");
|
||||
} else {
|
||||
boinc_resolve_link( "out", resolved_name );
|
||||
boinc_resolve_filename( "out", resolved_name );
|
||||
retval = out.open(resolved_name, "w");
|
||||
}
|
||||
fprintf(stderr, "APP: uc_slow starting\n");
|
||||
|
@ -92,14 +90,13 @@ int main() {
|
|||
|
||||
sleep(1);
|
||||
|
||||
if (time_to_checkpoint()) {
|
||||
if (boinc_time_to_checkpoint()) {
|
||||
retval = do_checkpoint(out, nchars);
|
||||
if (retval) {
|
||||
fprintf(stderr, "APP: uc_slow checkpoint failed %d\n", retval);
|
||||
exit(1);
|
||||
}
|
||||
ao.percent_done = 1;
|
||||
checkpoint_completed(ao);
|
||||
boinc_checkpoint_completed();
|
||||
}
|
||||
}
|
||||
retval = out.flush();
|
||||
|
@ -108,10 +105,9 @@ int main() {
|
|||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "APP: uc_slow ending, wrote %d chars\n", nchars);
|
||||
ao.percent_done = 1;
|
||||
app_completed(ao);
|
||||
time_file.printf("%f\n", ao.cpu_time_at_checkpoint);
|
||||
time_file.printf("%f\n", boinc_cpu_time());
|
||||
time_file.flush();
|
||||
time_file.close();
|
||||
boinc_finish(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,14 +22,12 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include "api.h"
|
||||
#include "boinc_api.h"
|
||||
|
||||
int main() {
|
||||
int c, n=0;
|
||||
APP_IN ai;
|
||||
APP_OUT ao;
|
||||
|
||||
boinc_init(ai);
|
||||
boinc_init();
|
||||
fprintf(stderr, "APP: upper_case starting\n");
|
||||
fflush(stderr);
|
||||
while (1) {
|
||||
|
@ -38,12 +36,12 @@ int main() {
|
|||
c = toupper(c);
|
||||
putchar(c);
|
||||
n++;
|
||||
if(time_to_checkpoint()) {
|
||||
if (boinc_time_to_checkpoint()) {
|
||||
fflush(stdout);
|
||||
ao.percent_done = 1;
|
||||
checkpoint_completed(ao);
|
||||
boinc_checkpoint_completed();
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "APP: upper_case ending, wrote %d chars\n", n);
|
||||
boinc_finish(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1382,3 +1382,59 @@ Eric Heien August 2, 2002
|
|||
net_xfer.C
|
||||
net_xfer.h
|
||||
|
||||
David A.
|
||||
Various changes to API:
|
||||
- Added user, team names, credit info to APP_INIT_DATA
|
||||
- separate call for getting init data
|
||||
- separate call for returning fraction done
|
||||
- separated out fraction_done_update_period
|
||||
- moved graphics API to separate file
|
||||
- moved MFILE implementation to separate file
|
||||
- API timer is now 0.1 sec; use counters for various uses
|
||||
(checkpoint, fraction done, graphics)
|
||||
- changed name of API files to boinc_api.C,h
|
||||
|
||||
- clarify distinction between
|
||||
"current CPU time"
|
||||
"CPU time at last checkpoint"
|
||||
"CPU time at start of current run"
|
||||
These are all kept in ACTIVE_TASK.
|
||||
RESULT now only has "final CPU time".
|
||||
|
||||
- fixed bug in dir scanning (ahem...)
|
||||
|
||||
- Coding style notes:
|
||||
- every fopen() MUST have a matching fclose() in same function
|
||||
- every malloc() MUST have a matching free() in same function
|
||||
- don't do a rewind() right after fopen()
|
||||
- write function calls as
|
||||
func(arg1, arg2);
|
||||
NOTE: there's a space after every comma, everywhere
|
||||
- write "if" statements as
|
||||
if (condition) {
|
||||
...
|
||||
}
|
||||
- no explicit argument checking. do this at higher level
|
||||
- functions in foo.C should be declared (as extern) in foo.h,
|
||||
AND NOWHERE ELSE.
|
||||
|
||||
api/
|
||||
Makefile.in
|
||||
api.C,h (removed)
|
||||
boinc_api.C,h (new)
|
||||
graphics_api.C,h (new)
|
||||
mfile.C (new)
|
||||
apps/
|
||||
Makefile.in
|
||||
*.C
|
||||
client/
|
||||
Makefile.in
|
||||
app.C,h
|
||||
client_state.C,h
|
||||
client_types.C,h
|
||||
cs_apps.C
|
||||
cs_scheduler.C
|
||||
file_names.C
|
||||
filesys.C,h
|
||||
doc/
|
||||
api.html
|
||||
|
|
|
@ -51,7 +51,7 @@ OBJS = \
|
|||
../lib/md5.o \
|
||||
../lib/crypt.o \
|
||||
../RSAEuro/source/rsaeuro.a \
|
||||
../api/api.o
|
||||
../api/boinc_api.o
|
||||
|
||||
TEST_NET_XFER_OBJS = \
|
||||
filesys.o \
|
||||
|
|
203
client/app.C
203
client/app.C
|
@ -67,11 +67,7 @@
|
|||
#include "util.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "api.h"
|
||||
|
||||
extern void write_core_file(FILE *f, APP_IN& ai);
|
||||
extern void write_init_file(FILE *f, char *file_name, int fdesc, int input_file);
|
||||
extern void parse_app_file(FILE *f, APP_OUT& ao);
|
||||
#include "boinc_api.h"
|
||||
|
||||
// take a string containing some space separated words.
|
||||
// return an array of pointers to the null-terminated words.
|
||||
|
@ -81,15 +77,6 @@ int parse_command_line(char* p, char** argv) {
|
|||
char** pp = argv;
|
||||
bool space = true;
|
||||
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: parse_command_line: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(argv==NULL) {
|
||||
fprintf(stderr, "error: parse_command_line: unexpected NULL pointer argv\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (isspace(*p)) {
|
||||
*p = 0;
|
||||
|
@ -112,10 +99,6 @@ int parse_command_line(char* p, char** argv) {
|
|||
static int print_argv(char** argv) {
|
||||
int i;
|
||||
|
||||
if(argv==NULL) {
|
||||
fprintf(stderr, "error: print_argv: unexpected NULL pointer argv\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
for (i=0; argv[i]; i++) {
|
||||
fprintf(stderr, "argv[%d]: %s\n", i, argv[i]);
|
||||
}
|
||||
|
@ -123,8 +106,6 @@ static int print_argv(char** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the ACTIVE_TASK object members to null
|
||||
//
|
||||
ACTIVE_TASK::ACTIVE_TASK() {
|
||||
result = NULL;
|
||||
wup = NULL;
|
||||
|
@ -135,17 +116,9 @@ ACTIVE_TASK::ACTIVE_TASK() {
|
|||
exit_status = 0;
|
||||
signal = 0;
|
||||
strcpy(dirname, "");
|
||||
prev_cpu_time = 0;
|
||||
}
|
||||
|
||||
// Initialize active task with a specific result requirement
|
||||
//
|
||||
int ACTIVE_TASK::init(RESULT* rp) {
|
||||
if(rp==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.init: unexpected NULL pointer rp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
result = rp;
|
||||
wup = rp->wup;
|
||||
app_version = wup->avp;
|
||||
|
@ -154,57 +127,60 @@ int ACTIVE_TASK::init(RESULT* rp) {
|
|||
}
|
||||
|
||||
// Start a task in a slot directory. This includes setting up soft links,
|
||||
// passing preferences, and starting the actual process for computation
|
||||
// passing preferences, and starting the process
|
||||
//
|
||||
// WHAT ARE ASSUMPTIONS ABOUT CURRENT DIR??
|
||||
// SHOULD REPLACE ../.. stuff
|
||||
//
|
||||
int ACTIVE_TASK::start(bool first_time) {
|
||||
char exec_name[256], file_path[256], link_path[256],temp[256];
|
||||
char exec_name[256], file_path[256], link_path[256], temp[256];
|
||||
char* argv[100];
|
||||
unsigned int i;
|
||||
FILE_REF file_ref;
|
||||
FILE_INFO* fip;
|
||||
int retval;
|
||||
char prefs_path[256],init_path[256];
|
||||
char prefs_path[256], init_path[256];
|
||||
FILE *prefs_fd,*init_file;
|
||||
APP_IN app_prefs;
|
||||
APP_INIT_DATA aid;
|
||||
|
||||
prev_cpu_time = 0;
|
||||
// These should be chosen in a better manner (user specifiable)
|
||||
app_prefs.graphics.xsize = 640;
|
||||
app_prefs.graphics.ysize = 480;
|
||||
app_prefs.graphics.refresh_period = 5;
|
||||
app_prefs.checkpoint_period = 5;
|
||||
app_prefs.poll_period = 5;
|
||||
if(!first_time) app_prefs.cpu_time = result->cpu_time;
|
||||
if (first_time) {
|
||||
checkpoint_cpu_time = 0;
|
||||
}
|
||||
current_cpu_time = checkpoint_cpu_time;
|
||||
starting_cpu_time = checkpoint_cpu_time;
|
||||
fraction_done = 0;
|
||||
|
||||
// Write out the app prefs. This has everything in the APP_IN
|
||||
// struct, including graphics prefs and checkpoint/poll prefs
|
||||
sprintf( prefs_path, "%s/%s", dirname, CORE_TO_APP_FILE );
|
||||
prefs_fd = fopen( prefs_path, "wb" );
|
||||
if( !prefs_fd ) {
|
||||
if( log_flags.task_debug ) {
|
||||
printf( "Failed to open core to app prefs file %s.\n", prefs_path );
|
||||
//app_prefs.graphics.xsize = 640;
|
||||
//app_prefs.graphics.ysize = 480;
|
||||
//app_prefs.graphics.refresh_period = 5;
|
||||
|
||||
memset(&aid, 0, sizeof(aid));
|
||||
// TODO: fill in the app prefs, user name, team name, etc.
|
||||
aid.checkpoint_period = DEFAULT_CHECKPOINT_PERIOD;
|
||||
aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD;
|
||||
aid.wu_cpu_time = checkpoint_cpu_time;
|
||||
|
||||
sprintf(prefs_path, "%s/%s", dirname, INIT_DATA_FILE);
|
||||
prefs_fd = fopen(prefs_path, "wb");
|
||||
if (!prefs_fd) {
|
||||
if (log_flags.task_debug) {
|
||||
printf("Failed to open core to app prefs file %s.\n", prefs_path);
|
||||
}
|
||||
return ERR_FOPEN;
|
||||
}
|
||||
rewind( prefs_fd );
|
||||
write_core_file( prefs_fd,app_prefs );
|
||||
retval = write_init_data_file(prefs_fd, aid);
|
||||
fclose(prefs_fd);
|
||||
|
||||
// Open the init file. This file contains initialization
|
||||
// information regarding tasks that can only be performed in
|
||||
// the app, such as redirecting file descriptors
|
||||
//
|
||||
sprintf( init_path, "%s/%s", dirname, BOINC_INIT_FILE );
|
||||
init_file = fopen( init_path, "wb" );
|
||||
if( !init_file ) {
|
||||
if( log_flags.task_debug ) {
|
||||
sprintf(init_path, "%s/%s", dirname, FD_INIT_FILE);
|
||||
init_file = fopen(init_path, "wb");
|
||||
if (!init_file) {
|
||||
if(log_flags.task_debug) {
|
||||
printf( "Failed to open init file %s.\n", init_path );
|
||||
}
|
||||
return ERR_FOPEN;
|
||||
}
|
||||
rewind( init_file );
|
||||
|
||||
// make a soft link to the executable(s)
|
||||
// make soft links to the executable(s)
|
||||
//
|
||||
for (i=0; i<app_version->app_files.size(); i++) {
|
||||
fip = app_version->app_files[i].file_info;
|
||||
|
@ -247,8 +223,8 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
sprintf( temp, "../../%s", file_path );
|
||||
write_init_file( init_file, temp, file_ref.fd, 1 );
|
||||
sprintf(temp, "../../%s", file_path);
|
||||
write_fd_init_file(init_file, temp, file_ref.fd, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +250,7 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
}
|
||||
} else {
|
||||
sprintf( temp, "../../%s", file_path );
|
||||
write_init_file( init_file, temp, file_ref.fd, 0 );
|
||||
write_fd_init_file(init_file, temp, file_ref.fd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +280,7 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
argv[0] = exec_name;
|
||||
parse_command_line(wup->command_line, argv+1);
|
||||
if (log_flags.task_debug) print_argv(argv);
|
||||
boinc_resolve_link( exec_name, temp );
|
||||
boinc_resolve_filename(exec_name, temp);
|
||||
retval = execv(temp, argv);
|
||||
fprintf(stderr, "execv failed: %d\n", retval);
|
||||
perror("execv");
|
||||
|
@ -331,6 +307,7 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
|
||||
// Need to condense argv into a single string
|
||||
//if (log_flags.task_debug) print_argv(argv);
|
||||
//
|
||||
sprintf( temp, "%s/%s", dirname, exec_name );
|
||||
boinc_resolve_link( temp, exec_name );
|
||||
if( !CreateProcess( exec_name,
|
||||
|
@ -394,10 +371,7 @@ void ACTIVE_TASK::request_exit(int seconds) {
|
|||
//
|
||||
int ACTIVE_TASK_SET::insert(ACTIVE_TASK* atp) {
|
||||
int retval;
|
||||
if(atp==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.insert: unexpected NULL pointer atp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
get_slot_dir(atp->slot, atp->dirname);
|
||||
clean_out_dir(atp->dirname);
|
||||
retval = atp->start(true);
|
||||
|
@ -423,9 +397,9 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
atp = active_tasks[i];
|
||||
if( GetExitCodeProcess( atp->pid_handle,&exit_code ) ) {
|
||||
if (GetExitCodeProcess(atp->pid_handle, &exit_code)) {
|
||||
// Get the elapsed CPU time
|
||||
if( GetProcessTimes( atp->pid_handle, &creation_time, &exit_time, &kernel_time, &user_time ) ) {
|
||||
if (GetProcessTimes(atp->pid_handle, &creation_time, &exit_time, &kernel_time, &user_time)) {
|
||||
tKernel.LowPart = kernel_time.dwLowDateTime;
|
||||
tKernel.HighPart = kernel_time.dwHighDateTime;
|
||||
|
||||
|
@ -440,7 +414,7 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
// This probably isn't correct
|
||||
atp->result->cpu_time = ((double)clock())/CLOCKS_PER_SEC;
|
||||
}
|
||||
if( exit_code != STILL_ACTIVE ) {
|
||||
if (exit_code != STILL_ACTIVE) {
|
||||
// Not sure how to incorporate the other states (WAS_SIGNALED, etc)
|
||||
atp->state = PROCESS_EXITED;
|
||||
atp->exit_status = exit_code;
|
||||
|
@ -470,15 +444,18 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
fprintf(stderr, "ACTIVE_TASK_SET::poll(): pid %d not found\n", pid);
|
||||
return true;
|
||||
}
|
||||
atp->result->cpu_time = rs.ru_utime.tv_sec + rs.ru_utime.tv_usec/1.e6;
|
||||
double x = rs.ru_utime.tv_sec + rs.ru_utime.tv_usec/1.e6;
|
||||
atp->result->final_cpu_time = atp->starting_cpu_time + x;
|
||||
if (WIFEXITED(stat)) {
|
||||
atp->state = PROCESS_EXITED;
|
||||
atp->exit_status = WEXITSTATUS(stat);
|
||||
atp->result->exit_status = atp->exit_status;
|
||||
if (log_flags.task_debug) printf("process exited status%d\n", atp->exit_status);
|
||||
} else if (WIFSIGNALED(stat)) {
|
||||
atp->state = PROCESS_WAS_SIGNALED;
|
||||
atp->signal = WTERMSIG(stat);
|
||||
atp->result->exit_status = atp->signal;
|
||||
if (log_flags.task_debug) printf("process was signaled %d\n", atp->signal);
|
||||
} else {
|
||||
atp->state = PROCESS_EXIT_UNKNOWN;
|
||||
atp->result->exit_status = -1;
|
||||
|
@ -507,10 +484,7 @@ bool ACTIVE_TASK_SET::poll() {
|
|||
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_pid(int pid) {
|
||||
unsigned int i;
|
||||
ACTIVE_TASK* atp;
|
||||
if(pid<0) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.lookup_pid: negatvie pid\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
atp = active_tasks[i];
|
||||
if (atp->pid == pid) return atp;
|
||||
|
@ -549,7 +523,7 @@ void ACTIVE_TASK_SET::exit_tasks() {
|
|||
for (i=0; i<active_tasks.size(); i++) {
|
||||
atp = active_tasks[i];
|
||||
atp->request_exit(0);
|
||||
atp->update_time();
|
||||
atp->check_app_status_files();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -586,10 +560,7 @@ void ACTIVE_TASK::unsuspend() {
|
|||
//
|
||||
int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
|
||||
vector<ACTIVE_TASK*>::iterator iter;
|
||||
if(atp==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.remove: unexpected NULL pointer atp\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
iter = active_tasks.begin();
|
||||
while (iter != active_tasks.end()) {
|
||||
if (*iter == atp) {
|
||||
|
@ -627,22 +598,32 @@ int ACTIVE_TASK_SET::restart_tasks() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Update the CPU time accounting based on the APP_TO_CORE_FILE passed to
|
||||
// us by the application
|
||||
// See if the app has generated new checkpoint CPU or fraction-done files.
|
||||
// If so read them and return true.
|
||||
//
|
||||
bool ACTIVE_TASK::update_time() {
|
||||
FILE* app_fp;
|
||||
bool ACTIVE_TASK::check_app_status_files() {
|
||||
FILE* f;
|
||||
char app_path[256];
|
||||
APP_OUT ao;
|
||||
bool found = false;
|
||||
|
||||
sprintf(app_path, "%s/%s", dirname, APP_TO_CORE_FILE);
|
||||
app_fp = fopen(app_path, "r");
|
||||
if(!app_fp) return false;
|
||||
parse_app_file(app_fp, ao);
|
||||
if(!ao.checkpointed) return false;
|
||||
result->cpu_time += ao.cpu_time_at_checkpoint - prev_cpu_time;
|
||||
prev_cpu_time = ao.cpu_time_at_checkpoint;
|
||||
return true;
|
||||
sprintf(app_path, "%s/%s", dirname, CHECKPOINT_CPU_FILE);
|
||||
f = fopen(app_path, "r");
|
||||
if (f) {
|
||||
found = true;
|
||||
parse_checkpoint_cpu_file(f, checkpoint_cpu_time);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
sprintf(app_path, "%s/%s", dirname, FRACTION_DONE_FILE);
|
||||
f = fopen(app_path, "r");
|
||||
if (f) {
|
||||
found = true;
|
||||
parse_fraction_done_file(
|
||||
f, current_cpu_time, fraction_done
|
||||
);
|
||||
fclose(f);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// Poll each of the currently running tasks and get their CPU time
|
||||
|
@ -651,9 +632,10 @@ bool ACTIVE_TASK_SET::poll_time() {
|
|||
ACTIVE_TASK* atp;
|
||||
unsigned int i;
|
||||
bool updated;
|
||||
|
||||
for(i=0; i<active_tasks.size(); i++) {
|
||||
atp = active_tasks[i];
|
||||
updated |= atp->update_time();
|
||||
updated |= atp->check_app_status_files();
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
@ -661,23 +643,19 @@ bool ACTIVE_TASK_SET::poll_time() {
|
|||
// Write XML data about this ACTIVE_TASK
|
||||
//
|
||||
int ACTIVE_TASK::write(FILE* fout) {
|
||||
if(fout==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.write: unexpected NULL pointer fout\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
fprintf(fout,
|
||||
"<active_task>\n"
|
||||
" <project_master_url>%s</project_master_url>\n"
|
||||
" <result_name>%s</result_name>\n"
|
||||
" <app_version_num>%d</app_version_num>\n"
|
||||
" <slot>%d</slot>\n"
|
||||
" <prev_cpu_time>%f</prev_cpu_time>\n"
|
||||
" <checkpoint_cpu_time>%f</checkpoint_cpu_time>\n"
|
||||
"</active_task>\n",
|
||||
result->project->master_url,
|
||||
result->name,
|
||||
app_version->version_num,
|
||||
slot,
|
||||
prev_cpu_time
|
||||
checkpoint_cpu_time
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
@ -688,14 +666,7 @@ int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
|
|||
char buf[256], result_name[256], project_master_url[256];
|
||||
int app_version_num=0;
|
||||
PROJECT* project;
|
||||
if(fin==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.parse: unexpected NULL pointer fin\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(cs==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK.parse: unexpected NULL pointer cs\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
strcpy(result_name, "");
|
||||
strcpy(project_master_url, "");
|
||||
while (fgets(buf, 256, fin)) {
|
||||
|
@ -727,7 +698,7 @@ int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
|
|||
else if (parse_str(buf, "<project_master_url>", project_master_url)) continue;
|
||||
else if (parse_int(buf, "<app_version_num>", app_version_num)) continue;
|
||||
else if (parse_int(buf, "<slot>", slot)) continue;
|
||||
else if (parse_double(buf, "<prev_cpu_time>", prev_cpu_time)) continue;
|
||||
else if (parse_double(buf, "<checkpoint_cpu_time>", checkpoint_cpu_time)) continue;
|
||||
else fprintf(stderr, "ACTIVE_TASK::parse(): unrecognized %s\n", buf);
|
||||
}
|
||||
return -1;
|
||||
|
@ -737,10 +708,7 @@ int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
|
|||
//
|
||||
int ACTIVE_TASK_SET::write(FILE* fout) {
|
||||
unsigned int i;
|
||||
if(fout==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.write: unexpected NULL pointer fout\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
fprintf(fout, "<active_task_set>\n");
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
active_tasks[i]->write(fout);
|
||||
|
@ -755,14 +723,7 @@ int ACTIVE_TASK_SET::parse(FILE* fin, CLIENT_STATE* cs) {
|
|||
ACTIVE_TASK* atp;
|
||||
char buf[256];
|
||||
int retval;
|
||||
if(fin==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.parse: unexpected NULL pointer fin\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(cs==NULL) {
|
||||
fprintf(stderr, "error: ACTIVE_TASK_SET.parse: unexpected NULL pointer cs\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
while (fgets(buf, 256, fin)) {
|
||||
if (match_tag(buf, "</active_task_set>")) return 0;
|
||||
else if (match_tag(buf, "<active_task>")) {
|
||||
|
|
|
@ -63,8 +63,11 @@ public:
|
|||
int state;
|
||||
int exit_status;
|
||||
int signal;
|
||||
double fraction_done;
|
||||
double starting_cpu_time;
|
||||
double checkpoint_cpu_time;
|
||||
double current_cpu_time;
|
||||
char dirname[256]; // directory where process runs
|
||||
double prev_cpu_time;
|
||||
ACTIVE_TASK();
|
||||
int init(RESULT*);
|
||||
|
||||
|
@ -77,7 +80,7 @@ public:
|
|||
void suspend();
|
||||
void unsuspend();
|
||||
|
||||
bool update_time();
|
||||
bool check_app_status_files();
|
||||
|
||||
int write(FILE*);
|
||||
int parse(FILE*, CLIENT_STATE*);
|
||||
|
|
|
@ -300,7 +300,6 @@ int CLIENT_STATE::exit() {
|
|||
}
|
||||
|
||||
int CLIENT_STATE::exit_tasks() {
|
||||
int retval;
|
||||
active_tasks.exit_tasks();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -512,7 +512,7 @@ void RESULT::clear() {
|
|||
is_active = false;
|
||||
is_compute_done = false;
|
||||
is_server_ack = false;
|
||||
cpu_time = 0;
|
||||
final_cpu_time = 0;
|
||||
exit_status = 0;
|
||||
strcpy(stderr_out, "");
|
||||
app = NULL;
|
||||
|
@ -563,7 +563,7 @@ int RESULT::parse_state(FILE* in) {
|
|||
output_files.push_back(file_ref);
|
||||
continue;
|
||||
}
|
||||
else if (parse_double(buf, "<cpu_time>", cpu_time)) continue;
|
||||
else if (parse_double(buf, "<final_cpu_time>", final_cpu_time)) continue;
|
||||
else if (parse_int(buf, "<exit_status>", exit_status)) continue;
|
||||
else if (match_tag(buf, "<stderr_out>" )) {
|
||||
while (fgets(buf, 256, in)) {
|
||||
|
@ -589,10 +589,10 @@ int RESULT::write(FILE* out, bool to_server) {
|
|||
"<result>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <exit_status>%d</exit_status>\n"
|
||||
" <cpu_time>%f</cpu_time>\n",
|
||||
" <final_cpu_time>%f</final_cpu_time>\n",
|
||||
name,
|
||||
exit_status,
|
||||
cpu_time
|
||||
final_cpu_time
|
||||
);
|
||||
n = strlen(stderr_out);
|
||||
if (n) {
|
||||
|
|
|
@ -177,7 +177,7 @@ struct RESULT {
|
|||
bool is_active; // an app is currently running for this
|
||||
bool is_compute_done; // computation finished
|
||||
bool is_server_ack; // ack received from scheduling server
|
||||
double cpu_time; // cpu time spent completing result
|
||||
double final_cpu_time;
|
||||
int exit_status;
|
||||
char stderr_out[STDERR_MAX_LEN];
|
||||
APP* app;
|
||||
|
|
|
@ -50,7 +50,7 @@ int CLIENT_STATE::app_finished(ACTIVE_TASK& at) {
|
|||
at.result->is_active = false;
|
||||
at.result->is_compute_done = true;
|
||||
update_avg_cpu(at.result->project);
|
||||
at.result->project->exp_avg_cpu += at.result->cpu_time;
|
||||
at.result->project->exp_avg_cpu += at.result->final_cpu_time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,8 @@ double CLIENT_STATE::current_water_days() {
|
|||
for (i=0; i<results.size(); i++) {
|
||||
rp = results[i];
|
||||
if (rp->is_compute_done) continue;
|
||||
if (rp->cpu_time > 0) {
|
||||
seconds_remaining += (rp->wup->seconds_to_complete - rp->cpu_time);
|
||||
} else {
|
||||
seconds_remaining += rp->wup->seconds_to_complete;
|
||||
}
|
||||
// TODO: subtract time already finished for WUs in progress
|
||||
seconds_remaining += rp->wup->seconds_to_complete;
|
||||
}
|
||||
return (seconds_remaining * SECONDS_IN_DAY);
|
||||
}
|
||||
|
|
|
@ -38,9 +38,6 @@ static void c2x(char *what) {
|
|||
char d1 = num / 16;
|
||||
char d2 = num % 16;
|
||||
int abase1, abase2;
|
||||
if(what==NULL) {
|
||||
fprintf(stderr, "error: c2x: unexpected NULL pointer what\n");
|
||||
}
|
||||
if (d1 < 10) abase1 = 48;
|
||||
else abase1 = 55;
|
||||
if (d2 < 10) abase2 = 48;
|
||||
|
@ -57,12 +54,6 @@ static void c2x(char *what) {
|
|||
//
|
||||
static void escape_url(char *in, char* out) {
|
||||
int x, y;
|
||||
if(in==NULL) {
|
||||
fprintf(stderr, "error: escape_url: unexpected NULL pointer in\n");
|
||||
}
|
||||
if(out==NULL) {
|
||||
fprintf(stderr, "error: escape_url: unexpected NULL pointer out\n");
|
||||
}
|
||||
for (x=0, y=0; in[x]; ++x) {
|
||||
if (isalnum(in[x]) || in[x]=='.' || in[x]=='-' || in[x]=='_') {
|
||||
out[y] = in[x];
|
||||
|
@ -85,14 +76,9 @@ static void escape_url(char *in, char* out) {
|
|||
// Gets the pathname of a file
|
||||
//
|
||||
void get_pathname(FILE_INFO* fip, char* path) {
|
||||
if(fip==NULL) {
|
||||
fprintf(stderr, "error: get_pathname: unexpected NULL pointer fip\n");
|
||||
}
|
||||
if(path==NULL) {
|
||||
fprintf(stderr, "error: get_pathname: unexpected NULL pointer path\n");
|
||||
}
|
||||
PROJECT* p = fip->project;
|
||||
char buf[256];
|
||||
|
||||
// for testing purposes, it's handy to allow a FILE_INFO without
|
||||
// an associated PROJECT.
|
||||
//
|
||||
|
@ -107,12 +93,6 @@ void get_pathname(FILE_INFO* fip, char* path) {
|
|||
// Returns the location of a numbered slot directory
|
||||
//
|
||||
void get_slot_dir(int slot, char* path) {
|
||||
if(path==NULL) {
|
||||
fprintf(stderr, "error: get_slot_dir: unexpected NULL pointer path\n");
|
||||
}
|
||||
if(slot<0) {
|
||||
fprintf(stderr, "error: get_slot_dir: negative slot\n");
|
||||
}
|
||||
sprintf(path, "slots/%d", slot);
|
||||
}
|
||||
|
||||
|
@ -173,10 +153,6 @@ int make_slot_dir(int slot) {
|
|||
// Returns a filename used for prefs backup
|
||||
//
|
||||
int make_prefs_backup_name(PREFS& prefs, char* name) {
|
||||
if(name==NULL) {
|
||||
fprintf(stderr, "error: make_prefs_backup_name: unexpected NULL pointer name\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
sprintf(name, "prefs_backup_%d", prefs.mod_time);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -70,13 +70,10 @@ char failed_file[256];
|
|||
// routines for enumerating the entries in a directory
|
||||
|
||||
// Open a directory
|
||||
//
|
||||
DIR *dir_open(char* p) {
|
||||
DIR *dirp;
|
||||
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: dir_open: unexpected NULL pointer p\n");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef HAVE_DIRENT_H
|
||||
dirp = opendir(p);
|
||||
if (!dirp) return NULL;
|
||||
|
@ -97,22 +94,14 @@ DIR *dir_open(char* p) {
|
|||
// Scan through a directory and return the next file name in it
|
||||
//
|
||||
int dir_scan(char* p, DIR *dirp) {
|
||||
if(p==NULL) {
|
||||
fprintf(stderr, "error: dir_scan: unexpected NULL pointer p\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if( !dirp )
|
||||
return -1;
|
||||
#ifdef HAVE_DIRENT_H
|
||||
while (1) {
|
||||
dirent* dp = readdir(dirp);
|
||||
if (dp) {
|
||||
if (dp->d_name[0] == '.') continue;
|
||||
if (p) strncpy(p, dp->d_name, 255);
|
||||
if (p) strcpy(p, dp->d_name);
|
||||
return 0;
|
||||
} else {
|
||||
closedir(dirp);
|
||||
dirp = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -151,11 +140,10 @@ int dir_scan(char* p, DIR *dirp) {
|
|||
|
||||
// Close a directory
|
||||
//
|
||||
void dir_close( DIR* dirp ) {
|
||||
void dir_close(DIR* dirp) {
|
||||
#ifdef HAVE_DIRENT_H
|
||||
if (dirp) {
|
||||
closedir(dirp);
|
||||
dirp = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
|
@ -165,7 +153,7 @@ void dir_close( DIR* dirp ) {
|
|||
}
|
||||
#endif
|
||||
#ifdef macintosh
|
||||
SayErr("\pdir_close called (empty function)"); /* CAF Temp */
|
||||
SayErr("\pdir_close called (empty function)"); /* CAF Temp */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -173,10 +161,7 @@ void dir_close( DIR* dirp ) {
|
|||
//
|
||||
int file_delete(char* path) {
|
||||
int retval,i;
|
||||
if(path==NULL) {
|
||||
fprintf(stderr, "error: file_delete: unexpected NULL pointer path\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
#ifdef HAVE_UNISTD_H
|
||||
retval = unlink(path);
|
||||
|
@ -198,54 +183,41 @@ int file_delete(char* path) {
|
|||
int file_size(char* path, int& size) {
|
||||
struct stat sbuf;
|
||||
int retval;
|
||||
if(path==NULL) {
|
||||
fprintf(stderr, "error: file_size: unexpected NULL pointer path\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
retval = stat(path, &sbuf);
|
||||
if (retval) return retval;
|
||||
size = sbuf.st_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* boinc_link creates a file (new_link) which contains an XML
|
||||
reference (soft link) to existing. */
|
||||
|
||||
int boinc_link( char *existing, char *new_link ) {
|
||||
// create a file (new_link) which contains an XML
|
||||
// reference to existing file.
|
||||
//
|
||||
int boinc_link(char *existing, char *new_link) {
|
||||
FILE *fp;
|
||||
if(existing==NULL) {
|
||||
fprintf(stderr, "error: boinc_link: unexpected NULL pointer existing\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
if(new_link==NULL) {
|
||||
fprintf(stderr, "error: boinc_link: unexpected NULL pointer new_link\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
fp = fopen( new_link, "wb" );
|
||||
|
||||
fp = fopen(new_link, "wb");
|
||||
if (!fp) return ERR_FOPEN;
|
||||
rewind( fp );
|
||||
fprintf( fp, "<soft_link>%s</soft_link>\n", existing );
|
||||
fclose( fp );
|
||||
fprintf(fp, "<soft_link>%s</soft_link>\n", existing);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
// Goes through directory specified by dirpath and removes all files from it
|
||||
//
|
||||
int clean_out_dir(char* dirpath) {
|
||||
char filename[256], path[256];
|
||||
int retval;
|
||||
DIR *dirp;
|
||||
if(dirpath==NULL) {
|
||||
fprintf(stderr, "error: clean_out_dir: unexpected NULL pointer dirpath\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
dirp = dir_open(dirpath);
|
||||
if (!dirp) return -1;
|
||||
while (1) {
|
||||
strcpy(filename,"");
|
||||
retval = dir_scan(filename,dirp);
|
||||
retval = dir_scan(filename, dirp);
|
||||
if (retval) break;
|
||||
sprintf(path, "%s/%s", dirpath, filename);
|
||||
retval = file_delete(path);
|
||||
|
@ -262,25 +234,19 @@ int clean_out_dir(char* dirpath) {
|
|||
// total size of files in it and its subdirectories
|
||||
//
|
||||
double dir_size(char* dirpath) {
|
||||
char filename[256], *path;
|
||||
char filename[256], subdir[256];
|
||||
int retval,temp;
|
||||
double cur_size = 0;
|
||||
DIR *dirp;
|
||||
|
||||
if(dirpath==NULL) {
|
||||
fprintf(stderr, "error: dir_size: unexpected NULL pointer dirpath\n");
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
path = (char *)malloc( 256*sizeof( char ) );
|
||||
dirp = dir_open(dirpath);
|
||||
if (!dirp) return -1;
|
||||
while (1) {
|
||||
retval = dir_scan(filename,dirp);
|
||||
retval = dir_scan(filename, dirp);
|
||||
if (retval) break;
|
||||
sprintf(path, "%s/%s", dirpath, filename);
|
||||
cur_size += dir_size( path );
|
||||
retval = file_size(path,temp);
|
||||
sprintf(subdir, "%s/%s", dirpath, filename);
|
||||
cur_size += dir_size(subdir);
|
||||
retval = file_size(subdir, temp);
|
||||
if (retval) {
|
||||
dir_close(dirp);
|
||||
return cur_size;
|
||||
|
|
|
@ -25,6 +25,6 @@ extern int dir_scan(char*,DIR*);
|
|||
extern void dir_close(DIR*);
|
||||
extern int file_delete(char*);
|
||||
extern int file_size(char*, int&);
|
||||
extern int boinc_link( char *existing, char *new_link );
|
||||
extern int boinc_link(char *existing, char *new_link);
|
||||
extern int clean_out_dir(char*);
|
||||
extern double dir_size(char* dirpath);
|
||||
|
|
132
doc/api.html
132
doc/api.html
|
@ -9,45 +9,45 @@ The graphics API is described <a href=graphics.html>separately</a>.
|
|||
<h3>Initialization and termination</h3>
|
||||
The application must call
|
||||
<pre>
|
||||
int boinc_init(bool is_main_program, char** init_data_xml)
|
||||
int boinc_init();
|
||||
</pre>
|
||||
before calling other BOINC functions or doing I/O.
|
||||
<tt>is_main_program</tt> indicates whether the program
|
||||
is the application's main program (normally true - see below).
|
||||
Various information is returned in the malloced <tt>init_data_xml</tt>,
|
||||
an XML string that may contain the following elements:
|
||||
It may call
|
||||
<pre>
|
||||
<init_data>
|
||||
<app_preferences>...</app_preferences>
|
||||
<user_name>...</user_name>
|
||||
<team_name>...</team_name>
|
||||
<wu_cpu_time>...</wu_cpu_time>
|
||||
<total_cobblestones>...</total_cobblestones>
|
||||
<recent_avg_cobblestones>...</recent_avg_cobblestones>
|
||||
</init_data>
|
||||
struct APP_INIT_DATA {
|
||||
char project_preferences[4096];
|
||||
char user_name[256];
|
||||
char team_name[256];
|
||||
double wu_cpu_time; // cpu time from previous sessions
|
||||
double total_cobblestones;
|
||||
double recent_avg_cobblestones;
|
||||
};
|
||||
|
||||
int boinc_get_init_data(APP_INIT_DATA&);
|
||||
</pre>
|
||||
to get the following information:
|
||||
<ul>
|
||||
<li><b>app_preferences</b>: arbitrary text (generally XML);
|
||||
the participant's preferences for this project.
|
||||
<li><b>user_name</b>: the user's account name for this project
|
||||
<li><b>team_name</b>: the user's team name, if any, for this project
|
||||
<li><b>wu_cpu_time</b>: the CPU time used so far for this work unit
|
||||
<li><b>total_cobblestones</b>: the user's total credit
|
||||
<li><b>recent_avg_cobblestones</b>: the user's recent average credit
|
||||
<li> <b>project_preferences</b>: An XML string containing
|
||||
the user's project-specific preferences.
|
||||
<li> <b>user_name</b>: the user's "screen name" on this project.
|
||||
<li> <b>team_name</b>: the user's team name, if any.
|
||||
<li> <b>wu_cpu_time</b>: the CPU time spent on this WU so far
|
||||
<li> <b>total_cobblestones</b>: the user's total work for this project.
|
||||
<li> <b>recent_avg_cobblestones</b>: the recent average work per day.
|
||||
</ul>
|
||||
<p>
|
||||
These items might be used by the application in its graphics.
|
||||
They can be parsed using the functions in lib/parse.C.
|
||||
At any time it may call
|
||||
<pre>
|
||||
double boinc_cpu_time();
|
||||
</pre>
|
||||
to get its current CPU time.
|
||||
<p>
|
||||
When the application has completed successfully it must call
|
||||
When the application has completed it must call
|
||||
<pre>
|
||||
int boinc_finish();
|
||||
</pre>
|
||||
before exiting.
|
||||
An application that encounters a fatal error must call
|
||||
<pre>
|
||||
void exit(int error);
|
||||
int boinc_finish(int status);
|
||||
</pre>
|
||||
<tt>status</tt> is nonzero if an error was encountered.
|
||||
|
||||
<h3>Resolving file names</h3>
|
||||
Applications that use named input or output files must call
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
int _putchar(char);
|
||||
int puts(char*);
|
||||
int printf(char* format, ...);
|
||||
size_t write(const void* buf, size_t count);
|
||||
size_t write(const void* buf, size_t size, size_t nitems);
|
||||
int close();
|
||||
int flush();
|
||||
};
|
||||
|
@ -115,42 +115,44 @@ then call
|
|||
<pre>
|
||||
void boinc_checkpoint_completed();
|
||||
</pre>
|
||||
A call to <tt>boinc_time_to_checkpoint()</tt> is extremely fast,
|
||||
so there is little penalty in calling it frequently.
|
||||
|
||||
<h3>Fraction done</h3>
|
||||
The core client GUI displays the percent done of workunits in progress.
|
||||
To keep this display current, an application should
|
||||
periodically call
|
||||
<pre>
|
||||
boinc_percent_done(double fraction_done);
|
||||
boinc_fraction_done(double fraction_done);
|
||||
</pre>
|
||||
The <tt>fraction_done</tt> argument is a rough estimate of the
|
||||
workunit fraction complete (0 to 1).
|
||||
This function is extremely fast and can be called often.
|
||||
|
||||
<h3>Multi-program applications</h3>
|
||||
Some applications consist of multiple programs:
|
||||
a <b>main program</b> that acts as coordinator,
|
||||
and one or more subsidiary programs.
|
||||
Each program should use the BOINC API as described above,
|
||||
using the appropriate argument to <tt>boinc_init()</tt>.
|
||||
Each program should use the BOINC API as described above.
|
||||
<p>
|
||||
For checkpointing, each program has its own state file;
|
||||
Each program should have its own state file;
|
||||
the state file of the coordinator program records
|
||||
which subsidiary program was last active.
|
||||
<p>
|
||||
To correctly implement percent done,
|
||||
To correctly implement fraction done,
|
||||
the main program should pass information to subsidiary programs
|
||||
(perhaps as command-line arguments) the starting and ending
|
||||
(perhaps as command-line arguments) indicating the starting and ending
|
||||
fractions for that program.
|
||||
<p>
|
||||
The coordinator must call
|
||||
<pre>
|
||||
boinc_child_start();
|
||||
void boinc_child_start();
|
||||
</pre>
|
||||
prior to forking a child process.
|
||||
When the child is done, the coordinator
|
||||
must get the child's CPU time, then call
|
||||
<pre>
|
||||
boinc_child_done(double total_CPU);
|
||||
void boinc_child_done(double total_cpu);
|
||||
</pre>
|
||||
before forking the next child process.
|
||||
|
||||
|
@ -164,9 +166,8 @@ Input and output files are kept outside the catbox.
|
|||
The mappings from virtual to physical filenames use
|
||||
"symbolic link" files in the catbox directory.
|
||||
The name of such a file is the virtual name,
|
||||
and it contains an XML tag with the physical name.
|
||||
This scheme is necessary because of the lack of filesystem links
|
||||
in Windows.
|
||||
and the file contains an XML tag with the physical name.
|
||||
(This scheme is used because of the lack of filesystem links in Windows.)
|
||||
|
||||
<p>
|
||||
Communication between the core client and applications
|
||||
|
@ -189,10 +190,11 @@ as well as the minimum checkpoint period.
|
|||
<b>Files created by the API implementation, read by the core client:</b>
|
||||
<ul>
|
||||
<li>
|
||||
<b>percent_done.xml</b>:
|
||||
contains the WU percent done.
|
||||
<b>fraction_done.xml</b>:
|
||||
contains the WU fraction done and the current CPU time from start of WU.
|
||||
Written by the timer routine as needed.
|
||||
|
||||
<li>
|
||||
<b>checkpoint_cpu.xml</b>
|
||||
CPU time (from start of WU) at last checkpoint.
|
||||
Written by checkpoint_completed.
|
||||
|
@ -204,6 +206,50 @@ the real-time clock is not available to applications.
|
|||
This timer is used for several purposes:
|
||||
<ul>
|
||||
<li> To tell the app when to checkpoint;
|
||||
<li> To regenerate the percent done file
|
||||
<li> To regenerate the fraction done file
|
||||
<li> To refresh graphics
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<b>Exit status</b>
|
||||
The core client does a wait() to get the status.
|
||||
boinc_finish() ends with an exit(status);
|
||||
<p>
|
||||
<b>Accounting of CPU time</b>:
|
||||
(note: in Unix, a parent can't get the CPU time of a child
|
||||
until the child exits. So we're forced to measure it in the child.)
|
||||
The core passes the WU CPU time in init_data.xml.
|
||||
boinc_checkpoint_done() and boinc_finish() compute the new WU CPU time,
|
||||
and write it to checkpoint_cpu.xml.
|
||||
The core deletes this after reading.
|
||||
If on exit there is no checkpoint_cpu.xml, it means the app
|
||||
called exit(0) rather than boinc_finish().
|
||||
In this case the core measures the child CPU itself.
|
||||
<p>
|
||||
The core client maintains
|
||||
<p>
|
||||
<b>Timing of checkpoints</b>
|
||||
<p>
|
||||
The app library maintains time_until_checkpoint,
|
||||
decremented from the timer handler.
|
||||
boinc_time_to_checkpoint() returns true if this is zero or less.
|
||||
boinc_checkpoint_done() resets it.
|
||||
|
||||
<p>
|
||||
<b>Maintaining fraction done and current CPU</b>
|
||||
<p>
|
||||
These two quantities are transferred from the app library to
|
||||
the core client in the file fraction_done.xml.
|
||||
The parameter <tt>time_until_fraction_done_update</tt>,
|
||||
passed in the initialization file,
|
||||
determines how often this file is written.
|
||||
It is written from the timer handler.
|
||||
<p>
|
||||
For multi-program applications, only the active application
|
||||
must write the file.
|
||||
The functions boinc_child_start() and boinc_child_done()
|
||||
tell the app library to stop and start writing the file.
|
||||
<p>
|
||||
TO DO: this creates disk traffic.
|
||||
Either figure out a way of increasing the period for users who don't
|
||||
want disk access, or don't use disk files.
|
||||
|
|
Loading…
Reference in New Issue