Added comments throughout code.

svn path=/trunk/boinc/; revision=202
This commit is contained in:
Eric Heien 2002-07-15 23:21:20 +00:00
parent 27f57f30b7
commit 0801522cb0
25 changed files with 503 additions and 90 deletions

View File

@ -49,16 +49,17 @@
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <ctype.h>
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <ctype.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "client_types.h"
#include "client_state.h"
#include "client_types.h"
#include "filesys.h"
#include "file_names.h"
#include "log_flags.h"
@ -67,19 +68,23 @@
#include "app.h"
#include "api.h"
// take a string containing some words.
// take a string containing some space separated words.
// return an array of pointers to the null-terminated words.
// Modifies the string arg.
//
void parse_command_line(char* p, char** argv) {
// TODO: use strtok here
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;
@ -93,40 +98,59 @@ void parse_command_line(char* p, char** argv) {
p++;
}
*pp++ = 0;
return 0;
}
static void print_argv(char** argv) {
// Goes through an array of strings, and prints each string
//
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]);
}
return 0;
}
// Initialize the ACTIVE_TASK object members to null
//
ACTIVE_TASK::ACTIVE_TASK() {
result = NULL;
wup = NULL;
app_version = NULL;
pid = 0;
slot = 0;
state = PROCESS_UNINITIALIZED;
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;
return 0;
}
// Start a task in a slot directory. This includes setting up soft links,
// passing preferences, and starting the actual process for computation
//
int ACTIVE_TASK::start(bool first_time) {
char exec_name[256], file_path[256], link_path[256],temp[256];
char* argv[100];
@ -139,37 +163,42 @@ int ACTIVE_TASK::start(bool first_time) {
APP_IN app_prefs;
prev_cpu_time = 0;
// These should be chosen in a better manner
// 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;
// Write out the app prefs
// 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 );
}
return -1;
return ERR_FOPEN;
}
rewind( prefs_fd );
write_core_file( prefs_fd,app_prefs );
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 ) {
printf( "Failed to open init file %s.\n", init_path );
}
return -1;
return ERR_FOPEN;
}
rewind( init_file );
// make a link to the executable
// make a soft link to the executable(s)
//
for (i=0; i<app_version->app_files.size(); i++) {
fip = app_version->app_files[i].file_info;
@ -217,7 +246,7 @@ int ACTIVE_TASK::start(bool first_time) {
}
}
// hook up the output files
// hook up the output files using BOINC soft links
//
for (i=0; i<result->output_files.size(); i++) {
file_ref = result->output_files[i];
@ -326,15 +355,15 @@ int ACTIVE_TASK::start(bool first_time) {
}
pid_handle = process_info.hProcess;
#endif
#ifdef macintosh
#endif
state = PROCESS_RUNNING;
return 0;
}
// Sends a request to the process of this active task to exit. If it
// doesn't exist within a set time (seconds), the process is terminated
//
void ACTIVE_TASK::request_exit(int seconds) {
int retval;
if(seconds<0) {
@ -355,6 +384,8 @@ void ACTIVE_TASK::request_exit(int seconds) {
#endif
}
// Inserts an active task into the ACTIVE_TASK_SET and starts it up
//
int ACTIVE_TASK_SET::insert(ACTIVE_TASK* atp) {
int retval;
if(atp==NULL) {
@ -369,7 +400,7 @@ int ACTIVE_TASK_SET::insert(ACTIVE_TASK* atp) {
return 0;
}
// check for child process exit
// Checks if any child processes have exited and records their final CPU time
//
bool ACTIVE_TASK_SET::poll() {
int stat;
@ -388,7 +419,6 @@ bool ACTIVE_TASK_SET::poll() {
atp = active_tasks[i];
if( GetExitCodeProcess( atp->pid_handle,&exit_code ) ) {
// Get the elapsed CPU time
// Factor this into the equivalent of a S@H etime function?
if( GetProcessTimes( atp->pid_handle, &creation_time, &exit_time, &kernel_time, &user_time ) ) {
tKernel.LowPart = kernel_time.dwLowDateTime;
tKernel.HighPart = kernel_time.dwHighDateTime;
@ -401,6 +431,7 @@ bool ACTIVE_TASK_SET::poll() {
atp->result->cpu_time = (totTime / 10000000.0);
} else {
// This probably isn't correct
atp->result->cpu_time = ((double)clock())/CLOCKS_PER_SEC;
}
if( exit_code != STILL_ACTIVE ) {
@ -465,20 +496,24 @@ bool ACTIVE_TASK_SET::poll() {
return true;
}
// Find the ACTIVE_TASK in the current set with the matching PID
//
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 0;
return NULL;
}
for (i=0; i<active_tasks.size(); i++) {
atp = active_tasks[i];
if (atp->pid == pid) return atp;
}
return 0;
return NULL;
}
// Sends a suspend request to all currently running computation processes
//
void ACTIVE_TASK_SET::suspend_all() {
unsigned int i;
ACTIVE_TASK* atp;
@ -488,6 +523,8 @@ void ACTIVE_TASK_SET::suspend_all() {
}
}
// Sends a resume signal to all currently running computation processes
//
void ACTIVE_TASK_SET::unsuspend_all() {
unsigned int i;
ACTIVE_TASK* atp;
@ -497,6 +534,9 @@ void ACTIVE_TASK_SET::unsuspend_all() {
}
}
// Attempts to exit all currently running computation processes, either
// via exit request or termination
//
void ACTIVE_TASK_SET::exit_tasks() {
unsigned int i;
ACTIVE_TASK *atp;
@ -508,26 +548,37 @@ void ACTIVE_TASK_SET::exit_tasks() {
}
#ifdef _WIN32
// Send a suspend request to the ACTIVE_TASK
//
void ACTIVE_TASK::suspend() {
prev_cpu_time = cpu_time;
// figure out a way to do this, perhaps via trigger file?
//kill(atp->pid, SIGSTOP);
}
// Send a resume request to the ACTIVE_TASK
//
void ACTIVE_TASK::unsuspend() {
// figure out a way to do this, perhaps via trigger file?
//kill(atp->pid, SIGCONT);
}
#else
// Send a suspend request to the ACTIVE_TASK
//
void ACTIVE_TASK::suspend() {
kill(this->pid, SIGSTOP);
kill(this->pid, SIGSTOP);
}
// Send a resume request to the ACTIVE_TASK
//
void ACTIVE_TASK::unsuspend() {
kill(this->pid, SIGCONT);
kill(this->pid, SIGCONT);
}
#endif
// Remove an ACTIVE_TASK from the set, assumes that the task has
// already been shut down via request_exit or similar means
//
int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
vector<ACTIVE_TASK*>::iterator iter;
if(atp==NULL) {
@ -546,6 +597,8 @@ int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
return 1;
}
// Restart active tasks without wiping and reinitializing slot directories
//
int ACTIVE_TASK_SET::restart_tasks() {
vector<ACTIVE_TASK*>::iterator iter;
ACTIVE_TASK* atp;
@ -569,6 +622,9 @@ 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
//
bool ACTIVE_TASK::update_time() {
FILE* app_fp;
char app_path[256];
@ -584,6 +640,8 @@ bool ACTIVE_TASK::update_time() {
return true;
}
// Poll each of the currently running tasks and get their CPU time
//
bool ACTIVE_TASK_SET::poll_time() {
ACTIVE_TASK* atp;
unsigned int i;
@ -595,6 +653,8 @@ bool ACTIVE_TASK_SET::poll_time() {
return updated;
}
// 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");
@ -617,6 +677,8 @@ int ACTIVE_TASK::write(FILE* fout) {
return 0;
}
// Parse XML information about an active task
//
int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
char buf[256], result_name[256], project_master_url[256];
int app_version_num=0;
@ -666,6 +728,8 @@ int ACTIVE_TASK::parse(FILE* fin, CLIENT_STATE* cs) {
return -1;
}
// Write XML information about this active task set
//
int ACTIVE_TASK_SET::write(FILE* fout) {
unsigned int i;
if(fout==NULL) {
@ -680,6 +744,8 @@ int ACTIVE_TASK_SET::write(FILE* fout) {
return 0;
}
// Parse XML information about an active task set
//
int ACTIVE_TASK_SET::parse(FILE* fin, CLIENT_STATE* cs) {
ACTIVE_TASK* atp;
char buf[256];

View File

@ -20,6 +20,8 @@
#ifndef _TASK_
#define _TASK_
// Possible states of a process in an ACTIVE_TASK
#define PROCESS_UNINITIALIZED 0
#define PROCESS_RUNNING 1
#define PROCESS_EXITED 2
#define PROCESS_WAS_SIGNALED 3

View File

@ -33,6 +33,7 @@
#define SECONDS_IN_MONTH 2592000
// Global CLIENT_STATE object
CLIENT_STATE gstate;
CLIENT_STATE::CLIENT_STATE() {
@ -74,6 +75,9 @@ int CLIENT_STATE::init(PREFS* p) {
if (log_flags.state_debug) {
print_counts();
}
// Finally, set up the project and slot directories
//
make_project_dirs();
make_slot_dirs();
@ -81,6 +85,8 @@ int CLIENT_STATE::init(PREFS* p) {
}
// Returns true if time tests should be run
// This is determined by seeing if the user passed the "-no_time_test"
// flag or if it's been a month since we last checked time stats
//
bool CLIENT_STATE::run_time_tests() {
return (run_time_test && (
@ -88,7 +94,7 @@ bool CLIENT_STATE::run_time_tests() {
));
}
// Updates computer statistics once per month
// Updates computer statistics (roughly once a month)
//
int CLIENT_STATE::time_tests() {
get_host_info(host_info); // this is platform dependent
@ -124,6 +130,9 @@ int CLIENT_STATE::check_suspend_activities() {
return 0;
}
// do_something is where all the action happens. This is part of the
// finite state machine abstraction of the client. Each of the key
// elements of the client is given a chance to perform work here.
// return true if something happened
//
bool CLIENT_STATE::do_something() {
@ -150,6 +159,8 @@ bool CLIENT_STATE::do_something() {
return action;
}
// Parse the client_state.xml file
//
int CLIENT_STATE::parse_state_file() {
char buf[256];
FILE* f = fopen(STATE_FILE_NAME, "r");
@ -245,6 +256,9 @@ int CLIENT_STATE::parse_state_file() {
return ERR_XML_PARSE;
}
// Make a directory for each of the projects present
// in the client state
//
int CLIENT_STATE::make_project_dirs() {
unsigned int i;
for (i=0; i<projects.size(); i++) {
@ -253,6 +267,9 @@ int CLIENT_STATE::make_project_dirs() {
return 0;
}
// Make a directory for each of the available slots specified
// in the client state
//
int CLIENT_STATE::make_slot_dirs() {
unsigned int i;
for (i=0; i<nslots; i++) {
@ -261,6 +278,10 @@ int CLIENT_STATE::make_slot_dirs() {
return 0;
}
// Perform a graceful shutdown of the client, including quitting
// all applications, checking their final status, and writing
// the client_state.xml file
//
int CLIENT_STATE::exit_tasks() {
int retval;
active_tasks.exit_tasks();
@ -273,6 +294,8 @@ int CLIENT_STATE::exit_tasks() {
return 0;
}
// Writes the client_state.xml file
//
int CLIENT_STATE::write_state_file() {
unsigned int i, j;
FILE* f = fopen(STATE_FILE_TEMP, "wb");
@ -327,6 +350,10 @@ int CLIENT_STATE::write_state_file() {
return 0;
}
// See if the project specified by master_url already exists
// in the client state record.
// TODO: make this smarter (i.e. www.project.com is the same as project.com)
//
PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
if(master_url==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_project: unexpected NULL pointer master_url\n");
@ -340,6 +367,9 @@ PROJECT* CLIENT_STATE::lookup_project(char* master_url) {
return 0;
}
// See if the application (name) associated with project p is
// around here
//
APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
if(p==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_app: unexpected NULL pointer p\n");
@ -356,6 +386,9 @@ APP* CLIENT_STATE::lookup_app(PROJECT* p, char* name) {
return 0;
}
// See if the result (name) associated with project p is
// around here
//
RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
if(p==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_result: unexpected NULL pointer p\n");
@ -372,6 +405,9 @@ RESULT* CLIENT_STATE::lookup_result(PROJECT* p, char* name) {
return 0;
}
// See if the workunit (name) associated with project p is
// around here
//
WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
if(p==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_workunit: unexpected NULL pointer p\n");
@ -388,6 +424,9 @@ WORKUNIT* CLIENT_STATE::lookup_workunit(PROJECT* p, char* name) {
return 0;
}
// See if the app_version (name) associated with project p is
// around here
//
APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
if(app==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_app_version: unexpected NULL pointer app\n");
@ -406,6 +445,9 @@ APP_VERSION* CLIENT_STATE::lookup_app_version(APP* app, int version_num) {
return 0;
}
// See if the file info (name) associated with project p is
// around here
//
FILE_INFO* CLIENT_STATE::lookup_file_info(PROJECT* p, char* name) {
if(p==NULL) {
fprintf(stderr, "error: CLIENT_STATE.lookup_file_info: unexpected NULL pointer p\n");
@ -580,6 +622,9 @@ int CLIENT_STATE::link_result(PROJECT* p, RESULT* rp) {
return 0;
}
// Print debugging information about how many projects/files/etc
// are currently in the client state record
//
void CLIENT_STATE::print_counts() {
if (log_flags.state_debug) {
printf(
@ -696,6 +741,12 @@ int CLIENT_STATE::write_state_file_if_needed() {
return 0;
}
// Parse the command line arguments passed to the client for specific flags:
// -exit_when_idle: the client will exit when it has no more work to do
// -no_time_test: the client will skip the speed and host information checks
// -exit_after: the client will exit after X iterations of the do_something loop
// (usually about X seconds)
//
void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
int i;
if(argc<0) {
@ -720,6 +771,8 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
}
}
// Returns true if the core client should exit
//
bool CLIENT_STATE::time_to_exit() {
if (!exit_when_idle && (exit_after != 0)) return false;
if (results.size() == 0 && contacted_sched_server) return true;

View File

@ -27,10 +27,26 @@
#include "client_types.h"
PROJECT::PROJECT() {
project_specific_prefs = 0;
code_sign_key = 0;
strcpy(master_url,"");
strcpy(authenticator,"");
project_specific_prefs = NULL;
resource_share = 0;
strcpy(project_name,"");
strcpy(user_name,"");
rpc_seqno = 0;
hostid = 0;
exp_avg_cpu = 0;
exp_avg_mod_time = 0;
code_sign_key = NULL;
nrpc_failures = 0;
min_rpc_time = 0;
resource_debt = 0;
debt_order = 0;
master_url_fetch_pending = 0;
}
// Destroy this project object
//
PROJECT::~PROJECT() {
if (project_specific_prefs) free(project_specific_prefs);
if (code_sign_key) free(code_sign_key);
@ -103,6 +119,8 @@ int PROJECT::parse_state(FILE* in) {
return ERR_XML_PARSE;
}
// Write the project information to prefs.xml
//
int PROJECT::write_state(FILE* out) {
unsigned int i;
if(out==NULL) {
@ -172,6 +190,8 @@ void PROJECT::copy_prefs_fields(PROJECT& p) {
resource_share = p.resource_share;
}
// Parse application XML information, usually found in client_state.xml
//
int APP::parse(FILE* in) {
char buf[256];
if(in==NULL) {
@ -189,6 +209,8 @@ int APP::parse(FILE* in) {
return ERR_XML_PARSE;
}
// Write application XML information, usually to client_state.xml
//
int APP::write(FILE* out) {
if(out==NULL) {
fprintf(stderr, "error: APP.write: unexpected NULL pointer out\n");
@ -208,6 +230,8 @@ int APP::write(FILE* out) {
FILE_INFO::FILE_INFO() {
}
// TODO: Determine what (if anything) needs to be done when destroying FILE_INFO
//
FILE_INFO::~FILE_INFO() {
}
@ -223,8 +247,8 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
}
strcpy(name, "");
strcpy(md5_cksum, "");
nbytes = 0;
max_nbytes = 0;
nbytes = 0;
generated_locally = false;
file_present = false;
executable = false;
@ -232,15 +256,17 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
upload_when_present = false;
sticky = false;
signature_required = false;
project = NULL;
file_xfer = NULL;
result = NULL;
project = NULL;
urls.clear();
if (from_server) {
signed_xml = strdup("");
} else {
signed_xml = 0;
signed_xml = NULL;
}
xml_signature = 0;
xml_signature = NULL;
file_signature = NULL;
while (fgets(buf, 256, in)) {
if (match_tag(buf, "</file_info>")) return 0;
else if (match_tag(buf, "<xml_signature>")) {
@ -279,6 +305,8 @@ int FILE_INFO::parse(FILE* in, bool from_server) {
return 1;
}
// Write out XML based file info
//
int FILE_INFO::write(FILE* out, bool to_server) {
unsigned int i;
if(out==NULL) {
@ -317,7 +345,7 @@ int FILE_INFO::write(FILE* out, bool to_server) {
return 0;
}
// delete underlying file
// delete physical underlying file associated with FILE_INFO
//
int FILE_INFO::delete_file() {
char path[256];
@ -326,6 +354,8 @@ int FILE_INFO::delete_file() {
return file_delete(path);
}
// Parse XML based app_version information, usually from client_state.xml
//
int APP_VERSION::parse(FILE* in) {
char buf[256];
FILE_REF file_ref;
@ -351,6 +381,8 @@ int APP_VERSION::parse(FILE* in) {
return 1;
}
// Write XML based app_version information, usually to client_state.xml
//
int APP_VERSION::write(FILE* out) {
unsigned int i;
if(out==NULL) {
@ -373,6 +405,8 @@ int APP_VERSION::write(FILE* out) {
return 0;
}
// Parse XML based file_ref information, usually from client_state.xml
//
int FILE_REF::parse(FILE* in) {
char buf[256];
if(in==NULL) {
@ -394,19 +428,21 @@ int FILE_REF::parse(FILE* in) {
return 1;
}
// Write XML based file_ref information, usually to client_state.xml
//
int FILE_REF::write(FILE* out) {
if(out==NULL) {
fprintf(stderr, "error: FILE_REF.write: unexpected NULL pointer out\n");
return ERR_NULL;
}
if (strlen(open_name)) {
fprintf(out, " <open_name>%s</open_name>\n", open_name);
}
fprintf(out,
" <file_ref>\n"
" <file_name>%s</file_name>\n",
file_name
);
if (strlen(open_name)) {
fprintf(out, " <open_name>%s</open_name>\n", open_name);
}
if (fd >= 0) {
fprintf(out, " <fd>%d</fd>\n", fd);
}
@ -417,6 +453,8 @@ int FILE_REF::write(FILE* out) {
return 0;
}
// Parse XML based workunit information, usually from client_state.xml
//
int WORKUNIT::parse(FILE* in) {
char buf[256];
FILE_REF file_ref;
@ -450,6 +488,8 @@ int WORKUNIT::parse(FILE* in) {
return 1;
}
// Write XML based workunit information, usually to client_state.xml
//
int WORKUNIT::write(FILE* out) {
unsigned int i;
if(out==NULL) {
@ -612,6 +652,8 @@ int RESULT::write(FILE* out, bool to_server) {
}
// this is called only after is_compute_done is true.
// returns true if the result and it's associated files
// were successfully uploaded
//
bool RESULT::is_upload_done() {
unsigned int i;

2
client/configure vendored
View File

@ -1505,7 +1505,7 @@ EOF
fi
for ac_hdr in fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h arpa/inet.h sys/resource.h signal.h sys/wait.h
for ac_hdr in fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/socket.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h netinet/tcp.h arpa/inet.h sys/resource.h signal.h sys/wait.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6

View File

@ -37,7 +37,7 @@ AC_CHECK_LIB(stdc++, cerr)
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h arpa/inet.h sys/resource.h signal.h sys/wait.h)
AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/select.h sys/statvfs.h sys/swap.h sys/systeminfo.h sys/socket.h sys/types.h dirent.h sys/utsname.h netdb.h netinet/in.h netinet/tcp.h arpa/inet.h sys/resource.h signal.h sys/wait.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

View File

@ -54,7 +54,7 @@ int CLIENT_STATE::app_finished(ACTIVE_TASK& at) {
return 0;
}
// poll and clean up after existing apps
// poll status of existing apps and and clean up after them
//
bool CLIENT_STATE::handle_running_apps() {
unsigned int i;
@ -80,6 +80,9 @@ bool CLIENT_STATE::handle_running_apps() {
return action;
}
// Returns true if all the input files for a result are available
// locally, false otherwise
//
bool CLIENT_STATE::input_files_available(RESULT* rp) {
if(rp==NULL) {
fprintf(stderr, "error: CLIENT_STATE.input_files_available: unexpected NULL pointer rp\n");
@ -111,6 +114,8 @@ bool CLIENT_STATE::start_apps() {
bool action = false;
for (i=0; i<results.size(); i++) {
// If all the app slots are already used, we can't start
// a new app
if (active_tasks.active_tasks.size() == nslots) {
if (log_flags.task_debug) {
printf("start_apps(): all slots full\n");
@ -118,6 +123,10 @@ bool CLIENT_STATE::start_apps() {
return 0;
}
rp = results[i];
// Start the application to compute a result if the result
// isn't done yet, the application isn't currently computing
// the result, and all the input files for the result are
// locally available
if (!rp->is_compute_done && !rp->is_active && input_files_available(rp)) {
if (log_flags.task_debug) {
printf("starting application for result %s\n", rp->name);
@ -133,7 +142,7 @@ bool CLIENT_STATE::start_apps() {
return action;
}
// This is called on initialization.
// This is called when the client is initialized.
// Try to restart any tasks that were running when we last shut down.
//
int CLIENT_STATE::restart_tasks() {

View File

@ -39,6 +39,9 @@
#include "client_state.h"
#include "error_numbers.h"
// Verify the validity of a downloaded file, through MD5 checksum
// or an RSA signature
//
int verify_downloaded_file(char* pathname, FILE_INFO& file_info) {
char cksum[64];
PROJECT* project;
@ -77,6 +80,10 @@ int verify_downloaded_file(char* pathname, FILE_INFO& file_info) {
return 0;
}
// scan all FILE_INFOs.
// start downloads and uploads as needed.
// check for completion of existing transfers
//
bool CLIENT_STATE::start_file_xfers() {
unsigned int i;
FILE_INFO* fip;
@ -85,10 +92,6 @@ bool CLIENT_STATE::start_file_xfers() {
int retval;
bool action = false;
// scan all FILE_INFOs.
// start downloads and uploads as needed.
// check for completion of existing transfers
//
for (i=0; i<file_infos.size(); i++) {
fip = file_infos[i];
fxp = fip->file_xfer;

View File

@ -158,6 +158,10 @@ PROJECT* CLIENT_STATE::choose_project() {
}
#endif
// Compute the "resource debt" of each project. This is used
// to determine what project we will focus on next, based on
// the user specified resource share
//
void CLIENT_STATE::compute_resource_debts() {
unsigned int i, j;
PROJECT* p, *pbest;
@ -190,6 +194,10 @@ void CLIENT_STATE::compute_resource_debts() {
}
}
// Prepare the scheduler request. This writes the request in XML to a
// file (SCHED_OP_REQUEST_FILE) which is later sent to the scheduling
// server
//
int CLIENT_STATE::make_scheduler_request(PROJECT* p, double work_req) {
FILE* f = fopen(SCHED_OP_REQUEST_FILE, "wb");
unsigned int i;
@ -371,15 +379,19 @@ bool CLIENT_STATE::get_work() {
}
#endif
// see whether a new preferences set, obtained from
// the given project, looks "reasonable".
// see whether a new preferences set, obtained from the given
// project, looks "reasonable". This is to prevent accidental or
// intentional preferences corruption
// Currently this is primitive: just make sure there's at least 1 project
//
// TODO: figure out what else to look for here
bool PREFS::looks_reasonable(PROJECT& project) {
if (projects.size() > 0) return true;
return false;
}
// Parse the reply from a scheduler and configure internal structures
// appropriately
//
void CLIENT_STATE::handle_scheduler_reply(
PROJECT* project, char* scheduler_url
) {

View File

@ -30,6 +30,8 @@
#include "file_names.h"
#include "error_numbers.h"
// Converts a character string of a decimal number to hexadecimal string
//
static void c2x(char *what) {
char buf[3];
char num = atoi(what);
@ -50,6 +52,9 @@ static void c2x(char *what) {
strcpy(what, buf);
}
// Escape a URL, converting the non alphanumeric characters to
// %XY where XY is their hexadecimal equivalent
//
static void escape_url(char *in, char* out) {
int x, y;
if(in==NULL) {
@ -77,6 +82,8 @@ static void escape_url(char *in, char* out) {
out[y] = 0;
}
// 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");
@ -97,6 +104,8 @@ 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");
@ -119,6 +128,8 @@ int make_project_dir(PROJECT& p) {
return 0;
}
// Returns the location of a numbered slot directory
//
int make_slot_dir(int slot) {
if(slot<0) {
fprintf(stderr, "error: make_slot_dir: negative slot\n");
@ -133,6 +144,8 @@ int make_slot_dir(int slot) {
#else
// Create the directory for the project p
//
int make_project_dir(PROJECT& p) {
char buf[256];
@ -141,6 +154,8 @@ int make_project_dir(PROJECT& p) {
return 0;
}
// Create the slot directory for the specified slot #
//
int make_slot_dir(int slot) {
char buf[256];
if(slot<0) {
@ -153,6 +168,8 @@ int make_slot_dir(int slot) {
return 0;
}
// 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");

View File

@ -28,12 +28,21 @@
FILE_XFER::FILE_XFER() {
file_xfer_done = false;
file_xfer_retval = 0;
start_time = 0;
end_time = 0;
fip = NULL;
strcpy(pathname,"");
strcpy(header,"");
//state = ?
}
// Do we need to do anything special when destroying the FILE_XFER object?
//
FILE_XFER::~FILE_XFER() {
}
#if 0
// Is there any reason to keep this around?
int FILE_XFER::init_download(char* url, char* outfile) {
if(url==NULL) {
fprintf(stderr, "error: FILE_XFER.init_download: unexpected NULL pointer url\n");
@ -46,6 +55,7 @@ int FILE_XFER::init_download(char* url, char* outfile) {
return HTTP_OP::init_get(url, outfile);
}
// Is there any reason to keep this around?
int FILE_XFER::init_upload(char* url, char* infile) {
if(url==NULL) {
fprintf(stderr, "error: FILE_XFER.init_upload: unexpected NULL pointer url\n");
@ -89,10 +99,14 @@ int FILE_XFER::init_upload(FILE_INFO& file_info) {
return HTTP_OP::init_post2((char*)(&fip->urls[0]), header, pathname, 0);
}
// Returns the total time that the file xfer has taken
//
double FILE_XFER::elapsed_time() {
return end_time - start_time;
}
// Create a new empty FILE_XFER_SET
//
FILE_XFER_SET::FILE_XFER_SET(HTTP_OP_SET* p) {
if(p==NULL) {
fprintf(stderr, "error: FILE_XFER_SET: unexpected NULL pointer p\n");
@ -100,6 +114,8 @@ FILE_XFER_SET::FILE_XFER_SET(HTTP_OP_SET* p) {
http_ops = p;
}
// Insert a FILE_XFER object into the set
//
int FILE_XFER_SET::insert(FILE_XFER* fxp) {
int retval;
if(fxp==NULL) {
@ -117,6 +133,8 @@ int FILE_XFER_SET::insert(FILE_XFER* fxp) {
return 0;
}
// Remove a FILE_XFER object from the set
//
int FILE_XFER_SET::remove(FILE_XFER* fxp) {
vector<FILE_XFER*>::iterator iter;
if(fxp==NULL) {
@ -138,6 +156,9 @@ int FILE_XFER_SET::remove(FILE_XFER* fxp) {
}
// Run through the FILE_XFER_SET and determine if any of the file
// transfers are complete or had an error
//
bool FILE_XFER_SET::poll() {
unsigned int i;
FILE_XFER* fxp;

View File

@ -73,6 +73,7 @@ char failed_file[256];
// routines for enumerating the entries in a directory
// Open a directory
int dir_open(char* p) {
if(p==NULL) {
fprintf(stderr, "error: dir_open: unexpected NULL pointer p\n");
@ -87,6 +88,7 @@ int dir_open(char* p) {
strcat(path, "\\*");
first = 1;
handle = INVALID_HANDLE_VALUE;
// This is probably incomplete
#endif
#ifdef macintosh
SayErr("\pdir_open called (empty function)"); /* CAF Temp */
@ -94,6 +96,8 @@ int dir_open(char* p) {
return 0;
}
// Scan through a directory and return the next file name in it
//
int dir_scan(char* p) {
if(p==NULL) {
fprintf(stderr, "error: dir_scan: unexpected NULL pointer p\n");
@ -145,6 +149,8 @@ int dir_scan(char* p) {
#endif
}
// Close a directory
//
void dir_close() {
#ifdef HAVE_DIRENT_H
if (dirp) {
@ -163,6 +169,8 @@ void dir_close() {
#endif
}
// Delete the file located at path
//
int file_delete(char* path) {
int retval,i;
if(path==NULL) {
@ -200,8 +208,8 @@ int file_size(char* path, int& size) {
return 0;
}
/* boinc_link creates a file (new) which contains an XML
reference to existing. */
/* boinc_link creates a file (new_link) which contains an XML
reference (soft link) to existing. */
int boinc_link( char *existing, char *new_link ) {
FILE *fp;
@ -222,6 +230,8 @@ int boinc_link( char *existing, char *new_link ) {
return 0;
}
// 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;

View File

@ -24,6 +24,8 @@
#include "hostinfo.h"
#include "error_numbers.h"
// Parse the host information, usually from the client state XML file
//
int HOST_INFO::parse(FILE* in) {
char buf[256];
if(in==NULL) {
@ -55,6 +57,8 @@ int HOST_INFO::parse(FILE* in) {
return 0;
}
// Write the host information, usually to the client state XML file
//
int HOST_INFO::write(FILE* out) {
if(out==NULL) {
fprintf(stderr, "error: HOST_INFO.write: unexpected NULL pointer out\n");

View File

@ -61,6 +61,9 @@
// functions to get name/addr of local host
// Returns the domain of the local host
// TODO: Should the 256 be MAXHOSTNAMELEN instead?
//
int get_local_domain_name(char* p) {
char buf[256];
if(p==NULL) {
@ -73,6 +76,8 @@ int get_local_domain_name(char* p) {
return 0;
}
// Gets the ip address of the local host
//
int get_local_ip_addr(int& p) {
char buf[256];
struct in_addr addr;
@ -85,6 +90,9 @@ int get_local_ip_addr(int& p) {
return 0;
}
// Returns the name of the local host
// TODO: Should the 256 be MAXHOSTNAMELEN instead?
//
int get_local_ip_addr_str(char* p) {
char buf[256];
if(p==NULL) {
@ -101,6 +109,8 @@ int get_local_ip_addr_str(char* p) {
return 0;
}
// Converts a int ip address to a string representation (i.e. "66.218.71.198")
//
char* ip_addr_string(int ip_addr) {
in_addr ia;
@ -108,7 +118,8 @@ char* ip_addr_string(int ip_addr) {
return inet_ntoa(ia);
}
// What does this return? # of seconds from GMT?
//
void get_timezone(int& tz) {
tzset();
@ -120,6 +131,9 @@ void get_timezone(int& tz) {
#endif
}
// Returns true if the host is currently running off battery power
// TODO: port this to other platforms (Windows, Mac OS X, others?)
//
bool host_is_running_on_batteries() {
float x1, x2;
int i1, i2;
@ -139,6 +153,8 @@ bool host_is_running_on_batteries() {
#ifdef linux
// Determine the memory specifications for this host, including RAM and swap space
//
void parse_meminfo(HOST_INFO& host) {
char buf[256];
FILE* f = fopen("/proc/meminfo", "r");
@ -157,7 +173,7 @@ void parse_meminfo(HOST_INFO& host) {
// Unfortunately the format of /proc/cpuinfo is not standardized.
// See http://people.nl.linux.org/~hch/cpuinfo/ for some examples.
// The following is for Redhat Linux 2.2.14.
//
// TODO: get this to work on all platforms
void parse_cpuinfo(HOST_INFO& host) {
char buf[256];
int n;
@ -182,6 +198,8 @@ void parse_cpuinfo(HOST_INFO& host) {
#endif
#if HAVE_SYS_UTSNAME_H
// Puts the operating system name and version into the HOST_INFO structure
//
void get_osinfo(HOST_INFO& host) {
struct utsname u;
uname(&u);
@ -190,6 +208,8 @@ void get_osinfo(HOST_INFO& host) {
}
#endif
// General function to get all relevant host information
//
int get_host_info(HOST_INFO& host) {
host.m_nbytes = 0;
host.m_cache = 0;

View File

@ -25,6 +25,8 @@
extern int get_local_domain_name(char* p);
extern int get_local_ip_addr_str(char* p);
// Gets windows specific host information (not complete)
//
int get_host_info(HOST_INFO& host) {
OSVERSIONINFO OSVersionInfo;
memset( &OSVersionInfo, NULL, sizeof( OSVersionInfo ) );

View File

@ -36,6 +36,10 @@
#define HTTP_BLOCKSIZE 4096
// Breaks a url down into its server and file path components
// TODO: deal with alternate protocols (ftp, gopher, etc) or disallow
// them and parse accordingly
//
static void parse_url(char* url, char* host, char* file) {
char* p;
char buf[256];
@ -64,6 +68,8 @@ static void parse_url(char* url, char* host, char* file) {
// We use 1.0 so we don't have to count bytes.
//
// Prints an HTTP 1.0 GET request header into buf
//
static void http_get_request_header(
char* buf, char* host, char* file, int offset
) {
@ -102,6 +108,8 @@ static void http_get_request_header(
}
}
// Prints an HTTP 1.0 HEAD request header into buf
//
static void http_head_request_header(char* buf, char* host, char* file) {
if(buf==NULL) {
fprintf(stderr, "error: http_head_request_header: unexpected NULL pointer buf\n");
@ -122,6 +130,8 @@ static void http_head_request_header(char* buf, char* host, char* file) {
);
}
// Prints an HTTP 1.0 POST request header into buf
//
static void http_post_request_header(
char* buf, char* host, char* file, int size
) {
@ -150,6 +160,8 @@ static void http_post_request_header(
}
#if 0
// Do we still need this?
//
void http_put_request_header(
char* buf, char* host, char* file, int size, int offset
) {
@ -196,6 +208,8 @@ void http_put_request_header(
}
#endif
// Parse an http reply header into the header struct
//
int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
int i, n;
char buf[1024], *p;
@ -224,6 +238,8 @@ int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
return 1;
}
// Read the contents of the socket into buf
//
static int read_reply(int socket, char* buf, int len) {
int i, n;
if(socket<0) {
@ -248,11 +264,24 @@ static int read_reply(int socket, char* buf, int len) {
HTTP_OP::HTTP_OP() {
http_op_state = HTTP_STATE_IDLE;
strcpy(hostname,"");
strcpy(filename,"");
req1 = NULL;
strcpy(infile,"");
strcpy(outfile,"");
content_length = 0;
file_offset = 0;
strcpy(request_header,"");
http_op_state = HTTP_STATE_IDLE;
http_op_type = HTTP_OP_NONE;
http_op_retval = 0;
}
HTTP_OP::~HTTP_OP() {
}
// Initialize HTTP HEAD operation to url
//
int HTTP_OP::init_head(char* url) {
if(url==NULL) {
fprintf(stderr, "error: HTTP_OP.init_head: unexpected NULL pointer url\n");
@ -266,6 +295,8 @@ int HTTP_OP::init_head(char* url) {
return 0;
}
// Initialize HTTP GET operation to url
//
int HTTP_OP::init_get(char* url, char* out, int off) {
if(url==NULL) {
fprintf(stderr, "error: HTTP_OP.init_get: unexpected NULL pointer url\n");
@ -289,6 +320,8 @@ int HTTP_OP::init_get(char* url, char* out, int off) {
return 0;
}
// Initialize HTTP POST operation to url
//
int HTTP_OP::init_post(char* url, char* in, char* out) {
int retval;
if(url==NULL) {
@ -317,6 +350,8 @@ int HTTP_OP::init_post(char* url, char* in, char* out) {
return 0;
}
// Initialize HTTP POST operation to url including file offset
//
int HTTP_OP::init_post2(
char* url, char* r1, char* in, double offset
) {
@ -355,6 +390,7 @@ int HTTP_OP::init_post2(
}
#if 0
// Is this still needed?
int HTTP_OP::init_put(char* url, char* in, int off) {
int retval;
@ -373,6 +409,8 @@ int HTTP_OP::init_put(char* url, char* in, int off) {
}
#endif
// Returns true if the HTTP operation is complete
//
bool HTTP_OP::http_op_done() {
return (http_op_state == HTTP_STATE_DONE);
}
@ -384,6 +422,8 @@ HTTP_OP_SET::HTTP_OP_SET(NET_XFER_SET* p) {
net_xfers = p;
}
// Inserts an hTTP_OP into the set
//
int HTTP_OP_SET::insert(HTTP_OP* ho) {
int retval;
if(ho==NULL) {
@ -396,6 +436,10 @@ int HTTP_OP_SET::insert(HTTP_OP* ho) {
return 0;
}
// Runs through the set of HTTP_OP objects in the set and decides
// what operation is appropriate for each. This section needs more
// thorough documentation, as it is fairly complex
//
bool HTTP_OP_SET::poll() {
unsigned int i;
HTTP_OP* htp;
@ -406,6 +450,8 @@ bool HTTP_OP_SET::poll() {
htp = http_ops[i];
switch(htp->http_op_state) {
case HTTP_STATE_CONNECTING:
// If the op is in the connecting state, and we notice it is done
// connecting, move it to the HTTP_STATE_REQUEST_HEADER state
if (htp->is_connected) {
htp->http_op_state = HTTP_STATE_REQUEST_HEADER;
htp->want_upload = true;
@ -547,6 +593,8 @@ bool HTTP_OP_SET::poll() {
return action;
}
// Remove an HTTP_OP from the set
//
int HTTP_OP_SET::remove(HTTP_OP* p) {
vector<HTTP_OP*>::iterator iter;
if(p==NULL) {
@ -567,6 +615,8 @@ int HTTP_OP_SET::remove(HTTP_OP* p) {
return 1;
}
// Returns the size of the set of HTTP_OP objects
//
int HTTP_OP_SET::size() {
return http_ops.size();
}

View File

@ -31,6 +31,7 @@ struct HTTP_REPLY_HEADER {
int content_length;
};
#define HTTP_OP_NONE 0
// For the first 4, data source/sink are files
#define HTTP_OP_GET 1
#define HTTP_OP_POST 2

View File

@ -28,9 +28,13 @@
LOG_FLAGS log_flags;
LOG_FLAGS::LOG_FLAGS() {
memset(this, 0, sizeof(LOG_FLAGS));
task = file_xfer = sched_ops = state_debug = false;
task_debug = file_xfer_debug = sched_op_debug = false;
http_debug = time_debug = net_xfer_debug = false;
}
// Parse log flag preferences
//
int LOG_FLAGS::parse(FILE* in) {
char buf[256];
if(in==NULL) {

View File

@ -30,6 +30,9 @@
#include "prefs.h"
#include "util.h"
// Display a message to the user. Depending on the priority, the
// message may be more or less obtrusive
//
void show_message(char* message, char* priority) {
if(message==NULL) {
fprintf(stderr, "error: show_message: unexpected NULL pointer message\n");
@ -46,6 +49,7 @@ void show_message(char* message, char* priority) {
// Prompt user for project URL and authenticator,
// and create a prototype prefs file
// TODO: use better input method here, backspace doesn't always seem to work
//
int initialize_prefs() {
char master_url[256];
@ -73,14 +77,19 @@ int main(int argc, char** argv) {
FILE* f;
int retval;
// Set the stdout buffer to 0, such that stdout output
// immediately gets written out
setbuf(stdout, 0);
// Read any log flags preferences, used mainly for debugging
f = fopen(LOG_FLAGS_FILE, "r");
if (f) {
log_flags.parse(f);
fclose(f);
}
// Read the user preferences file, if it exists. If it doesn't,
// prompt user for project URL via initialize_prefs()
prefs = new PREFS;
retval = prefs->parse_file();
if (retval) {
@ -96,23 +105,34 @@ int main(int argc, char** argv) {
}
}
// Initialize the client state with the preferences
gstate.init(prefs);
// Parse command line arguments
gstate.parse_cmdline(argc, argv);
// Run the time tests and host information check if needed
// TODO: break time tests and host information check into two
// separate functions?
if(gstate.run_time_tests()) {
gstate.time_tests();
}
// Restart any tasks that were running when we last quit the client
gstate.restart_tasks();
while (1) {
// do_something is where the meat of the clients work is done
// it will return false if it had nothing to do, in which case
// client will go to sleep for a second
if (!gstate.do_something()) {
if (log_flags.time_debug) printf("SLEEP 1 SECOND\n");
fflush(stdout);
boinc_sleep(1);
}
// If it's time to exit, break out of the while loop
if (gstate.time_to_exit()) {
printf("time to exit\n");
break;
}
}
// Clean everything up and gracefully exit
gstate.exit_tasks();
return 0;
}

View File

@ -26,6 +26,7 @@
#include "error_numbers.h"
#include "net_stats.h"
// Is this a reasonable cutoff?
#define SMALL_FILE_CUTOFF 32000
NET_STATS::NET_STATS() {
@ -35,6 +36,7 @@ NET_STATS::NET_STATS() {
bwdown = 0;
}
// Update network statistics
void NET_STATS::update(bool is_upload, double nbytes, double nsecs) {
double w1, w2, bw;
@ -66,6 +68,8 @@ void NET_STATS::update(bool is_upload, double nbytes, double nsecs) {
}
}
// Write XML based network statistics
//
int NET_STATS::write(FILE* out, bool to_server) {
if(out==NULL) {
fprintf(stderr, "error: NET_STATS.write: unexpected NULL pointer out\n");
@ -89,6 +93,8 @@ int NET_STATS::write(FILE* out, bool to_server) {
return 0;
}
// Read XML based network statistics
//
int NET_STATS::parse(FILE* in) {
char buf[256];
if(in==NULL) {

View File

@ -23,22 +23,38 @@
#ifdef _WIN32
#include "winsock.h"
#else
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <sys/types.h>
//#include <sys/ioctl.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include "error_numbers.h"
@ -54,7 +70,8 @@
#define socklen_t size_t
#endif
// Attempt to open a nonblocking socket to a server
//
int NET_XFER::open_server() {
sockaddr_in addr;
hostent* hep;
@ -108,18 +125,23 @@ int NET_XFER::open_server() {
void NET_XFER::init(char* host, int p, int b) {
strcpy(hostname, host);
port = p;
// net_xfer_state = ?
socket = -1;
is_connected = false;
want_download = false;
want_upload = false;
do_file_io = false;
io_done = false;
file = NULL;
io_ready = false;
error = 0;
strcpy(hostname, host);
port = p;
blocksize = b;
}
// Insert a NET_XFER object into the set
//
int NET_XFER_SET::insert(NET_XFER* nxp) {
int retval = nxp->open_server();
if (retval) return retval;
@ -127,6 +149,8 @@ int NET_XFER_SET::insert(NET_XFER* nxp) {
return 0;
}
// Remove a NET_XFER object from the set
//
int NET_XFER_SET::remove(NET_XFER* nxp) {
vector<NET_XFER*>::iterator iter;
@ -150,7 +174,7 @@ int NET_XFER_SET::remove(NET_XFER* nxp) {
// transfer data to/from a list of active streams
// transfer at most max_bytes bytes.
//
// TODO: implement other bandwidth constraints (ul/dl ratio, time of day)
int NET_XFER_SET::poll(int max_bytes, int& bytes_transferred) {
int n, retval;
@ -252,6 +276,8 @@ int NET_XFER_SET::do_select(int max_bytes, int& bytes_transferred) {
return 0;
}
// Return the NET_XFER object whose socket matches fd
//
NET_XFER* NET_XFER_SET::lookup_fd(int fd) {
for (unsigned int i=0; i<net_xfers.size(); i++) {
if (net_xfers[i]->socket == fd) {

View File

@ -42,6 +42,8 @@ PREFS::PREFS() {
disk_min_free_gb = 0;
};
// Parse XML based prefs, usually from prefs.xml
//
int PREFS::parse(FILE* in) {
char buf[256];
PROJECT* project;
@ -76,6 +78,8 @@ int PREFS::parse(FILE* in) {
return ERR_XML_PARSE;
}
// Parse prefs.xml for user preferences
//
int PREFS::parse_file() {
FILE* f;
int retval;
@ -87,6 +91,8 @@ int PREFS::parse_file() {
return retval;
}
// Write the default preference set for a project
// TODO: should mod_time really be 1?
int write_initial_prefs(char* master_url, char* authenticator) {
FILE* f = fopen(PREFS_FILE_NAME, "w");
if (!f) return ERR_FOPEN;

View File

@ -6,9 +6,10 @@
#include "speed_stats.h"
#include "error_numbers.h"
#define D_FLOP_ITERS 1
#define I_OP_ITERS 1
#define BANDWIDTH_ITERS 1
// # of iterations of each test to run for initial timing purposes
#define D_FLOP_ITERS 100
#define I_OP_ITERS 100
#define BANDWIDTH_ITERS 5
//#define RUN_TEST
@ -24,6 +25,29 @@ int main( void ) {
return 0;
}
void run_test_suite( double num_secs_per_test ) {
if(num_secs_per_test<0) {
fprintf(stderr, "error: run_test_suite: negative num_seconds_per_test\n");
}
printf(
"Running tests. This will take about %.1lf seconds.\n\n",
num_secs_per_test*3
);
printf(
"Speed: %.5lf million flops/sec\n\n",
run_double_prec_test(num_secs_per_test)/1000000
);
printf(
"Speed: %.5lf million integer ops/sec\n\n",
run_int_test(num_secs_per_test)/1000000
);
printf(
"Speed: %.5lf MB/sec\n\n",
12*sizeof(double)*run_mem_bandwidth_test(num_secs_per_test)/1000000
);
}
#endif
int check_cache_size( int mem_size ) {
@ -163,6 +187,8 @@ int check_cache_size( int mem_size ) {
return 0;
}
// Run the test of double precision math speed for about num_secs seconds
//
double run_double_prec_test( double num_secs ) {
int df_test_time, df_iters;
double df_secs;
@ -178,7 +204,7 @@ double run_double_prec_test( double num_secs ) {
// Calculate the # of iterations based on these tests
df_iters = (int)(D_FLOP_ITERS*num_secs/df_secs);
if( df_iters > D_FLOP_ITERS ) { // no need to redo test
if( df_iters > D_FLOP_ITERS ) { // no need to redo test if we already got enough
df_test_time = (int)double_flop_test( df_iters, 0 );
} else {
df_iters = D_FLOP_ITERS;
@ -189,6 +215,8 @@ double run_double_prec_test( double num_secs ) {
return 1000000*df_iters/df_secs;
}
// Run the test of integer math speed for about num_secs seconds
//
double run_int_test( double num_secs ) {
int int_test_time, int_iters;
double int_secs;
@ -215,6 +243,8 @@ double run_int_test( double num_secs ) {
return 1000000*int_iters/int_secs;
}
// Run the test of memory bandwidth speed for about num_secs seconds
//
double run_mem_bandwidth_test( double num_secs ) {
int bw_test_time;
double bw_secs;
@ -241,29 +271,6 @@ double run_mem_bandwidth_test( double num_secs ) {
return 1000000*bw_iters/bw_secs;
}
void run_test_suite( double num_secs_per_test ) {
if(num_secs_per_test<0) {
fprintf(stderr, "error: run_test_suite: negative num_seconds_per_test\n");
}
printf(
"Running tests. This will take about %.1lf seconds.\n\n",
num_secs_per_test*3
);
printf(
"Speed: %.5lf million flops/sec\n\n",
run_double_prec_test(num_secs_per_test)/1000000
);
printf(
"Speed: %.5lf million integer ops/sec\n\n",
run_int_test(num_secs_per_test)/1000000
);
printf(
"Speed: %.5lf MB/sec\n\n",
12*sizeof(double)*run_mem_bandwidth_test(num_secs_per_test)/1000000
);
}
// One iteration == D_LOOP_ITERS (1,000,000) floating point operations
// If time_total is negative, there was an error in the calculation,
// meaning there is probably something wrong with the CPU
@ -289,9 +296,10 @@ clock_t double_flop_test( int iterations, int print_debug ) {
for( j=0;j<D_LOOP_ITERS;j+=((NUM_DOUBLES-1)*5) ) {
temp = 1;
t1 = a[0];
// These tests do a pretty good job of breaking the processor pipeline,
// These tests do a pretty good job of preventing optimization
// since the result from all but one of the lines is required for the
// next line.
// next line. At the end of each iteration through the for loop,
// the array should be the same as when it started
for( k=0;k<NUM_DOUBLES-1;k++ ) {
t2 = a[k+1];
@ -306,11 +314,20 @@ clock_t double_flop_test( int iterations, int print_debug ) {
}
}
time_total = clock()-time_start;
// Stop the clock
time_total = clock();
// Accomodate for the possibility of clock wraparound
if( time_total > time_start ) {
time_total -= time_start;
} else {
time_total = 0; // this is just a kludge
}
calc_error = 0;
temp = 1;
// Check to make sure all the values are the same
// Check to make sure all the values are the same as when we started
for( i=0;i<NUM_DOUBLES;i++ ) {
if( (float)a[i] != (float)temp ) {
calc_error = 1;
@ -351,6 +368,10 @@ clock_t int_op_test( int iterations, int print_debug ) {
time_start = clock();
for( i=0;i<iterations;i++ ) {
// The contents of the array "a" should be the same at the
// beginning and end of each loop iteration. Most compilers will
// partially unroll the individual loops within this one, so
// those integer operations (incrementing k) are not counted
for( j=0;j<I_LOOP_ITERS/(NUM_INTS*9);j++ ) {
for( k=0;k<NUM_INTS;k++ ) {
a[k] *= 3; // 1 int ops
@ -380,11 +401,19 @@ clock_t int_op_test( int iterations, int print_debug ) {
}
}
time_total = clock()-time_start;
// Stop the clock
time_total = clock();
// Accomodate for the possibility of clock wraparound
if( time_total > time_start ) {
time_total -= time_start;
} else {
time_total = 0; // this is just a kludge
}
calc_error = 0;
temp = 1;
// Check to make sure all the values are the same
// Check to make sure all the values are the same as when we started
for( i=0;i<NUM_INTS;i++ ) {
if( a[i] != temp ) {
calc_error = 1;
@ -406,7 +435,7 @@ clock_t int_op_test( int iterations, int print_debug ) {
return time_total;
}
// One iteration == Read of 6M*sizeof(double), Write of 6M*sizeof(double)
// One iteration == Read of 6,000,000*sizeof(double), Write of 6,000,000*sizeof(double)
// If time_total is negative, there was an error in the copying,
// meaning there is probably something wrong with the CPU
@ -458,7 +487,7 @@ clock_t bandwidth_test( int iterations, int print_debug ) {
if( time_total > time_start ) {
time_total -= time_start;
} else {
time_total -= time_start;
time_total = 0; // this is just a kludge
}
copy_error = 0;

View File

@ -33,13 +33,15 @@
#define ALPHA (3600.*24*7*30)
TIME_STATS::TIME_STATS() {
first = true;
last_update = 0;
first = true;
on_frac = 1;
connected_frac = 1;
active_frac = 1;
}
// Update time statistics based on current activities
//
void TIME_STATS::update(bool is_connected, bool is_active) {
int now = time(0), dt;
double w1, w2;
@ -78,6 +80,8 @@ void TIME_STATS::update(bool is_connected, bool is_active) {
}
}
// Write XML based time statistics
//
int TIME_STATS::write(FILE* out, bool to_server) {
fprintf(out,
"<time_stats>\n"
@ -98,6 +102,8 @@ int TIME_STATS::write(FILE* out, bool to_server) {
return 0;
}
// Parse XML based time statistics, usually from client_state.xml
//
int TIME_STATS::parse(FILE* in) {
char buf[256];
if(in==NULL) {

View File

@ -53,6 +53,8 @@ double dtime() {
}
#ifdef _WIN32
// Goes to sleep for a specified number of seconds
// TODO: allow for fractional second sleep times?
void boinc_sleep( int seconds ) {
if(seconds<0) {
fprintf(stderr, "error: boinc_sleep: negative seconds\n");
@ -63,6 +65,8 @@ void boinc_sleep( int seconds ) {
#else
// Goes to sleep for a specified number of seconds
// TODO: allow for fractional second sleep times?
void boinc_sleep( int seconds ) {
if(seconds<0) {
fprintf(stderr,"error: boinc_sleep: negative seconds\n");