svn path=/trunk/boinc/; revision=12850

This commit is contained in:
David Anderson 2007-06-08 07:55:27 +00:00
parent 18c29a91ee
commit b4087e0e1b
15 changed files with 380 additions and 278 deletions

View File

@ -120,6 +120,7 @@ static int want_network = 0;
static int have_network = 1;
bool g_sleep = false;
// simulate unresponsive app by setting to true (debugging)
static FUNC_PTR timer_callback = 0;
#define TIMER_PERIOD 1
// period of worker-thread timer interrupts.
@ -176,14 +177,14 @@ static int setup_shared_mem() {
return 0;
}
// Return CPU time of worker thread.
// Return CPU time of worker thread (and optionally others)
// This may be called from other threads
//
static int boinc_worker_thread_cpu_time(double& cpu) {
double boinc_worker_thread_cpu_time() {
static double last_cpu=0;
static time_t last_time=0;
time_t now = time(0);
double time_diff = now-last_time;
double cpu, time_diff = now - last_time;
#ifdef _WIN32
int retval;
if (options.all_threads_cpu_time) {
@ -195,24 +196,23 @@ static int boinc_worker_thread_cpu_time(double& cpu) {
cpu = nrunning_ticks * TIMER_PERIOD; // for Win9x
}
#else
if (!pthread_mutex_lock(&getrusage_mutex)) {
cpu = (double)worker_thread_ru.ru_utime.tv_sec
+ (((double)worker_thread_ru.ru_utime.tv_usec)/1000000.0);
cpu += (double)worker_thread_ru.ru_stime.tv_sec
+ (((double)worker_thread_ru.ru_stime.tv_usec)/1000000.0);
pthread_mutex_unlock(&getrusage_mutex);
}
if (pthread_mutex_lock(&getrusage_mutex)) return last_cpu;
cpu = (double)worker_thread_ru.ru_utime.tv_sec
+ (((double)worker_thread_ru.ru_utime.tv_usec)/1000000.0);
cpu += (double)worker_thread_ru.ru_stime.tv_sec
+ (((double)worker_thread_ru.ru_stime.tv_usec)/1000000.0);
pthread_mutex_unlock(&getrusage_mutex);
#endif
double cpu_diff = cpu - last_cpu;
if (cpu_diff>(time_diff+1)) {
if (cpu_diff>(time_diff + 1)) {
// fprintf(stderr,"CPU time incrementing faster than real time. Correcting.\n");
cpu = last_cpu+time_diff;
cpu = last_cpu + time_diff;
}
if (time_diff != 0) {
last_cpu=cpu;
last_time=now;
if (time_diff) {
last_cpu = cpu;
last_time = now;
}
return 0;
return cpu;
}
// communicate to the core client (via shared mem)
@ -382,7 +382,7 @@ static void send_trickle_up_msg() {
int boinc_finish(int status) {
if (options.send_status_msgs) {
double total_cpu;
boinc_worker_thread_cpu_time(total_cpu);
total_cpu = boinc_worker_thread_cpu_time();
total_cpu += initial_wu_cpu_time;
// NOTE: the app_status slot may already contain a message.
@ -693,7 +693,10 @@ static void handle_process_control_msg() {
}
}
static void worker_timer(int /*a*/) {
// once-a-second timer.
// Runs in a separate thread (not the worker thread)
//
static void timer_handler() {
if (g_sleep) return;
interrupt_count++;
if (!ready_to_checkpoint) {
@ -740,7 +743,7 @@ static void worker_timer(int /*a*/) {
time_until_fraction_done_update -= TIMER_PERIOD;
if (time_until_fraction_done_update <= 0) {
double cur_cpu;
boinc_worker_thread_cpu_time(cur_cpu);
cur_cpu = boinc_worker_thread_cpu_time();
last_wu_cpu_time = cur_cpu + initial_wu_cpu_time;
update_app_progress(last_wu_cpu_time, last_checkpoint_cpu_time);
time_until_fraction_done_update = (int)aid.fraction_done_update_period;
@ -749,6 +752,9 @@ static void worker_timer(int /*a*/) {
if (options.handle_trickle_ups) {
send_trickle_up_msg();
}
if (timer_callback) {
timer_callback();
}
}
#ifdef _WIN32
@ -756,41 +762,17 @@ static void worker_timer(int /*a*/) {
static HANDLE timer_quit_event;
UINT WINAPI timer_thread(void *) {
DWORD dwEvent = NULL;
BOOL bContinue = TRUE;
diagnostics_set_thread_name("Timer");
while (1) {
Sleep(TIMER_PERIOD*1000);
timer_handler();
// Create the event that can be used to shutdown the timer thread.
//
timer_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!timer_quit_event) {
fprintf(stderr, "timer_thread(): CreateEvent() failed, GLE %d.\n", GetLastError());
}
while (bContinue) {
dwEvent = WaitForSingleObject(
timer_quit_event,
TIMER_PERIOD*1000
);
switch(dwEvent) {
case WAIT_OBJECT_0:
// timer_quit_event was signaled.
bContinue = FALSE;
break;
case WAIT_TIMEOUT:
// process any shared memory messages.
worker_timer(0);
// poor man's CPU time accounting for Win9x
//
if (!boinc_status.suspended) {
nrunning_ticks++;
}
break;
// poor man's CPU time accounting for Win9x
//
if (!boinc_status.suspended) {
nrunning_ticks++;
}
}
return 0;
}
@ -800,11 +782,15 @@ void* timer_thread(void*) {
block_sigalrm();
while(1) {
boinc_sleep(TIMER_PERIOD);
worker_timer(0);
timer_handler();
}
return 0;
}
// This SIGALRM handler gets handled only by the worker thread.
// It gets CPU time and implements sleeping.
// It must call only signal-safe functions, and must not do FP math
//
void worker_signal_handler(int) {
if (!pthread_mutex_trylock(&getrusage_mutex)) {
getrusage(RUSAGE_SELF, &worker_thread_ru);
@ -828,7 +814,7 @@ int set_worker_timer() {
#ifdef _WIN32
// as long as we're here, get the worker thread handle
// get the worker thread handle
//
DuplicateHandle(
GetCurrentProcess(),
@ -840,13 +826,12 @@ int set_worker_timer() {
DUPLICATE_SAME_ACCESS
);
// Initialize the worker thread info for diagnostic purposes.
//
diagnostics_set_thread_name("Worker");
diagnostics_set_thread_worker();
// Create the timer thread to deal with shared memory control messages.
// Create the timer thread
//
uintptr_t thread;
UINT uiThreadId;
@ -865,7 +850,7 @@ int set_worker_timer() {
return retval;
}
// lower our priority here
// lower our priority
//
SetThreadPriority(worker_thread_handle, THREAD_PRIORITY_IDLE);
@ -877,6 +862,8 @@ int set_worker_timer() {
return retval;
}
// set up a periodic SIGALRM, to be hanled by the worker thread
//
struct sigaction sa;
itimerval value;
sa.sa_handler = worker_signal_handler;
@ -924,7 +911,7 @@ int boinc_time_to_checkpoint() {
int boinc_checkpoint_completed() {
double cur_cpu;
boinc_worker_thread_cpu_time(cur_cpu);
cur_cpu = boinc_worker_thread_cpu_time();
last_wu_cpu_time = cur_cpu + aid.wu_cpu_time;
last_checkpoint_cpu_time = last_wu_cpu_time;
if (options.send_status_msgs) {
@ -1039,4 +1026,8 @@ void block_sigalrm() {
}
#endif
void boinc_register_timer_callback(FUNC_PTR p) {
timer_callback = p;
}
const char *BOINC_RCSID_0fa0410386 = "$Id$";

View File

@ -67,6 +67,8 @@ typedef struct BOINC_STATUS {
double max_working_set_size;
} BOINC_STATUS;
typedef void (*FUNC_PTR)();
struct APP_INIT_DATA;
extern int boinc_init(void);
@ -94,6 +96,8 @@ extern int boinc_receive_trickle_down(char* buf, int len);
extern int boinc_init_options(BOINC_OPTIONS*);
extern int boinc_get_status(BOINC_STATUS*);
extern double boinc_get_fraction_done();
extern void boinc_register_timer_callback(FUNC_PTR);
extern double boinc_worker_thread_cpu_time();
#ifdef __APPLE__
extern int setMacPList(void);

View File

@ -1,29 +1,20 @@
#ifndef _GRAPHICS2_H_
#define _GRAPHICS2_H_
#ifdef __cplusplus
extern "C" {
#endif
// Functions that must be supplied by the app
//
extern void app_graphics_render(int xs, int ys, double time_of_day);
extern void app_graphics_init(void);
// called each time a window is opened;
// called in the graphics thread
extern void app_graphics_reread_prefs(void);
// called when get REREAD_PREFS message from core client.
// called in the graphics thread
extern void app_graphics_resize(int width, int height);
extern void boinc_app_mouse_button(int x, int y, int which, int is_down);
extern void boinc_app_mouse_move(int x, int y, int left, int middle, int right);
extern void boinc_app_key_press(int, int);
extern void boinc_app_key_release(int, int);
// C++ API follows here
#ifdef __cplusplus
} // end extern "C"
// Functions that the app can call
//
extern void boinc_graphics_loop(int, char**);
extern void* boinc_graphics_make_shmem(char*, int);
extern void* boinc_graphics_get_shmem(char*);
@ -35,7 +26,4 @@ extern double boinc_max_gfx_cpu_frac;
extern void get_window_title(char* buf, int len);
extern bool throttled_app_render(int, int, double);
#endif // C++ API
#endif

View File

@ -317,8 +317,13 @@ static VOID CALLBACK timer_handler(HWND, UINT, UINT, DWORD) {
}
}
void win_graphics_event_loop() {
void boinc_graphics_loop(int argc, char** argv) {
MSG msg;
for (int i=1; i<argc; i++) {
if (!strcmp(argv[i], "--fullscreen")) {
fullscreen = true;
}
}
reg_win_class();
gfx_timer_id = SetTimer(NULL, 1, 30, (TIMERPROC)&timer_handler);
@ -335,15 +340,6 @@ void win_graphics_event_loop() {
unreg_win_class();
}
void boinc_graphics_loop(int argc, char** argv) {
for (int i=1; i<argc; i++) {
if (!strcmp(argv[i], "--fullscreen")) {
fullscreen = true;
}
}
win_graphics_event_loop();
}
extern int main(int, char**);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) {

View File

@ -5129,12 +5129,12 @@ Rom 21 May 2007
BOINCTaskBar.cpp
David 21 May 2007
- API: don't include config.h in a few places
- API: don't include config.h in a few places
api/
graphics_impl.C
texture.C
tgalib.C
api/
graphics_impl.C
texture.C
tgalib.C
David 21 May 2007
- feeder: fixed SQL query again
@ -5147,14 +5147,14 @@ David 21 May 2007
feeder.C
start
Janus 22 May 2007
Janus 22 May 2007
- Fixed missing version trackers in BInteger, BList classes
- Added BString class for BEncoded strings for the Bittorrent code
html/bt/inc/
blist.php
binteger.php
bstring.php (new)
binteger.php
bstring.php (new)
Rom 22 May 2007
- fixes #85 - Both Grid based views and List based views are now
@ -5184,9 +5184,9 @@ David 22 May 2007
Makefile.am
David 22 May 2007
api/
graphics2.C
graphics2_win.C
api/
graphics2.C
graphics2_win.C
Charlie 22 May 2007
- Manager: Fix crash bug in wxPieCtrl.
@ -5235,7 +5235,7 @@ Rom 23 May 2007
configure.ac
version.h
Janus 23 May 2007
Janus 23 May 2007
- Added "IllegalArgumentException" class for use in the remainin BT code
- Also added the class which will be used to represent the contents of
a .torrent descriptor.
@ -5247,7 +5247,7 @@ Janus 23 May 2007
html/bt/inc/
torrent.php (new)
illegalargumentexception.php (new)
illegalargumentexception.php (new)
David 23 May 2007
- client: unscrambled some of the #ifdefs in hostinfo_unix.C
@ -5277,15 +5277,15 @@ Jeff 23 May 2007
file_upload_handler.C
David 23 May 2007
- debug version 6-style graphics on Windows.
New example app works now!
- debug version 6-style graphics on Windows.
New example app works now!
api/
graphics2.C,h
graphics2_util.C
graphics2_win.C
lib/
util.C,h
api/
graphics2.C,h
graphics2_util.C
graphics2_win.C
lib/
util.C,h
David 23 May 2007
- debug version-6-style graphics on Unix
@ -5329,15 +5329,15 @@ David 24 May 2007
server_types.C
David 24 May 2007
- client, Windows: when making calls to get free disk space
(e.g. pGetDiskFreeSpaceEx())
pass the path of the current directory instead of NULL.
Otherwise, if we're running as an unprivileted user
with no access to the root dir,
the call fails and reports zero free space.
- client, Windows: when making calls to get free disk space
(e.g. pGetDiskFreeSpaceEx())
pass the path of the current directory instead of NULL.
Otherwise, if we're running as an unprivileted user
with no access to the root dir,
the call fails and reports zero free space.
lib/
filesys.C
lib/
filesys.C
David 24 May 2007
- renamed texfont.c to texfont.C to fix automake warning
@ -5684,11 +5684,11 @@ David 1 June 2007
procinfo.h
David 1 June 2007
- client: a few more network_status_debug messages
- client: a few more network_status_debug messages
client/
client_state.C
net_stats.C
client/
client_state.C
net_stats.C
David 3 June 2007
- client: allow suspension of non-CPU-intensive project or app
@ -5713,7 +5713,7 @@ David 3 June 2007
but I fixed it by doing integer benchmarks only on CPU zero.
This is OK since cores have separate integer units
(but not necessarily FP units)
Also shortened benchmark from 60 sec to 30 sec.
Also shortened benchmark from 60 sec to 30 sec.
client/
cs_benchmark.C
@ -5838,7 +5838,7 @@ Rom 6 June 2007
boinccas.dll
boinccas95.dll
Janus 6 June 2007
Janus 6 June 2007
- Fixed a small display error on the pending credit page (the
workunitid-column was showing the resultid for the result.
@ -5903,3 +5903,46 @@ David 8 June 2007
boinc_api.C
lib/
diagnostics.h
David 8 June 2007
- API: added boinc_register_timer_callback() for V6 graphics.
This lets the app do things
(e.g. updated shared memory for graphics) every second.
- API: change signature of boinc_worker_thread_cpu()
- API: rename worker_timer() to timer_handler()
- API (win): got rid of timer_quit_event (not used)
- API (version 6 graphics): removed extern C stuff
- client: improved the handling of unrecognized XML
Old: suppose we have
<name>foobar</name>
<unrec>
<name>blah</name>
</unrec>
where "<unrec>" is unrecognized.
We'd skip the <unrec>, but parse the <name> within it.
This wrong.
New: skip the entire unrecognized element
NOTE: I implemented this in the new parser (XML_PARSER)
and added it for everything that uses XML_PARSER.
The old parser still isn't quite right:
it will skip until the next </unrec>,
but not necessarily the matching instance of that tag.
- client: added error messages for unparsed XML in several places
- client/lib: use "else-less" syntax in XML parsing code
api/
boinc_api.C,h
graphics2.h
greaphic2_win.C
client/
acct_mgr.C
cs_statefile
gui_rpc_server_ops.C
log_flags.C
net_stats.C
lib/
app_ipc.C
gui_rpc_client_ops.C
parse.C,h
prefs.C

View File

@ -228,13 +228,22 @@ int AM_ACCOUNT::parse(XML_PARSER& xp) {
if (xp.parse_bool(tag, "update", update)) continue;
if (xp.parse_bool(tag, "dont_request_more_work", btemp)) {
dont_request_more_work.set(btemp);
continue;
}
if (xp.parse_bool(tag, "detach_when_done", btemp)) {
detach_when_done.set(btemp);
continue;
}
if (xp.parse_double(tag, "resource_share", dtemp)) {
resource_share.set(dtemp);
continue;
}
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] AM_ACCOUNT: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -306,6 +315,12 @@ int ACCT_MGR_OP::parse(FILE* f) {
continue;
}
if (xp.parse_str(tag, "host_venue", host_venue, sizeof(host_venue))) continue;
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] ACCT_MGR_OP::parse: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -586,6 +601,12 @@ int ACCT_MGR_INFO::parse_login_file(FILE* p) {
retval = xp.element_contents("</opaque>", opaque, sizeof(opaque));
continue;
}
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] ACCT_MGR_INFO::parse_login: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
return 0;
}
@ -618,6 +639,12 @@ int ACCT_MGR_INFO::init() {
retval = xp.element_contents("</signing_key>", signing_key, sizeof(signing_key));
continue;
}
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] ACCT_MGR_INFO::init: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
fclose(p);

View File

@ -317,7 +317,7 @@ int CLIENT_STATE::parse_state_file() {
msg_printf(NULL, MSG_INTERNAL_ERROR,
"Project files outside project in state file"
);
skip_unrecognized(buf, f);
skip_unrecognized(buf, mf);
continue;
}
project->parse_project_files(mf, false);
@ -383,7 +383,7 @@ int CLIENT_STATE::parse_state_file() {
msg_printf(NULL, MSG_INTERNAL_ERROR,
"auto update outside project in state file"
);
skip_unrecognized(buf, f);
skip_unrecognized(buf, mf);
continue;
}
if (!auto_update.parse(mf) && !auto_update.validate_and_link(project)) {
@ -395,6 +395,7 @@ int CLIENT_STATE::parse_state_file() {
"[unparsed_xml] state_file: unrecognized: %s", buf
);
}
skip_unrecognized(buf, mf);
}
}
fclose(f);

View File

@ -890,6 +890,12 @@ static int set_debt(XML_PARSER& xp) {
got_ltd = true;
continue;
}
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] set_debt: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
return 0;
}
@ -916,6 +922,12 @@ static void handle_set_debts(char* buf, MIOFILE& fout) {
return;
}
}
if (log_flags.unparsed_xml) {
msg_printf(NULL, MSG_INFO,
"[unparsed_xml] handle_set_debts: unrecognized %s", tag
);
}
xp.skip_unexpected(tag);
}
}

View File

@ -95,37 +95,36 @@ int LOG_FLAGS::parse(XML_PARSER& xp) {
continue;
}
if (!strcmp(tag, "/log_flags")) return 0;
else if (xp.parse_bool(tag, "task", task)) continue;
else if (xp.parse_bool(tag, "file_xfer", file_xfer)) continue;
else if (xp.parse_bool(tag, "sched_ops", sched_ops)) continue;
else if (xp.parse_bool(tag, "cpu_sched", cpu_sched)) continue;
else if (xp.parse_bool(tag, "cpu_sched_debug", cpu_sched_debug)) continue;
else if (xp.parse_bool(tag, "rr_simulation", rr_simulation)) continue;
else if (xp.parse_bool(tag, "debt_debug", debt_debug)) continue;
else if (xp.parse_bool(tag, "task_debug", task_debug)) continue;
else if (xp.parse_bool(tag, "work_fetch_debug", work_fetch_debug)) continue;
else if (xp.parse_bool(tag, "unparsed_xml", unparsed_xml)) continue;
else if (xp.parse_bool(tag, "state_debug", state_debug)) continue;
else if (xp.parse_bool(tag, "file_xfer_debug", file_xfer_debug)) continue;
else if (xp.parse_bool(tag, "sched_op_debug", sched_op_debug)) continue;
else if (xp.parse_bool(tag, "http_debug", http_debug)) continue;
else if (xp.parse_bool(tag, "proxy_debug", proxy_debug)) continue;
else if (xp.parse_bool(tag, "time_debug", time_debug)) continue;
else if (xp.parse_bool(tag, "http_xfer_debug", http_xfer_debug)) continue;
else if (xp.parse_bool(tag, "benchmark_debug", benchmark_debug)) continue;
else if (xp.parse_bool(tag, "poll_debug", poll_debug)) continue;
else if (xp.parse_bool(tag, "guirpc_debug", guirpc_debug)) continue;
else if (xp.parse_bool(tag, "scrsave_debug", scrsave_debug)) continue;
else if (xp.parse_bool(tag, "app_msg_send", app_msg_send)) continue;
else if (xp.parse_bool(tag, "app_msg_receive", app_msg_receive)) continue;
else if (xp.parse_bool(tag, "mem_usage_debug", mem_usage_debug)) continue;
else if (xp.parse_bool(tag, "network_status_debug", network_status_debug)) continue;
else if (xp.parse_bool(tag, "checkpoint_debug", checkpoint_debug)) continue;
else {
msg_printf(NULL, MSG_USER_ERROR, "Unrecognized tag in %s: <%s>\n",
CONFIG_FILE, tag
);
}
if (xp.parse_bool(tag, "task", task)) continue;
if (xp.parse_bool(tag, "file_xfer", file_xfer)) continue;
if (xp.parse_bool(tag, "sched_ops", sched_ops)) continue;
if (xp.parse_bool(tag, "cpu_sched", cpu_sched)) continue;
if (xp.parse_bool(tag, "cpu_sched_debug", cpu_sched_debug)) continue;
if (xp.parse_bool(tag, "rr_simulation", rr_simulation)) continue;
if (xp.parse_bool(tag, "debt_debug", debt_debug)) continue;
if (xp.parse_bool(tag, "task_debug", task_debug)) continue;
if (xp.parse_bool(tag, "work_fetch_debug", work_fetch_debug)) continue;
if (xp.parse_bool(tag, "unparsed_xml", unparsed_xml)) continue;
if (xp.parse_bool(tag, "state_debug", state_debug)) continue;
if (xp.parse_bool(tag, "file_xfer_debug", file_xfer_debug)) continue;
if (xp.parse_bool(tag, "sched_op_debug", sched_op_debug)) continue;
if (xp.parse_bool(tag, "http_debug", http_debug)) continue;
if (xp.parse_bool(tag, "proxy_debug", proxy_debug)) continue;
if (xp.parse_bool(tag, "time_debug", time_debug)) continue;
if (xp.parse_bool(tag, "http_xfer_debug", http_xfer_debug)) continue;
if (xp.parse_bool(tag, "benchmark_debug", benchmark_debug)) continue;
if (xp.parse_bool(tag, "poll_debug", poll_debug)) continue;
if (xp.parse_bool(tag, "guirpc_debug", guirpc_debug)) continue;
if (xp.parse_bool(tag, "scrsave_debug", scrsave_debug)) continue;
if (xp.parse_bool(tag, "app_msg_send", app_msg_send)) continue;
if (xp.parse_bool(tag, "app_msg_receive", app_msg_receive)) continue;
if (xp.parse_bool(tag, "mem_usage_debug", mem_usage_debug)) continue;
if (xp.parse_bool(tag, "network_status_debug", network_status_debug)) continue;
if (xp.parse_bool(tag, "checkpoint_debug", checkpoint_debug)) continue;
msg_printf(NULL, MSG_USER_ERROR, "Unrecognized tag in %s: <%s>\n",
CONFIG_FILE, tag
);
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -207,21 +206,20 @@ int CONFIG::parse_options(XML_PARSER& xp) {
if (!strcmp(tag, "/options")) {
return 0;
}
else if (xp.parse_int(tag, "save_stats_days", save_stats_days)) continue;
else if (xp.parse_bool(tag, "dont_check_file_sizes", dont_check_file_sizes)) continue;
else if (xp.parse_bool(tag, "http_1_0", http_1_0)) continue;
else if (xp.parse_int(tag, "ncpus", ncpus)) continue;
else if (xp.parse_int(tag, "max_file_xfers", max_file_xfers)) continue;
else if (xp.parse_int(tag, "max_file_xfers_per_project", max_file_xfers_per_project)) continue;
else if (xp.parse_bool(tag, "suppress_net_info", suppress_net_info)) continue;
else if (xp.parse_bool(tag, "disallow_attach", disallow_attach)) continue;
else if (xp.parse_bool(tag, "os_random_only", os_random_only)) continue;
else if (xp.parse_bool(tag, "no_alt_platform", no_alt_platform)) continue;
else {
msg_printf(NULL, MSG_USER_ERROR, "Unparsed tag in %s: <%s>\n",
CONFIG_FILE, tag
);
}
if (xp.parse_int(tag, "save_stats_days", save_stats_days)) continue;
if (xp.parse_bool(tag, "dont_check_file_sizes", dont_check_file_sizes)) continue;
if (xp.parse_bool(tag, "http_1_0", http_1_0)) continue;
if (xp.parse_int(tag, "ncpus", ncpus)) continue;
if (xp.parse_int(tag, "max_file_xfers", max_file_xfers)) continue;
if (xp.parse_int(tag, "max_file_xfers_per_project", max_file_xfers_per_project)) continue;
if (xp.parse_bool(tag, "suppress_net_info", suppress_net_info)) continue;
if (xp.parse_bool(tag, "disallow_attach", disallow_attach)) continue;
if (xp.parse_bool(tag, "os_random_only", os_random_only)) continue;
if (xp.parse_bool(tag, "no_alt_platform", no_alt_platform)) continue;
msg_printf(NULL, MSG_USER_ERROR, "Unparsed tag in %s: <%s>\n",
CONFIG_FILE, tag
);
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -254,6 +252,7 @@ int CONFIG::parse(FILE* f) {
msg_printf(NULL, MSG_USER_ERROR, "Unparsed tag in %s: <%s>\n",
CONFIG_FILE, tag
);
xp.skip_unexpected(tag);
}
}
msg_printf(NULL, MSG_USER_ERROR, "Missing end tag in %s", CONFIG_FILE);

View File

@ -172,16 +172,13 @@ int NET_STATUS::network_status() {
if (gstate.lookup_website_op.error_num == ERR_IN_PROGRESS) {
retval = NETWORK_STATUS_LOOKUP_PENDING;
} else if (gstate.now - last_comm_time < 10) {
//msg_printf(0, MSG_INFO, "nops %d; return 0", http_ops->nops());
retval = NETWORK_STATUS_ONLINE;
} else if (need_physical_connection) {
//msg_printf(0, MSG_INFO, "need phys conn; return 1");
retval = NETWORK_STATUS_WANT_CONNECTION;
} else if (gstate.active_tasks.want_network()) {
retval = NETWORK_STATUS_WANT_CONNECTION;
} else {
have_sporadic_connection = false;
//msg_printf(0, MSG_INFO, "returning 2");
retval = NETWORK_STATUS_WANT_DISCONNECT;
}
if (log_flags.network_status_debug) {

View File

@ -202,47 +202,49 @@ int parse_init_data_file(FILE* f, APP_INIT_DATA& ai) {
if (retval) return retval;
continue;
}
else if (!strcmp(tag, "host_info")) {
if (!strcmp(tag, "host_info")) {
ai.host_info.parse(mf);
continue;
}
else if (!strcmp(tag, "proxy_info")) {
if (!strcmp(tag, "proxy_info")) {
ai.proxy_info.parse(mf);
continue;
}
else if (xp.parse_int(tag, "major_version", ai.major_version)) continue;
else if (xp.parse_int(tag, "minor_version", ai.minor_version)) continue;
else if (xp.parse_int(tag, "release", ai.release)) continue;
else if (xp.parse_int(tag, "app_version", ai.app_version)) continue;
else if (xp.parse_str(tag, "app_name", ai.app_name, sizeof(ai.app_name))) continue;
else if (xp.parse_str(tag, "symstore", ai.symstore, sizeof(ai.symstore))) continue;
else if (xp.parse_str(tag, "acct_mgr_url", ai.acct_mgr_url, sizeof(ai.acct_mgr_url))) continue;
else if (xp.parse_str(tag, "user_name", ai.user_name, sizeof(ai.user_name))) continue;
else if (xp.parse_str(tag, "team_name", ai.team_name, sizeof(ai.team_name))) continue;
else if (xp.parse_str(tag, "project_dir", ai.project_dir, sizeof(ai.project_dir))) continue;
else if (xp.parse_str(tag, "boinc_dir", ai.boinc_dir, sizeof(ai.boinc_dir))) continue;
else if (xp.parse_str(tag, "authenticator", ai.authenticator, sizeof(ai.authenticator))) continue;
else if (xp.parse_str(tag, "wu_name", ai.wu_name, sizeof(ai.wu_name))) continue;
if (xp.parse_int(tag, "major_version", ai.major_version)) continue;
if (xp.parse_int(tag, "minor_version", ai.minor_version)) continue;
if (xp.parse_int(tag, "release", ai.release)) continue;
if (xp.parse_int(tag, "app_version", ai.app_version)) continue;
if (xp.parse_str(tag, "app_name", ai.app_name, sizeof(ai.app_name))) continue;
if (xp.parse_str(tag, "symstore", ai.symstore, sizeof(ai.symstore))) continue;
if (xp.parse_str(tag, "acct_mgr_url", ai.acct_mgr_url, sizeof(ai.acct_mgr_url))) continue;
if (xp.parse_str(tag, "user_name", ai.user_name, sizeof(ai.user_name))) continue;
if (xp.parse_str(tag, "team_name", ai.team_name, sizeof(ai.team_name))) continue;
if (xp.parse_str(tag, "project_dir", ai.project_dir, sizeof(ai.project_dir))) continue;
if (xp.parse_str(tag, "boinc_dir", ai.boinc_dir, sizeof(ai.boinc_dir))) continue;
if (xp.parse_str(tag, "authenticator", ai.authenticator, sizeof(ai.authenticator))) continue;
if (xp.parse_str(tag, "wu_name", ai.wu_name, sizeof(ai.wu_name))) continue;
#ifdef _WIN32
else if (xp.parse_str(tag, "comm_obj_name", ai.shmem_seg_name, sizeof(ai.shmem_seg_name))) continue;
if (xp.parse_str(tag, "comm_obj_name", ai.shmem_seg_name, sizeof(ai.shmem_seg_name))) continue;
#else
else if (xp.parse_int(tag, "shm_key", ai.shmem_seg_name)) continue;
if (xp.parse_int(tag, "shm_key", ai.shmem_seg_name)) continue;
#endif
else if (xp.parse_int(tag, "slot", ai.slot)) continue;
else if (xp.parse_double(tag, "user_total_credit", ai.user_total_credit)) continue;
else if (xp.parse_double(tag, "user_expavg_credit", ai.user_expavg_credit)) continue;
else if (xp.parse_double(tag, "host_total_credit", ai.host_total_credit)) continue;
else if (xp.parse_double(tag, "host_expavg_credit", ai.host_expavg_credit)) continue;
else if (xp.parse_double(tag, "resource_share_fraction", ai.resource_share_fraction)) continue;
else if (xp.parse_double(tag, "rsc_fpops_est", ai.rsc_fpops_est)) continue;
else if (xp.parse_double(tag, "rsc_fpops_bound", ai.rsc_fpops_bound)) continue;
else if (xp.parse_double(tag, "rsc_memory_bound", ai.rsc_memory_bound)) continue;
else if (xp.parse_double(tag, "rsc_disk_bound", ai.rsc_disk_bound)) continue;
else if (xp.parse_double(tag, "wu_cpu_time", ai.wu_cpu_time)) continue;
else if (xp.parse_double(tag, "checkpoint_period", ai.checkpoint_period)) continue;
else if (xp.parse_double(tag, "fraction_done_update_period", ai.fraction_done_update_period)) continue;
else if (xp.parse_double(tag, "fraction_done_start", ai.fraction_done_start)) continue;
else if (xp.parse_double(tag, "fraction_done_end", ai.fraction_done_end)) continue;
//else fprintf(stderr, "parse_init_data_file: unrecognized %s", tag);
if (xp.parse_int(tag, "slot", ai.slot)) continue;
if (xp.parse_double(tag, "user_total_credit", ai.user_total_credit)) continue;
if (xp.parse_double(tag, "user_expavg_credit", ai.user_expavg_credit)) continue;
if (xp.parse_double(tag, "host_total_credit", ai.host_total_credit)) continue;
if (xp.parse_double(tag, "host_expavg_credit", ai.host_expavg_credit)) continue;
if (xp.parse_double(tag, "resource_share_fraction", ai.resource_share_fraction)) continue;
if (xp.parse_double(tag, "rsc_fpops_est", ai.rsc_fpops_est)) continue;
if (xp.parse_double(tag, "rsc_fpops_bound", ai.rsc_fpops_bound)) continue;
if (xp.parse_double(tag, "rsc_memory_bound", ai.rsc_memory_bound)) continue;
if (xp.parse_double(tag, "rsc_disk_bound", ai.rsc_disk_bound)) continue;
if (xp.parse_double(tag, "wu_cpu_time", ai.wu_cpu_time)) continue;
if (xp.parse_double(tag, "checkpoint_period", ai.checkpoint_period)) continue;
if (xp.parse_double(tag, "fraction_done_update_period", ai.fraction_done_update_period)) continue;
if (xp.parse_double(tag, "fraction_done_start", ai.fraction_done_start)) continue;
if (xp.parse_double(tag, "fraction_done_end", ai.fraction_done_end)) continue;
// fprintf(stderr, "parse_init_data_file: unrecognized %s", tag);
xp.skip_unexpected(tag);
}
return 0;
}

View File

@ -107,27 +107,14 @@ int PROJECT_LIST_ENTRY::parse(XML_PARSER& xp) {
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!strcmp(tag, "/project")) return 0;
else if (xp.parse_string(tag, "name", name)) {
continue;
}
else if (xp.parse_string(tag, "url", url)) {
continue;
}
else if (xp.parse_string(tag, "general_area", general_area)) {
continue;
}
else if (xp.parse_string(tag, "specific_area", specific_area)) {
continue;
}
else if (xp.parse_string(tag, "description", description)) {
continue;
}
else if (xp.parse_string(tag, "home", home)) {
continue;
}
else if (xp.parse_string(tag, "image", image)) {
continue;
}
if (xp.parse_string(tag, "name", name)) continue;
if (xp.parse_string(tag, "url", url)) continue;
if (xp.parse_string(tag, "general_area", general_area)) continue;
if (xp.parse_string(tag, "specific_area", specific_area)) continue;
if (xp.parse_string(tag, "description", description)) continue;
if (xp.parse_string(tag, "home", home)) continue;
if (xp.parse_string(tag, "image", image)) continue;
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -1136,24 +1123,23 @@ int RPC_CLIENT::get_state(CC_STATE& state) {
// the following are to handle responses from pre-5.6 core clients
// remove them 6/07
else if (parse_int(buf, "<major_version>", state.version_info.major)) continue;
else if (parse_int(buf, "<minor_version>", state.version_info.minor)) continue;
else if (parse_int(buf, "<release>", state.version_info.release)) continue;
else if (match_tag(buf, "<project>")) {
if (parse_int(buf, "<major_version>", state.version_info.major)) continue;
if (parse_int(buf, "<minor_version>", state.version_info.minor)) continue;
if (parse_int(buf, "<release>", state.version_info.release)) continue;
if (match_tag(buf, "<project>")) {
project = new PROJECT();
project->parse(rpc.fin);
state.projects.push_back(project);
continue;
}
else if (match_tag(buf, "<app>")) {
if (match_tag(buf, "<app>")) {
APP* app = new APP();
app->parse(rpc.fin);
app->project = project;
state.apps.push_back(app);
continue;
}
else if (match_tag(buf, "<app_version>")) {
if (match_tag(buf, "<app_version>")) {
APP_VERSION* app_version = new APP_VERSION();
app_version->parse(rpc.fin);
app_version->project = project;
@ -1161,7 +1147,7 @@ int RPC_CLIENT::get_state(CC_STATE& state) {
state.app_versions.push_back(app_version);
continue;
}
else if (match_tag(buf, "<workunit>")) {
if (match_tag(buf, "<workunit>")) {
WORKUNIT* wu = new WORKUNIT();
wu->parse(rpc.fin);
wu->project = project;
@ -1170,7 +1156,7 @@ int RPC_CLIENT::get_state(CC_STATE& state) {
state.wus.push_back(wu);
continue;
}
else if (match_tag(buf, "<result>")) {
if (match_tag(buf, "<result>")) {
RESULT* result = new RESULT();
result->parse(rpc.fin);
result->project = project;
@ -1179,13 +1165,14 @@ int RPC_CLIENT::get_state(CC_STATE& state) {
state.results.push_back(result);
continue;
}
else if (match_tag(buf, "<global_preferences>")) {
if (match_tag(buf, "<global_preferences>")) {
bool flag = false;
GLOBAL_PREFS_MASK mask;
XML_PARSER xp(&rpc.fin);
state.global_prefs.parse(xp, "", flag, mask);
continue;
}
skip_unrecognized(buf, rpc.fin);
}
}
return retval;

View File

@ -391,7 +391,7 @@ void xml_unescape(const char* in, char* out) {
// If it's of the form <foo> then scan for </foo> and return 0.
// Otherwise return ERR_XML_PARSE
//
int skip_unrecognized(char* buf, FILE* in) {
int skip_unrecognized(char* buf, MIOFILE& fin) {
char* p, *q, buf2[256];
std::string close_tag;
@ -408,7 +408,7 @@ int skip_unrecognized(char* buf, FILE* in) {
}
*q = 0;
close_tag = string("</") + string(p+1) + string(">");
while (fgets(buf2, 256, in)) {
while (fin.fgets(buf2, 256)) {
if (strstr(buf2, close_tag.c_str())) {
return 0;
}
@ -697,6 +697,23 @@ int XML_PARSER::element_contents(const char* end_tag, char* buf, int buflen) {
return retval;
}
// We got an unexpected tag.
// If it's an end tag, do nothing.
// Otherwise skip until the end tag, if any
//
void XML_PARSER::skip_unexpected(const char* start_tag) {
char tag[256], end_tag[256];
bool eof, is_tag;
if (start_tag[0] == '/') return;
sprintf(end_tag, "/%s", start_tag);
while (!get(tag, sizeof(tag), is_tag)) {
if (!is_tag) continue;
if (!strcmp(tag, end_tag)) return;
skip_unexpected(tag);
}
}
// sample use is shown below
#if 0
@ -732,7 +749,7 @@ void parse(FILE* f) {
printf("got bool: %d\n", flag);
} else {
printf("unparsed tag: %s\n", tag);
return;
xp.skip_unexpected(tag);
}
}
printf("unexpected EOF\n");
@ -742,5 +759,21 @@ int main() {
FILE* f = fopen("foo.xml", "r");
parse(f);
}
... and run it against, e.g.:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<blah>
<x>
asdlfkj
<x> fj</x>
</x>
<str>blah</str>
<int> 6
</int>
<double>6.555</double>
<bool>0</bool>
</blah>
#endif
const char *BOINC_RCSID_3f3de9eb18 = "$Id$";

View File

@ -50,6 +50,7 @@ public:
bool parse_double(char*, const char*, double&);
bool parse_bool(char*, const char*, bool&);
int element_contents(const char*, char*, int);
void skip_unexpected(const char*);
};
/////////////// START DEPRECATED XML PARSER
@ -117,6 +118,6 @@ extern char* sgets(char* buf, int len, char* &in);
extern void xml_escape(const char*, char*);
extern void xml_unescape(const char*, char*);
extern void extract_venue(const char*, const char*, char*);
extern int skip_unrecognized(char* buf, FILE*);
extern int skip_unrecognized(char* buf, MIOFILE&);
#endif

View File

@ -214,16 +214,13 @@ int DAY_PREFS::parse(XML_PARSER& xp) {
if (!strcmp(tag, "/day_prefs")) {
if (day_of_week < 0 || day_of_week > 6) return ERR_XML_PARSE;
return 0;
} else if (xp.parse_int(tag, "day_of_week", day_of_week)) {
} else if (xp.parse_double(tag, "start_hour", time_prefs.start_hour)) {
continue;
} else if (xp.parse_double(tag, "end_hour", time_prefs.end_hour)) {
continue;
} else if (xp.parse_double(tag, "net_start_hour", time_prefs.net_start_hour)) {
continue;
} else if (xp.parse_double(tag, "net_end_hour", time_prefs.net_end_hour)) {
continue;
}
if (xp.parse_int(tag, "day_of_week", day_of_week)) continue;
if (xp.parse_double(tag, "start_hour", time_prefs.start_hour)) continue;
if (xp.parse_double(tag, "end_hour", time_prefs.end_hour)) continue;
if (xp.parse_double(tag, "net_start_hour", time_prefs.net_start_hour)) continue;
if (xp.parse_double(tag, "net_end_hour", time_prefs.net_end_hour)) continue;
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}
@ -277,33 +274,37 @@ int GLOBAL_PREFS::parse_override(
continue;
}
}
if (xp.parse_str(tag, "source_project", source_project, sizeof(source_project))) {
if (xp.parse_str(tag, "source_project", source_project, sizeof(source_project))) continue;
if (xp.parse_str(tag, "source_scheduler", source_scheduler, sizeof(source_scheduler))) {
continue;
} else if (xp.parse_str(tag, "source_scheduler", source_scheduler, sizeof(source_scheduler))) {
continue;
} else if (xp.parse_int(tag, "mod_time", mod_time)) {
continue;
} else if (!strcmp(tag, "/global_preferences")) {
return 0;
} else if (xp.parse_bool(tag, "run_on_batteries", run_on_batteries)) {
}
if (xp.parse_int(tag, "mod_time", mod_time)) continue;
if (!strcmp(tag, "/global_preferences")) return 0;
if (xp.parse_bool(tag, "run_on_batteries", run_on_batteries)) {
mask.run_on_batteries = true;
continue;
} else if (xp.parse_bool(tag, "run_if_user_active", run_if_user_active)) {
}
if (xp.parse_bool(tag, "run_if_user_active", run_if_user_active)) {
mask.run_if_user_active = true;
continue;
} else if (xp.parse_double(tag, "start_hour", time_prefs.start_hour)) {
}
if (xp.parse_double(tag, "start_hour", time_prefs.start_hour)) {
mask.start_hour = true;
continue;
} else if (xp.parse_double(tag, "end_hour", time_prefs.end_hour)) {
}
if (xp.parse_double(tag, "end_hour", time_prefs.end_hour)) {
mask.end_hour = true;
continue;
} else if (xp.parse_double(tag, "net_start_hour", time_prefs.net_start_hour)) {
}
if (xp.parse_double(tag, "net_start_hour", time_prefs.net_start_hour)) {
mask.net_start_hour = true;
continue;
} else if (xp.parse_double(tag, "net_end_hour", time_prefs.net_end_hour)) {
}
if (xp.parse_double(tag, "net_end_hour", time_prefs.net_end_hour)) {
mask.net_end_hour = true;
continue;
} else if (!strcmp(tag, "day_prefs")) {
}
if (!strcmp(tag, "day_prefs")) {
DAY_PREFS dp;
retval = dp.parse(xp);
if (!retval) {
@ -311,82 +312,102 @@ int GLOBAL_PREFS::parse_override(
week_prefs.present = true;
week_prefs.days[dp.day_of_week] = dp;
}
} else if (xp.parse_bool(tag, "leave_apps_in_memory", leave_apps_in_memory)) {
}
if (xp.parse_bool(tag, "leave_apps_in_memory", leave_apps_in_memory)) {
mask.leave_apps_in_memory = true;
continue;
} else if (xp.parse_bool(tag, "confirm_before_connecting", confirm_before_connecting)) {
}
if (xp.parse_bool(tag, "confirm_before_connecting", confirm_before_connecting)) {
mask.confirm_before_connecting = true;
continue;
} else if (xp.parse_bool(tag, "hangup_if_dialed", hangup_if_dialed)) {
}
if (xp.parse_bool(tag, "hangup_if_dialed", hangup_if_dialed)) {
mask.hangup_if_dialed = true;
continue;
} else if (xp.parse_bool(tag, "dont_verify_images", dont_verify_images)) {
}
if (xp.parse_bool(tag, "dont_verify_images", dont_verify_images)) {
mask.dont_verify_images = true;
continue;
} else if (xp.parse_double(tag, "work_buf_min_days", work_buf_min_days)) {
}
if (xp.parse_double(tag, "work_buf_min_days", work_buf_min_days)) {
if (work_buf_min_days < 0.00001) work_buf_min_days = 0.00001;
mask.work_buf_min_days = true;
continue;
} else if (xp.parse_double(tag, "work_buf_additional_days", work_buf_additional_days)) {
}
if (xp.parse_double(tag, "work_buf_additional_days", work_buf_additional_days)) {
if (work_buf_additional_days < 0) work_buf_additional_days = 0;
mask.work_buf_additional_days = true;
continue;
} else if (xp.parse_int(tag, "max_cpus", max_cpus)) {
}
if (xp.parse_int(tag, "max_cpus", max_cpus)) {
if (max_cpus < 1) max_cpus = 1;
mask.max_cpus = true;
continue;
} else if (xp.parse_double(tag, "disk_interval", disk_interval)) {
}
if (xp.parse_double(tag, "disk_interval", disk_interval)) {
if (disk_interval<0) disk_interval = 0;
mask.disk_interval = true;
continue;
} else if (xp.parse_double(tag, "cpu_scheduling_period_minutes", cpu_scheduling_period_minutes)) {
}
if (xp.parse_double(tag, "cpu_scheduling_period_minutes", cpu_scheduling_period_minutes)) {
if (cpu_scheduling_period_minutes < 0.0001) cpu_scheduling_period_minutes = 60;
mask.cpu_scheduling_period_minutes = true;
continue;
} else if (xp.parse_double(tag, "disk_max_used_gb", disk_max_used_gb)) {
}
if (xp.parse_double(tag, "disk_max_used_gb", disk_max_used_gb)) {
mask.disk_max_used_gb = true;
continue;
} else if (xp.parse_double(tag, "disk_max_used_pct", disk_max_used_pct)) {
}
if (xp.parse_double(tag, "disk_max_used_pct", disk_max_used_pct)) {
mask.disk_max_used_pct = true;
continue;
} else if (xp.parse_double(tag, "disk_min_free_gb", disk_min_free_gb)) {
}
if (xp.parse_double(tag, "disk_min_free_gb", disk_min_free_gb)) {
mask.disk_min_free_gb = true;
continue;
} else if (xp.parse_double(tag, "vm_max_used_pct", dtemp)) {
}
if (xp.parse_double(tag, "vm_max_used_pct", dtemp)) {
vm_max_used_frac = dtemp/100;
mask.vm_max_used_frac = true;
continue;
} else if (xp.parse_double(tag, "ram_max_used_busy_pct", dtemp)) {
}
if (xp.parse_double(tag, "ram_max_used_busy_pct", dtemp)) {
if (!dtemp) dtemp = 100;
ram_max_used_busy_frac = dtemp/100;
mask.ram_max_used_busy_frac = true;
continue;
} else if (xp.parse_double(tag, "ram_max_used_idle_pct", dtemp)) {
}
if (xp.parse_double(tag, "ram_max_used_idle_pct", dtemp)) {
if (!dtemp) dtemp = 100;
ram_max_used_idle_frac = dtemp/100;
mask.ram_max_used_idle_frac = true;
continue;
} else if (xp.parse_double(tag, "idle_time_to_run", idle_time_to_run)) {
}
if (xp.parse_double(tag, "idle_time_to_run", idle_time_to_run)) {
mask.idle_time_to_run = true;
continue;
} else if (xp.parse_double(tag, "max_bytes_sec_up", max_bytes_sec_up)) {
}
if (xp.parse_double(tag, "max_bytes_sec_up", max_bytes_sec_up)) {
if (max_bytes_sec_up < 0) max_bytes_sec_up = 0;
mask.max_bytes_sec_up = true;
continue;
} else if (xp.parse_double(tag, "max_bytes_sec_down", max_bytes_sec_down)) {
}
if (xp.parse_double(tag, "max_bytes_sec_down", max_bytes_sec_down)) {
if (max_bytes_sec_down < 0) max_bytes_sec_down = 0;
mask.max_bytes_sec_down = true;
continue;
} else if (xp.parse_double(tag, "cpu_usage_limit", dtemp)) {
}
if (xp.parse_double(tag, "cpu_usage_limit", dtemp)) {
if (dtemp > 0 && dtemp <= 100) {
cpu_usage_limit = dtemp;
mask.cpu_usage_limit = true;
}
continue;
} else if (xp.parse_bool(tag, "host_specific", host_specific)) {
}
if (xp.parse_bool(tag, "host_specific", host_specific)) {
continue;
}
xp.skip_unexpected(tag);
}
return ERR_XML_PARSE;
}