mirror of https://github.com/BOINC/boinc.git
user-specified files in app versions
svn path=/trunk/boinc/; revision=1219
This commit is contained in:
parent
92e8b08d70
commit
9844f440f4
|
@ -1,3 +1,22 @@
|
|||
// 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 "graphics_data.h"
|
||||
|
||||
void GRAPHICS_BUFFER::clear() {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// Contributor(s):
|
||||
//
|
||||
|
||||
// The class GRAPHICS_DOUBLE_BUFFER provides a handy mechanism
|
||||
// The class GRAPHICS_DOUBLE_BUFFER provides a mechanism
|
||||
// for synchronizing the generation of graphics information
|
||||
// (done by the "science thread")
|
||||
// with the graphics rendering (done by the "GUI thread",
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
// 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>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -14,7 +33,7 @@
|
|||
#endif
|
||||
|
||||
#include "gutil.h"
|
||||
GLfloat mat_diffuse[] = {0.7, 0.5, 1.0, 0.4};
|
||||
//GLfloat mat_diffuse[] = {0.7, 0.5, 1.0, 0.4};
|
||||
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
|
||||
GLfloat mat_shininess[] = {40.0};
|
||||
|
||||
|
@ -36,7 +55,6 @@ void mode_texture() {
|
|||
glLoadIdentity();
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_LIGHT0);
|
||||
//glTranslatef( 0.0f, 0.0f, -4.0f );
|
||||
}
|
||||
|
||||
void mode_unshaded() {
|
||||
|
|
31
api/gutil.h
31
api/gutil.h
|
@ -1,3 +1,26 @@
|
|||
// 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):
|
||||
//
|
||||
|
||||
// various utility classes for OpenGL programming,
|
||||
// used in Astropulse and SETI@home
|
||||
// See also graphics_data.C,h
|
||||
|
||||
struct COLOR {
|
||||
GLfloat r;
|
||||
GLfloat g;
|
||||
|
@ -26,7 +49,8 @@ extern GLfloat text_width(char* text);
|
|||
extern void draw_text_panel(
|
||||
GLfloat* _pos, GLfloat* size, GLfloat margin, COLOR color,
|
||||
GLfloat char_height, GLfloat line_width, GLfloat line_spacing,
|
||||
char* text);
|
||||
char* text
|
||||
);
|
||||
|
||||
extern void mode_texture();
|
||||
extern void mode_shaded(GLfloat*);
|
||||
|
@ -59,7 +83,10 @@ public:
|
|||
void add_tick(float x, float yfrac);
|
||||
};
|
||||
|
||||
// read a portable pixmap file
|
||||
//
|
||||
extern int read_ppm(char* name, int& w, int& h, unsigned char** arrayp);
|
||||
|
||||
extern void init_texture(char* filename);
|
||||
extern void draw_texture(float* pos, float* size);
|
||||
extern void draw_texture(float* pos, float* size);
|
||||
|
||||
|
|
|
@ -4212,3 +4212,63 @@ Eric May 16, 2003
|
|||
net_xfer.C
|
||||
win/
|
||||
wingui_mainwindow.cpp
|
||||
|
||||
Erik May 19 2003
|
||||
- added support for user-selected files to be included
|
||||
as part of an app_version.
|
||||
If there is an element of the form
|
||||
<app_file>
|
||||
<url>X</url>
|
||||
<open_name>Y</open_name>
|
||||
</app_file>
|
||||
in a user's project preferences,
|
||||
then for every APP_VERSION that is sent to the user,
|
||||
elements of the form
|
||||
<file_info>
|
||||
<name>X'</name>
|
||||
<url>X</url>
|
||||
</file_info>
|
||||
... and in the <app_version> element
|
||||
<file_ref>
|
||||
<file_name>X'</file_name>
|
||||
<open_name>Y</open_name>
|
||||
</file_ref>
|
||||
are added to the app version's XML description,
|
||||
where X' is an escaped version of X.
|
||||
This can be used (for example) to allow applications to
|
||||
have user-specified images in their graphics
|
||||
- Handle it correctly if the "insert" part of a file transfer fails
|
||||
- The "main program" of an app version is the one labeled <main_program/>
|
||||
(not necessarily the first one)
|
||||
- Only files labeled <executable/> are required to be signed
|
||||
- added copyright notice to some files
|
||||
- added sgets() for parsing a string that is made up of multiple lines
|
||||
- write MD5 checksum elements only if checksum is present
|
||||
- created escape_url_readable
|
||||
|
||||
TODO: app_versions are currently treated as immutable by client.
|
||||
Need to change this.
|
||||
|
||||
todo
|
||||
api/
|
||||
graphics_data.C,h
|
||||
util.cpp,h
|
||||
client/
|
||||
app.C
|
||||
client_state.C
|
||||
client_types.C
|
||||
cs_files.C
|
||||
file_names.C
|
||||
pers_file_xfer.C,h
|
||||
doc/
|
||||
api.html
|
||||
boinc_dev.html
|
||||
client_app.html
|
||||
client_app_graphics.html
|
||||
graphics.html
|
||||
lib/
|
||||
parse.C,h
|
||||
util.C,h
|
||||
sched/
|
||||
handle_request.C
|
||||
server_types.C,h
|
||||
|
|
|
@ -211,9 +211,10 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
// 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;
|
||||
FILE_REF fref = app_version->app_files[i];
|
||||
fip = fref.file_info;
|
||||
get_pathname(fip, file_path);
|
||||
if (i == 0) {
|
||||
if (fref.main_program) {
|
||||
safe_strcpy(exec_name, fip->name);
|
||||
safe_strcpy(exec_path, file_path);
|
||||
}
|
||||
|
|
|
@ -976,9 +976,11 @@ int CLIENT_STATE::link_app_version(PROJECT* p, APP_VERSION* avp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// any file associated with an app version must be signed
|
||||
// any executable file associated with an app version must be signed
|
||||
//
|
||||
fip->signature_required = true;
|
||||
if (fip->executable) {
|
||||
fip->signature_required = true;
|
||||
}
|
||||
avp->app_files[i].file_info = fip;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -436,11 +436,16 @@ int FILE_INFO::write(FILE* out, bool to_server) {
|
|||
fprintf(out,
|
||||
"<file_info>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <md5_cksum>%s</md5_cksum>\n"
|
||||
" <nbytes>%f</nbytes>\n"
|
||||
" <max_nbytes>%f</max_nbytes>\n",
|
||||
name, md5_cksum, nbytes, max_nbytes
|
||||
name, nbytes, max_nbytes
|
||||
);
|
||||
if (strlen(md5_cksum)) {
|
||||
fprintf(out,
|
||||
" <md5_cksum>%s</md5_cksum>\n",
|
||||
md5_cksum
|
||||
);
|
||||
}
|
||||
if (!to_server) {
|
||||
if (generated_locally) fprintf(out, " <generated_locally/>\n");
|
||||
fprintf(out, " <status>%d</status>\n", status);
|
||||
|
|
|
@ -103,7 +103,7 @@ int verify_downloaded_file(char* pathname, FILE_INFO& file_info) {
|
|||
fprintf(stderr, "error: verify_file2: file not verified\n");
|
||||
return ERR_RSA_FAILED;
|
||||
}
|
||||
} else if (file_info.md5_cksum) {
|
||||
} else if (strlen(file_info.md5_cksum)) {
|
||||
retval = md5_file(pathname, cksum, file_info.nbytes);
|
||||
if (strcmp(cksum, file_info.md5_cksum) || retval) {
|
||||
fprintf(stderr, "error: verify_file2: MD5 check failed\n");
|
||||
|
|
|
@ -396,18 +396,13 @@ int CLIENT_STATE::handle_scheduler_reply(
|
|||
// deal with project preferences (should always be there)
|
||||
//
|
||||
if (sr.project_prefs_xml) {
|
||||
strcpy(project->project_specific_prefs, sr.project_prefs_xml);
|
||||
retval = project->write_account_file();
|
||||
if (retval) return retval;
|
||||
|
||||
#if 0
|
||||
char path[256];
|
||||
get_account_filename(project->master_url, path);
|
||||
f = fopen(path, "r");
|
||||
if (!f) return ERR_FOPEN;
|
||||
project->parse_account(f);
|
||||
fclose(f);
|
||||
#endif
|
||||
if (strcmp(
|
||||
project->project_specific_prefs, sr.project_prefs_xml
|
||||
)) {
|
||||
strcpy(project->project_specific_prefs, sr.project_prefs_xml);
|
||||
retval = project->write_account_file();
|
||||
if (retval) return retval;
|
||||
}
|
||||
}
|
||||
|
||||
// if the scheduler reply includes a code-signing key,
|
||||
|
|
|
@ -32,38 +32,8 @@
|
|||
#include "file_names.h"
|
||||
#include "util.h"
|
||||
|
||||
// Escape a URL for the project directory, cutting off the "http://",
|
||||
// converting '\' '/' and ' ' to '_',
|
||||
// and converting the non alphanumeric characters to %XY
|
||||
// where XY is their hexadecimal equivalent
|
||||
//
|
||||
void escape_project_url(char *in, char* out) {
|
||||
int x, y;
|
||||
char *temp;
|
||||
char buf[256];
|
||||
|
||||
temp = strstr(in,"://");
|
||||
if (temp) {
|
||||
in = temp + strlen("://");
|
||||
}
|
||||
for (x=0, y=0; in[x]; ++x) {
|
||||
if (isalnum(in[x]) || in[x]=='.' || in[x]=='-' || in[x]=='_') {
|
||||
out[y] = in[x];
|
||||
++y;
|
||||
} else if (in[x] == '/' || in[x] == '\\' || in[x] == ' ') {
|
||||
out[y] = '_';
|
||||
++y;
|
||||
} else {
|
||||
out[y] = '%';
|
||||
++y;
|
||||
out[y] = 0;
|
||||
sprintf(buf, "%d", (char)in[x]);
|
||||
c2x(buf);
|
||||
strcat(out, buf);
|
||||
y += 2;
|
||||
}
|
||||
}
|
||||
out[y] = 0;
|
||||
escape_url_readable(in, out);
|
||||
}
|
||||
|
||||
// Gets the pathname of a file
|
||||
|
|
|
@ -93,17 +93,21 @@ int PERS_FILE_XFER::start_xfer() {
|
|||
(is_upload ? "upload" : "download"), fip->get_url(), retval
|
||||
);
|
||||
show_message(fip->project, buf, MSG_ERROR);
|
||||
handle_xfer_failure();
|
||||
return retval;
|
||||
// TODO: do we need to do anything here?
|
||||
}
|
||||
retval = gstate.file_xfers->insert(file_xfer);
|
||||
fxp = file_xfer;
|
||||
if (retval) {
|
||||
if (log_flags.file_xfer) {
|
||||
show_message(fip->project, "file_xfer insert failed", MSG_ERROR);
|
||||
}
|
||||
sprintf(buf,
|
||||
"Couldn't start %s for %s: error %d",
|
||||
(is_upload ? "upload" : "download"), fip->get_url(), retval
|
||||
);
|
||||
show_message(fip->project, buf, MSG_ERROR);
|
||||
fxp->file_xfer_retval = retval;
|
||||
handle_xfer_failure(time(0));
|
||||
handle_xfer_failure();
|
||||
delete fxp;
|
||||
fxp = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
@ -209,7 +213,7 @@ bool PERS_FILE_XFER::poll(time_t now) {
|
|||
} else if (fxp->file_xfer_retval == ERR_UPLOAD_PERMANENT) {
|
||||
giveup();
|
||||
} else {
|
||||
handle_xfer_failure(now);
|
||||
handle_xfer_failure();
|
||||
}
|
||||
// remove fxp from file_xfer_set and deallocate it
|
||||
//
|
||||
|
@ -240,7 +244,8 @@ void PERS_FILE_XFER::giveup() {
|
|||
|
||||
// Handle a transfer failure
|
||||
//
|
||||
void PERS_FILE_XFER::handle_xfer_failure(time_t cur_time) {
|
||||
void PERS_FILE_XFER::handle_xfer_failure() {
|
||||
time_t now = time(0);
|
||||
|
||||
// If it was a bad range request, delete the file and start over
|
||||
//
|
||||
|
@ -248,11 +253,11 @@ void PERS_FILE_XFER::handle_xfer_failure(time_t cur_time) {
|
|||
fip->delete_file();
|
||||
}
|
||||
|
||||
retry_or_backoff(cur_time);
|
||||
retry_or_backoff();
|
||||
|
||||
// See if it's time to give up on the persistent file xfer
|
||||
//
|
||||
if ((cur_time - first_request_time) > gstate.file_xfer_giveup_period) {
|
||||
if ((now - first_request_time) > gstate.file_xfer_giveup_period) {
|
||||
giveup();
|
||||
}
|
||||
}
|
||||
|
@ -260,15 +265,15 @@ void PERS_FILE_XFER::handle_xfer_failure(time_t cur_time) {
|
|||
// Cycle to the next URL, or if we've hit all URLs in this cycle,
|
||||
// backoff and try again later
|
||||
//
|
||||
void PERS_FILE_XFER::retry_or_backoff(time_t cur_time) {
|
||||
void PERS_FILE_XFER::retry_or_backoff() {
|
||||
double exp_backoff;
|
||||
int backoff;
|
||||
struct tm *newtime;
|
||||
time_t aclock;
|
||||
time_t now;
|
||||
char buf[256];
|
||||
|
||||
time(&aclock);
|
||||
newtime = localtime(&aclock);
|
||||
now = time(0);
|
||||
newtime = localtime(&now);
|
||||
|
||||
// Cycle to the next URL to try
|
||||
//
|
||||
|
@ -286,7 +291,7 @@ void PERS_FILE_XFER::retry_or_backoff(time_t cur_time) {
|
|||
// PERS_RETRY_DELAY_MAX
|
||||
//
|
||||
backoff = (int)max(PERS_RETRY_DELAY_MIN, min(PERS_RETRY_DELAY_MAX, exp_backoff));
|
||||
next_request_time = cur_time + backoff;
|
||||
next_request_time = now + backoff;
|
||||
}
|
||||
if (log_flags.file_xfer_debug) {
|
||||
sprintf(buf,
|
||||
|
|
|
@ -59,8 +59,8 @@ public:
|
|||
PERS_FILE_XFER();
|
||||
int init(FILE_INFO*, bool is_file_upload);
|
||||
bool poll(time_t now);
|
||||
void handle_xfer_failure(time_t cur_time);
|
||||
void retry_or_backoff(time_t cur_time);
|
||||
void handle_xfer_failure();
|
||||
void retry_or_backoff();
|
||||
void giveup();
|
||||
int write(FILE* fout);
|
||||
int parse(FILE* fin);
|
||||
|
|
98
doc/api.html
98
doc/api.html
|
@ -157,101 +157,3 @@ must get the child's CPU time, then call
|
|||
void boinc_child_done(double total_cpu);
|
||||
</pre>
|
||||
before forking the next child process.
|
||||
|
||||
|
||||
<hr>
|
||||
<h3>Implementation</h3>
|
||||
<p>
|
||||
Application are executed in separate "catbox" directories,
|
||||
allowing them to create and use temporary files without name conflicts.
|
||||
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 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
|
||||
is done through XML files in the catbox directory.
|
||||
Several files are used.
|
||||
<p>
|
||||
<b>Files created by the core client, read by the app:</b>
|
||||
(Once, at start of app)
|
||||
<ul>
|
||||
<li> Symbolic link files
|
||||
<li> <b>fd_init.xml</b>:
|
||||
specifies the mappings of file descriptors (stdin/stdout/stderr)
|
||||
to physical files.
|
||||
|
||||
<li> <b>init_data.xml</b>: this contains the initialization data
|
||||
returned by <tt>boinc_init()</tt> (see above),
|
||||
as well as the minimum checkpoint period.
|
||||
</ul>
|
||||
<p>
|
||||
<b>Files created by the API implementation, read by the core client:</b>
|
||||
<ul>
|
||||
<li>
|
||||
<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.
|
||||
|
||||
</ul>
|
||||
<p>
|
||||
The API implementation uses a timer (60Hz);
|
||||
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 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.
|
||||
|
|
|
@ -27,7 +27,9 @@ Core client
|
|||
<li> <a href=client_data.html>Data structures</a>
|
||||
<li> <a href=client_logic.html>Main loop logic</a>
|
||||
<li> <a href=client_debug.html>Debugging</a>
|
||||
<li> <a href=host_measure.html>Host measurements</a>
|
||||
<li> <a href=host_measure.html>Host measurement and identification</a>
|
||||
<li> <a href=client_app.html>Core client/application interaction (basic)</a>
|
||||
<li> <a href=client_app_graphic.html>Core client/application interaction (graphics)</a>
|
||||
</ul>
|
||||
<font size=+1><b>
|
||||
Scheduling server
|
||||
|
|
|
@ -7,3 +7,99 @@ Explain startup files
|
|||
Explain shared memory mechanism in general
|
||||
<p>
|
||||
Explain work-related use of shmem
|
||||
|
||||
|
||||
<p>
|
||||
Application are executed in separate "catbox" directories,
|
||||
allowing them to create and use temporary files without name conflicts.
|
||||
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 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
|
||||
is done through XML files in the catbox directory.
|
||||
Several files are used.
|
||||
<p>
|
||||
<b>Files created by the core client, read by the app:</b>
|
||||
(Once, at start of app)
|
||||
<ul>
|
||||
<li> Symbolic link files
|
||||
<li> <b>fd_init.xml</b>:
|
||||
specifies the mappings of file descriptors (stdin/stdout/stderr)
|
||||
to physical files.
|
||||
|
||||
<li> <b>init_data.xml</b>: this contains the initialization data
|
||||
returned by <tt>boinc_init()</tt> (see above),
|
||||
as well as the minimum checkpoint period.
|
||||
</ul>
|
||||
<p>
|
||||
<b>Files created by the API implementation, read by the core client:</b>
|
||||
<ul>
|
||||
<li>
|
||||
<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.
|
||||
|
||||
</ul>
|
||||
<p>
|
||||
The API implementation uses a timer (60Hz);
|
||||
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 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.
|
||||
|
|
|
@ -3,7 +3,24 @@
|
|||
TO BE WRITTEN
|
||||
|
||||
<p>
|
||||
Explain graphics startup files
|
||||
The graphics API uses a file <b>graphics.xml</b>
|
||||
that is created and occasionally modified by the
|
||||
core client or screensaver.
|
||||
This file has the format
|
||||
<pre>
|
||||
<graphics_info>
|
||||
<do_graphics/>
|
||||
<xsize>500</xsize>
|
||||
<ysize>400</ysize>
|
||||
<full_screen/>
|
||||
</graphics_info>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The graphics API implementation uses a 60 Hz timer.
|
||||
Every 0.5 sec, it sees if graphics.xml has been modified, and if so parses it.
|
||||
Every 1/60 sec, it sees if it's time for a new frame,
|
||||
and if so calls <tt>app_render()</tt>.
|
||||
<p>
|
||||
Explain graphics modes of apps
|
||||
<p>
|
||||
|
|
|
@ -33,26 +33,3 @@ It can refer to the user name, CPU time etc. obtained from
|
|||
Applications that don't do graphics must also supply a
|
||||
dummy <tt>app_render</tt> to link with the API.
|
||||
<tt>boinc_draw_gl</tt> is called to draw graphics
|
||||
|
||||
<hr>
|
||||
<h3>Implementation</h3>
|
||||
|
||||
<p>
|
||||
The graphics API uses a file <b>graphics.xml</b>
|
||||
that is created and occasionally modified by the
|
||||
core client or screensaver.
|
||||
This file has the format
|
||||
<pre>
|
||||
<graphics_info>
|
||||
<do_graphics/>
|
||||
<xsize>500</xsize>
|
||||
<ysize>400</ysize>
|
||||
<full_screen/>
|
||||
</graphics_info>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The graphics API implementation uses a 60 Hz timer.
|
||||
Every 0.5 sec, it sees if graphics.xml has been modified, and if so parses it.
|
||||
Every 1/60 sec, it sees if it's time for a new frame,
|
||||
and if so calls <tt>app_render()</tt>.
|
||||
|
|
15
lib/parse.C
15
lib/parse.C
|
@ -204,3 +204,18 @@ void extract_venue(char* in, char* venue_name, char* out) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy a line from the given string.
|
||||
// kinda like fgets() when you're reading from a string
|
||||
//
|
||||
char* sgets(char* buf, int len, char*& in) {
|
||||
char* p;
|
||||
|
||||
p = strstr(in, "\n");
|
||||
if (!p) return NULL;
|
||||
*p = 0;
|
||||
safe_strncpy(buf, in, len);
|
||||
*p = '\n';
|
||||
in = p+1;
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -32,3 +32,4 @@ extern int copy_element_contents(FILE* in, char* end_tag, char* p, int len);
|
|||
extern int read_file_malloc(char* pathname, char*& str);
|
||||
extern void replace_element(char* buf, char* start, char* end, char* replacement);
|
||||
extern void extract_venue(char* in, char* venue_name, char* out);
|
||||
extern char* sgets(char* buf, int len, char* &in);
|
||||
|
|
34
lib/util.C
34
lib/util.C
|
@ -291,6 +291,40 @@ void escape_url(char *in, char*out) {
|
|||
out[y] = 0;
|
||||
}
|
||||
|
||||
// Escape a URL for the project directory, cutting off the "http://",
|
||||
// converting '\' '/' and ' ' to '_',
|
||||
// and converting the non alphanumeric characters to %XY
|
||||
// where XY is their hexadecimal equivalent
|
||||
//
|
||||
void escape_url_readable(char *in, char* out) {
|
||||
int x, y;
|
||||
char *temp;
|
||||
char buf[256];
|
||||
|
||||
temp = strstr(in,"://");
|
||||
if (temp) {
|
||||
in = temp + strlen("://");
|
||||
}
|
||||
for (x=0, y=0; in[x]; ++x) {
|
||||
if (isalnum(in[x]) || in[x]=='.' || in[x]=='-' || in[x]=='_') {
|
||||
out[y] = in[x];
|
||||
++y;
|
||||
} else if (in[x] == '/' || in[x] == '\\' || in[x] == ' ') {
|
||||
out[y] = '_';
|
||||
++y;
|
||||
} else {
|
||||
out[y] = '%';
|
||||
++y;
|
||||
out[y] = 0;
|
||||
sprintf(buf, "%d", (char)in[x]);
|
||||
c2x(buf);
|
||||
strcat(out, buf);
|
||||
y += 2;
|
||||
}
|
||||
}
|
||||
out[y] = 0;
|
||||
}
|
||||
|
||||
void safe_strncpy(char* dst, char* src, int len) {
|
||||
strncpy(dst, src, len);
|
||||
dst[len-1]=0;
|
||||
|
|
|
@ -29,6 +29,7 @@ extern void c2x(char *what);
|
|||
extern void strip_whitespace(char *str);
|
||||
extern void unescape_url(char *url);
|
||||
extern void escape_url(char *in, char*out);
|
||||
extern void escape_url_readable(char* in, char* out);
|
||||
extern void safe_strncpy(char*, char*, int);
|
||||
#define safe_strcpy(x, y) safe_strncpy(x, y, sizeof(x))
|
||||
#define safe_strcat(x, y) if (strlen(x)+strlen(y)<sizeof(x)) strcat(x, y)
|
||||
|
|
|
@ -120,6 +120,68 @@ int insert_wu_tags(WORKUNIT& wu, double seconds, APP& app) {
|
|||
return insert_after(wu.xml_doc, "<workunit>\n", buf);
|
||||
}
|
||||
|
||||
void parse_project_prefs(char* prefs, vector<APP_FILE>& app_files) {
|
||||
char buf[256];
|
||||
APP_FILE af;
|
||||
|
||||
while (sgets(buf, 256, prefs)) {
|
||||
if (match_tag(buf, "<app_file>")) {
|
||||
af.parse(prefs);
|
||||
app_files.push_back(af);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the user's project prefs include elements of the form
|
||||
// <app_file>
|
||||
// <url>X</url>
|
||||
// <open_name>Y</open_name>
|
||||
// </app_file>
|
||||
// then insert appropriate elements in app_version XML doc, namely:
|
||||
// <file_info>
|
||||
// <name>X'</name>
|
||||
// <url>X</url>
|
||||
// </file_info>
|
||||
// ... (in the <app_version> element)
|
||||
// <file_ref>
|
||||
// <file_name>X'</file_name>
|
||||
// <open_name>Y</open_name>
|
||||
// </file_ref>
|
||||
// where X' is the escaped version of X
|
||||
//
|
||||
int insert_app_file_tags(APP_VERSION& av, USER& user) {
|
||||
vector<APP_FILE> app_files;
|
||||
APP_FILE af;
|
||||
unsigned int i;
|
||||
char buf[256], namebuf[256];
|
||||
int retval;
|
||||
|
||||
parse_project_prefs(user.project_prefs, app_files);
|
||||
for (i=0; i<app_files.size(); i++) {
|
||||
af = app_files[i];
|
||||
escape_url_readable(af.url, namebuf);
|
||||
sprintf(buf,
|
||||
"<file_info>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <url>%s</url>\n"
|
||||
"</file_info>\n",
|
||||
namebuf, af.url
|
||||
);
|
||||
retval = insert_after(av.xml_doc, "", buf);
|
||||
if (retval) return retval;
|
||||
sprintf(buf,
|
||||
" <file_ref>\n"
|
||||
" <file_name>%s</file_name>\n"
|
||||
" <open_name>%s</open_name>\n"
|
||||
" </file_ref>\n",
|
||||
namebuf, af.open_name
|
||||
);
|
||||
retval = insert_after(av.xml_doc, "<app_version>\n", buf);
|
||||
if (retval) return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add the given workunit to a reply.
|
||||
// look up its app, and make sure there's a version for this platform.
|
||||
// Add the app and app_version to the reply also.
|
||||
|
@ -153,8 +215,18 @@ int add_wu_to_reply(
|
|||
|
||||
// add the app, app_version, and workunit to the reply,
|
||||
// but only if they aren't already there
|
||||
|
||||
//
|
||||
reply.insert_app_unique(*app);
|
||||
|
||||
// If the user's project prefs include any <app_file> tags,
|
||||
// make appropriate modifications to the app_version XML
|
||||
//
|
||||
retval = insert_app_file_tags(*app_version, reply.user);
|
||||
if (retval) {
|
||||
write_log("insert_app_file_tags failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
reply.insert_app_version_unique(*app_version);
|
||||
|
||||
// add time estimate to reply
|
||||
|
|
|
@ -192,6 +192,7 @@ int SCHEDULER_REPLY::write(FILE* fout) {
|
|||
for (i=0; i<apps.size(); i++) {
|
||||
apps[i].write(fout);
|
||||
}
|
||||
|
||||
for (i=0; i<app_versions.size(); i++) {
|
||||
for (j=0; j<apps.size(); j++) {
|
||||
if (apps[j].id == app_versions[i].appid) {
|
||||
|
@ -200,17 +201,21 @@ int SCHEDULER_REPLY::write(FILE* fout) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<wus.size(); i++) {
|
||||
fputs(wus[i].xml_doc, fout);
|
||||
}
|
||||
|
||||
for (i=0; i<results.size(); i++) {
|
||||
fputs(results[i].xml_doc_in, fout);
|
||||
}
|
||||
|
||||
if (strlen(code_sign_key)) {
|
||||
fputs("<code_sign_key>\n", fout);
|
||||
fputs(code_sign_key, fout);
|
||||
fputs("</code_sign_key>\n", fout);
|
||||
}
|
||||
|
||||
if (strlen(code_sign_key_signature)) {
|
||||
fputs("<code_sign_key_signature>\n", fout);
|
||||
fputs(code_sign_key_signature, fout);
|
||||
|
@ -360,3 +365,18 @@ int HOST::parse_net_stats(FILE* fin) {
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APP_FILE::parse(char*& in) {
|
||||
char buf[256], ebuf[256];
|
||||
|
||||
while (sgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</app_file>")) return 0;
|
||||
else if (parse_str(buf, "<url>", url, sizeof(url))) continue;
|
||||
else if (parse_str(buf, "<open_name>", open_name, sizeof(open_name))) continue;
|
||||
else {
|
||||
sprintf(ebuf, "APP_FILE::parse(): unrecognized %s\n", buf);
|
||||
write_log(ebuf);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -85,4 +85,12 @@ struct SCHEDULER_REPLY {
|
|||
void insert_result(RESULT&);
|
||||
};
|
||||
|
||||
// represents an <app_file> element in user's project prefs
|
||||
//
|
||||
struct APP_FILE {
|
||||
char url[256];
|
||||
char open_name[256];
|
||||
int parse(char*&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
1
todo
1
todo
|
@ -9,7 +9,6 @@ BUGS (arranged from high to low priority)
|
|||
- Win GUI: line between menus and tabs
|
||||
- "show graphics" should not use right-click
|
||||
- win GUI: reduce flicker?
|
||||
- on major version change, should discard any pending WUs
|
||||
- labels on disk graph are not clear
|
||||
- document and add to global prefs?
|
||||
start_saver
|
||||
|
|
Loading…
Reference in New Issue