diff --git a/checkin_notes b/checkin_notes index 59b0e4aa63..15d5cca838 100755 --- a/checkin_notes +++ b/checkin_notes @@ -11214,3 +11214,24 @@ David Mar 31 2004 boinc_api.C graphics_api.C windows_opengl.C + +David April 1 2004 + - Client: add a mechanism for suspending/resume network activity, + exactly parallel to the one existing mechanism for + suspending/resuming all (CPU+network) activity. + Initially this will be used to provide a GUI control. + Eventually we might have preference that control network + independently (time of day, only if idle, etc.) + - Client: save all messages in memory. + Implement GUI RPCs for getting ranges of messages. + + client/ + client_state.C,h + cs_prefs.C + gui_rpc_client.h + gui_rpc_server.C + main.C + message.C,h + lib/ + messages.C + util.C,h diff --git a/client/client_state.C b/client/client_state.C index 175fa6c95f..8103a354d9 100644 --- a/client/client_state.C +++ b/client/client_state.C @@ -73,6 +73,7 @@ CLIENT_STATE::CLIENT_STATE() { file_xfer_giveup_period = PERS_GIVEUP; contacted_sched_server = false; activities_suspended = false; + network_suspended = false; previous_activities_suspended = false; core_client_major_version = MAJOR_VERSION; core_client_minor_version = MINOR_VERSION; @@ -86,6 +87,7 @@ CLIENT_STATE::CLIENT_STATE() { strcpy(detach_project_url, ""); strcpy(host_venue, ""); user_run_request = USER_RUN_REQUEST_AUTO; + user_network_request = USER_RUN_REQUEST_AUTO; started_by_screensaver = false; requested_exit = false; master_fetch_period = MASTER_FETCH_PERIOD; @@ -298,7 +300,7 @@ int CLIENT_STATE::init() { int CLIENT_STATE::net_sleep(double x) { ScopeMessages scope_messages(log_messages, ClientMessages::DEBUG_NET_XFER); scope_messages.printf("CLIENT_STATE::net_sleep(%f)\n", x); - if (activities_suspended) { + if (activities_suspended || network_suspended) { boinc_sleep(x); return 0; } else { @@ -341,12 +343,24 @@ bool CLIENT_STATE::do_something() { return false; } + check_suspend_network(reason); + if (reason) { + if (!network_suspended) { + suspend_network(reason); + } + } else { + if (network_suspended) { + resume_network(); + } + } + network_suspended = (reason != 0); + scope_messages.printf("CLIENT_STATE::do_something(): Begin poll:\n"); ++scope_messages; ss_logic.poll(); if (activities_suspended) { - scope_messages.printf("CLIENT_STATE::do_something(): No active tasks! (suspended)\n"); + scope_messages.printf("CLIENT_STATE::do_something(): activities suspended\n"); POLL_ACTION(net_xfers , net_xfers->poll ); POLL_ACTION(http_ops , http_ops->poll ); POLL_ACTION(scheduler_rpc , scheduler_rpc_poll ); @@ -354,6 +368,19 @@ bool CLIENT_STATE::do_something() { POLL_ACTION(update_results , update_results ); #ifndef _WIN32 POLL_ACTION(gui_rpc , gui_rpcs.poll ); +#endif + } else if (network_suspended) { + scope_messages.printf("CLIENT_STATE::do_something(): network suspended\n"); + POLL_ACTION(net_xfers , net_xfers->poll ); + POLL_ACTION(http_ops , http_ops->poll ); + POLL_ACTION(active_tasks , active_tasks.poll ); + POLL_ACTION(start_apps , start_apps ); + POLL_ACTION(handle_finished_apps , handle_finished_apps ); + POLL_ACTION(scheduler_rpc , scheduler_rpc_poll ); + POLL_ACTION(garbage_collect , garbage_collect ); + POLL_ACTION(update_results , update_results ); +#ifndef _WIN32 + POLL_ACTION(gui_rpc , gui_rpcs.poll ); #endif } else { net_stats.poll(*net_xfers); diff --git a/client/client_state.h b/client/client_state.h index 8a5458c76e..266741e433 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -86,6 +86,9 @@ public: int file_xfer_giveup_period; bool user_idle; int user_run_request; + // values above (USER_RUN_REQUEST_*) + int user_network_request; + // same, just for network bool started_by_screensaver; bool exit_when_idle; bool return_results_immediately; @@ -110,6 +113,7 @@ public: bool previous_activities_suspended; // if activities were suspended in the previous check_suspend(); // this is needed to update GUI windows after suspension and close transfers/files. + bool network_suspended; bool executing_as_windows_service; private: @@ -219,6 +223,9 @@ private: void check_suspend_activities(int&); int suspend_activities(int reason); int resume_activities(); + void check_suspend_network(int&); + int suspend_network(int reason); + int resume_network(); void install_global_prefs(); void show_global_prefs_source(bool); diff --git a/client/cs_prefs.C b/client/cs_prefs.C index 5bbe7c09f4..6df22c286c 100644 --- a/client/cs_prefs.C +++ b/client/cs_prefs.C @@ -115,8 +115,6 @@ void CLIENT_STATE::check_suspend_activities(int& reason) { reason |= SUSPEND_REASON_BATTERIES; } - // user_idle is set in the Mac/Win GUI code - // if (!global_prefs.run_if_user_active && !user_idle) { reason |= SUSPEND_REASON_USER_ACTIVE; } @@ -130,7 +128,7 @@ void CLIENT_STATE::check_suspend_activities(int& reason) { int CLIENT_STATE::suspend_activities(int reason) { string s_reason; - s_reason = "Suspending computation and file transfer"; + s_reason = "Suspending computation and network activity"; if (reason & SUSPEND_REASON_BATTERIES) { s_reason += " - on batteries"; } @@ -161,6 +159,32 @@ int CLIENT_STATE::resume_activities() { return 0; } +void CLIENT_STATE::check_suspend_network(int& reason) { + reason = 0; + + if (user_network_request == USER_RUN_REQUEST_ALWAYS) return; + if (user_network_request == USER_RUN_REQUEST_NEVER) { + reason |= SUSPEND_REASON_USER_REQ; + return; + } + return; +} + +int CLIENT_STATE::suspend_network(int reason) { + string s_reason; + s_reason = "Suspending network activity"; + if (reason & SUSPEND_REASON_USER_REQ) { + s_reason += " - user request"; + } + msg_printf(NULL, MSG_INFO, const_cast(s_reason.c_str())); + pers_file_xfers->suspend(); + return 0; +} + +int CLIENT_STATE::resume_network() { + return 0; +} + void CLIENT_STATE::show_global_prefs_source(bool found_venue) { PROJECT* pp = lookup_project(global_prefs.source_project.c_str()); if (pp) { diff --git a/client/gui_rpc_client.h b/client/gui_rpc_client.h index 5a88503682..71b159a43f 100644 --- a/client/gui_rpc_client.h +++ b/client/gui_rpc_client.h @@ -139,6 +139,15 @@ public: ~RPC_CLIENT(); int init(char*); int get_state(); + int result_show_graphics(RESULT&); + int project_reset(PROJECT&); + int project_attach(char* url, char* auth); + int project_detach(PROJECT&); + int project_update(PROJECT&); + int set_run_mode(int mode); + int run_benchmarks(); + int set_proxy_settings(PROXY_INFO&); + int get_messages(int nmessages, int offset, vector&); void print(); }; diff --git a/client/gui_rpc_server.C b/client/gui_rpc_server.C index 635151fda2..058fbcab21 100644 --- a/client/gui_rpc_server.C +++ b/client/gui_rpc_server.C @@ -175,6 +175,60 @@ static void handle_set_proxy_settings(char* buf, FILE* fout) { fprintf(fout, "\n"); } +// params: +// x +// return at most this many messages +// n +// start at message n. +// if no offset is given, return last n messages +// +void handle_get_messages(char* buf, FILE* fout) { + int nmessages=-1, offset=-1, j; + unsigned int i; + + parse_int(buf, "", nmessages); + parse_int(buf, "", offset); + if (nmessages < 0) { + fprintf(fout, "No nmessages given\n"); + return; + } + + if (offset > (int)message_descs.size()) { + offset = message_descs.size(); + } + if (offset < 0) { + offset = message_descs.size()-nmessages; + if (offset < 0) { + offset = 0; + } + } + + fprintf(fout, "\n"); + j = 0; + for (i=offset; i\n" + " %d\n" + " %d\n" + " %s\n" + " \n", + i, + md.priority, + md.message.c_str(), + md.timestamp + ); + if (md.project) { + fprintf(fout, + " %s", + md.project->get_project_name() + ); + } + fprintf(fout, "\n"); + } + fprintf(fout, "\n"); +} + int GUI_RPC_CONN::handle_rpc() { char buf[1024]; int n; @@ -205,11 +259,13 @@ int GUI_RPC_CONN::handle_rpc() { handle_run_benchmarks(buf, fout); } else if (match_tag(buf, "")) { handle_set_proxy_settings(buf, fout); + } else if (match_tag(buf, "")) { + handle_get_messages(buf, fout); } else { fprintf(fout, "\n"); } fflush(fout); - return 0; + return 0; } int GUI_RPC_CONN_SET::insert(GUI_RPC_CONN* p) { diff --git a/client/main.C b/client/main.C index 6260011cf5..6ef1f23ee8 100644 --- a/client/main.C +++ b/client/main.C @@ -79,6 +79,8 @@ void project_add_failed(PROJECT* project) { void show_message(PROJECT *p, char* msg, int priority) { char* x; char message[1024]; + time_t now = time(0); + char* time_string = time_to_string(now); #if defined(WIN32) && defined(_CONSOLE) char event_message[2048]; #endif @@ -93,34 +95,39 @@ void show_message(PROJECT *p, char* msg, int priority) { } else { x = "---"; } + + MESSAGE_DESC md; + md.project = p; + md.priority = priority; + md.timestamp = now; + md.message = msg; + message_descs.push_back(md); + switch (priority) { case MSG_ERROR: - fprintf(stderr, "%s [%s] %s\n", timestamp(), x, message); - printf("%s [%s] %s\n", timestamp(), x, message); - if (gstate.executing_as_windows_service) - { + fprintf(stderr, "%s [%s] %s\n", time_string, x, message); + printf("%s [%s] %s\n", time_string, x, message); + if (gstate.executing_as_windows_service) { #if defined(WIN32) && defined(_CONSOLE) - _stprintf(event_message, TEXT("%s [%s] %s\n"), timestamp(), x, message); + _stprintf(event_message, TEXT("%s [%s] %s\n"), time_string, x, message); LogEventErrorMessage(event_message); #endif } break; case MSG_WARNING: - printf("%s [%s] %s\n", timestamp(), x, message); - if (gstate.executing_as_windows_service) - { + printf("%s [%s] %s\n", time_string, x, message); + if (gstate.executing_as_windows_service) { #if defined(WIN32) && defined(_CONSOLE) - _stprintf(event_message, TEXT("%s [%s] %s\n"), timestamp(), x, message); + _stprintf(event_message, TEXT("%s [%s] %s\n"), time_string, x, message); LogEventWarningMessage(event_message); #endif } break; case MSG_INFO: - printf("%s [%s] %s\n", timestamp(), x, message); - if (gstate.executing_as_windows_service) - { + printf("%s [%s] %s\n", time_string, x, message); + if (gstate.executing_as_windows_service) { #if defined(WIN32) && defined(_CONSOLE) - _stprintf(event_message, TEXT("%s [%s] %s\n"), timestamp(), x, message); + _stprintf(event_message, TEXT("%s [%s] %s\n"), time_string, x, message); LogEventInfoMessage(event_message); #endif } diff --git a/client/message.C b/client/message.C index 9efe15b184..48bab079dd 100644 --- a/client/message.C +++ b/client/message.C @@ -27,6 +27,8 @@ #include "message.h" +vector message_descs; + // Takes a printf style formatted string, inserts the proper values, // and passes it to show_message // TODO: add translation functionality diff --git a/client/message.h b/client/message.h index 3db642fa7c..e9ae95db21 100644 --- a/client/message.h +++ b/client/message.h @@ -20,18 +20,31 @@ #ifndef MESSAGE_H #define MESSAGE_H +#include + #include "util.h" +#include "client_types.h" // Show a message, preceded by timestamp and project name // priorities: #define MSG_INFO 1 - // cmdline: write to stdout + // write to stdout // GUI: write to msg window #define MSG_ERROR 2 - // cmdline: write to stderr + // write to stderr // GUI: write to msg window in bold or red #define MSG_WARNING 3 + // deprecated - do not use + +struct MESSAGE_DESC { + PROJECT* project; + int priority; + int timestamp; + string message; +}; + +extern vector message_descs; extern void show_message(class PROJECT *p, char* message, int priority); @@ -59,6 +72,7 @@ extern ClientMessages log_messages; // the __attribute((format...)) tags are GCC extensions that let the compiler // do like-checking on printf-like arguments +// #if !defined(__GNUC__) && !defined(__attribute__) #define __attribute__(x) /*nothing*/ #endif diff --git a/lib/messages.C b/lib/messages.C index 403616f40f..e810918614 100644 --- a/lib/messages.C +++ b/lib/messages.C @@ -61,16 +61,14 @@ using namespace std; // See sched/sched_messages.C and client/client_messages.C for those classes. -Messages::Messages(FILE* output_) -{ +Messages::Messages(FILE* output_) { output = output_; indent_level = 0; spaces[0] = 0; strcpy(spaces+1, " "); } -void Messages::enter_level(int diff) -{ +void Messages::enter_level(int diff) { assert (indent_level >= 0); spaces[indent_level] = ' '; indent_level += diff*2; @@ -78,16 +76,17 @@ void Messages::enter_level(int diff) assert (indent_level >= 0); } -void Messages::vprintf(int kind, const char* format, va_list va) -{ +void Messages::vprintf(int kind, const char* format, va_list va) { + const char* now_timestamp = time_to_string(time(0)); if (!v_message_wanted(kind)) return; - fprintf(output, "%s [%s]%s ", timestamp(), v_format_kind(kind), spaces); + fprintf(output, "%s [%s]%s ", now_timestamp, v_format_kind(kind), spaces); vfprintf(output, format, va); } // break a multi-line string into lines (so that we show prefix on each line) -void Messages::vprintf_multiline(int kind, const char* str, const char* prefix_format, va_list va) -{ +void Messages::vprintf_multiline( + int kind, const char* str, const char* prefix_format, va_list va +) { if (!v_message_wanted(kind)) return; if (str == NULL) return; @@ -95,7 +94,7 @@ void Messages::vprintf_multiline(int kind, const char* str, const char* prefix_f if (prefix_format) { vsprintf(sprefix, prefix_format, va); } - const char* now_timestamp = timestamp(); + const char* now_timestamp = time_to_string(time(0)); const char* skind = v_format_kind(kind); string line; @@ -113,15 +112,16 @@ void Messages::vprintf_multiline(int kind, const char* str, const char* prefix_f } } -void Messages::vprintf_file(int kind, const char* filename, const char* prefix_format, va_list va) -{ +void Messages::vprintf_file( + int kind, const char* filename, const char* prefix_format, va_list va +) { if (!v_message_wanted(kind)) return; char sprefix[256] = ""; if (prefix_format) { vsprintf(sprefix, prefix_format, va); } - const char* now_timestamp = timestamp(); + const char* now_timestamp = time_to_string(time(0)); const char* skind = v_format_kind(kind); ifstream f(filename); @@ -133,24 +133,25 @@ void Messages::vprintf_file(int kind, const char* filename, const char* prefix_f } } -void Messages::printf(int kind, const char* format, ...) -{ +void Messages::printf(int kind, const char* format, ...) { va_list va; va_start(va, format); vprintf(kind, format, va); va_end(va); } -void Messages::printf_multiline(int kind, const char* str, const char* prefix_format, ...) -{ +void Messages::printf_multiline( + int kind, const char* str, const char* prefix_format, ... +) { va_list va; va_start(va, prefix_format); vprintf_multiline(kind, str, prefix_format, va); va_end(va); } -void Messages::printf_file(int kind, const char* filename, const char* prefix_format, ...) -{ +void Messages::printf_file( + int kind, const char* filename, const char* prefix_format, ... +) { va_list va; va_start(va, prefix_format); vprintf_file(kind, filename, prefix_format, va); @@ -162,24 +163,25 @@ void Messages::printf_file(int kind, const char* filename, const char* prefix_fo // corresponding Messages functions with the same name, passing the KIND that // was specified on creation of the ScopeMessages object. -void ScopeMessages::printf(const char* format, ...) -{ +void ScopeMessages::printf(const char* format, ...) { va_list va; va_start(va, format); messages.vprintf(kind, format, va); va_end(va); } -void ScopeMessages::printf_multiline(const char* str, const char* prefix_format, ...) -{ +void ScopeMessages::printf_multiline( + const char* str, const char* prefix_format, ... +) { va_list va; va_start(va, prefix_format); messages.vprintf_multiline(kind, str, prefix_format, va); va_end(va); } -void ScopeMessages::printf_file(const char* filename, const char* prefix_format, ...) -{ +void ScopeMessages::printf_file( + const char* filename, const char* prefix_format, ... +) { va_list va; va_start(va, prefix_format); messages.vprintf_file(kind, filename, prefix_format, va); diff --git a/lib/util.C b/lib/util.C index d2e388e35e..a6fa1d3ec0 100755 --- a/lib/util.C +++ b/lib/util.C @@ -425,12 +425,6 @@ char* time_to_string(time_t x) { return buf; } -// return current time of day as ASCII string, no CR -// -char* timestamp() { - return time_to_string(time(0)); -} - // set by command line bool debug_fake_exponential_backoff = false; double debug_total_exponential_backoff = 0; diff --git a/lib/util.h b/lib/util.h index 04d86e1189..3adf80f8fc 100755 --- a/lib/util.h +++ b/lib/util.h @@ -50,7 +50,6 @@ extern void safe_strncpy(char*, const char*, int); #define safe_strcpy(x, y) safe_strncpy(x, y, sizeof(x)) #define safe_strcat(x, y) if (strlen(x)+strlen(y)