diff --git a/api/boinc_api.cpp b/api/boinc_api.cpp index 84c4e21f3b..592388bb05 100644 --- a/api/boinc_api.cpp +++ b/api/boinc_api.cpp @@ -131,6 +131,9 @@ using std::vector; //#define MSGS_FROM_FILE // get messages from a file "msgs.txt" instead of shared mem +//#define ANDROID + // use the Android thread/signal logic, which works on Linux too + #ifdef __APPLE__ #include "mac_backtrace.h" #endif @@ -281,6 +284,9 @@ char* boinc_msg_prefix(char* sbuf, int len) { return sbuf; } +#ifdef MSGS_FROM_FILE +static FILE* fout = fopen("out_msgs.txt", "w"); +#else static int setup_shared_mem() { char buf[256]; if (standalone) { @@ -324,6 +330,7 @@ static int setup_shared_mem() { if (app_client_shm == NULL) return -1; return 0; } +#endif // MSGS_FROM_FILE // a mutex for data structures shared between time and worker threads // @@ -420,31 +427,41 @@ static bool update_app_progress(double cpu_t, double cp_cpu_t) { sprintf(buf, "%f\n", bytes_received); strlcat(msg_buf, buf, sizeof(msg_buf)); } +#ifdef MSGS_FROM_FILE + fputs(msg_buf, fout); + return 0; +#else return app_client_shm->shm->app_status.send_msg(msg_buf); +#endif } +// called in timer thread +// static void handle_heartbeat_msg() { char buf[MSG_CHANNEL_SIZE]; double dtemp; bool btemp; - if (app_client_shm->shm->heartbeat.get_msg(buf)) { - boinc_status.network_suspended = false; - if (match_tag(buf, "")) { - heartbeat_giveup_count = interrupt_count + HEARTBEAT_GIVEUP_COUNT; - } - if (parse_double(buf, "", dtemp)) { - boinc_status.working_set_size = dtemp; - } - if (parse_double(buf, "", dtemp)) { - boinc_status.max_working_set_size = dtemp; - } - if (parse_bool(buf, "suspend_network", btemp)) { - boinc_status.network_suspended = btemp; - } + if (!app_client_shm->shm->heartbeat.get_msg(buf)) { + return; + } + boinc_status.network_suspended = false; + if (match_tag(buf, "")) { + heartbeat_giveup_count = interrupt_count + HEARTBEAT_GIVEUP_COUNT; + } + if (parse_double(buf, "", dtemp)) { + boinc_status.working_set_size = dtemp; + } + if (parse_double(buf, "", dtemp)) { + boinc_status.max_working_set_size = dtemp; + } + if (parse_bool(buf, "suspend_network", btemp)) { + boinc_status.network_suspended = btemp; } } +// called in timer thread +// static bool client_dead() { char buf[256]; bool dead; @@ -521,11 +538,13 @@ static void parallel_master(int child_pid) { #endif int boinc_init() { +#ifndef MSGS_FROM_FILE int retval; if (!diagnostics_is_initialized()) { retval = boinc_init_diagnostics(BOINC_DIAG_DEFAULTS); if (retval) return retval; } +#endif boinc_options_defaults(options); return boinc_init_options(&options); } @@ -592,20 +611,23 @@ int boinc_set_min_checkpoint_period(int x) { } int boinc_init_options_general(BOINC_OPTIONS& opt) { - int retval; - char buf[256]; options = opt; +#ifndef MSGS_FROM_FILE + int retval; if (!diagnostics_is_initialized()) { retval = boinc_init_diagnostics(BOINC_DIAG_DEFAULTS); if (retval) return retval; } +#endif boinc_status.no_heartbeat = false; boinc_status.suspended = false; boinc_status.quit_request = false; boinc_status.abort_request = false; +#ifndef MSGS_FROM_FILE + char buf[256]; if (options.main_program) { // make sure we're the only app running in this slot // @@ -654,6 +676,7 @@ int boinc_init_options_general(BOINC_OPTIONS& opt) { standalone = true; } } +#endif // MSGS_FROM_FILE // copy the WU CPU time to a separate var, // since we may reread the structure again later. @@ -836,6 +859,9 @@ int boinc_is_standalone() { // called from the timer thread if we need to exit, // e.g. quit message from client, or client has gone away // +// On Linux we can't exit directly from the timer thread. +// Set a flag telling the worker thread to exit. +// static void exit_from_timer_thread(int status) { #ifdef VERBOSE char buf[256]; @@ -863,13 +889,14 @@ static void exit_from_timer_thread(int status) { pthread_kill(worker_thread_handle, SIGALRM); // the exit should happen more or less instantly. - // But if we're still here after 2 sec, exit directly + // But if we're still here after 5 sec, exit directly // - sleep(2.0); + sleep(5.0); boinc_exit(status); -#endif +#else pthread_exit(NULL); #endif +#endif } // parse the init data file. @@ -940,10 +967,15 @@ int boinc_report_app_status_aux( sprintf(buf, "%f\n", _bytes_received); safe_strcat(msg_buf, buf); } +#ifdef MSGS_FROM_FILE + fputs(msg_buf, fout); + return 0; +#else if (app_client_shm->shm->app_status.send_msg(msg_buf)) { return 0; } return ERR_WRITE; +#endif } int boinc_report_app_status( @@ -1032,6 +1064,7 @@ int resume_activities() { return 0; } +#ifndef MSGS_FROM_FILE static void handle_upload_file_status() { char path[MAXPATHLEN], buf[256], log_name[256], *p, log_buf[256]; std::string filename; @@ -1080,6 +1113,7 @@ static void handle_trickle_down_msg() { } } } +#endif // This flag is set of we get a suspend request while in a critical section, // and options.direct_process_action is set. @@ -1092,94 +1126,105 @@ static bool suspend_request = false; static void handle_process_control_msg() { char buf[MSG_CHANNEL_SIZE]; #ifdef MSGS_FROM_FILE - char msg_buf[1024]; - strcpy(msg_buf, ""); + strcpy(buf, ""); if (boinc_file_exists("msgs.txt")) { FILE* f = fopen("msgs.txt", "r"); - fgets(msg_buf, sizeof(msg_buf), f); + fgets(buf, sizeof(buf), f); fclose(f); - } - if (strlen(msg_buf)) { unlink("msgs.txt"); + } + if (!strlen(buf)) { + return; + } #else - if (app_client_shm->shm->process_control_request.get_msg(buf)) { + if (!app_client_shm->shm->process_control_request.get_msg(buf)) { + return; + } #endif - acquire_mutex(); + // here if we have a message to process + + acquire_mutex(); #ifdef VERBOSE - char log_buf[256]; - fprintf(stderr, "%s got process control msg %s\n", - boinc_msg_prefix(log_buf, sizeof(log_buf)), buf - ); + char log_buf[256]; + fprintf(stderr, "%s got process control msg %s\n", + boinc_msg_prefix(log_buf, sizeof(log_buf)), buf + ); #endif - if (match_tag(buf, "")) { - BOINCINFO("Received suspend message"); - if (options.direct_process_action) { - if (in_critical_section) { - suspend_request = true; - } else { - boinc_status.suspended = true; - suspend_request = false; - suspend_activities(false); - } + if (match_tag(buf, "")) { + BOINCINFO("Received suspend message"); + if (options.direct_process_action) { + if (in_critical_section) { + suspend_request = true; } else { boinc_status.suspended = true; + suspend_request = false; + suspend_activities(false); } + } else { + boinc_status.suspended = true; } - - if (match_tag(buf, "")) { - BOINCINFO("Received resume message"); - if (options.direct_process_action) { - if (boinc_status.suspended) { - resume_activities(); - } else if (suspend_request) { - suspend_request = false; - } - } - boinc_status.suspended = false; - } - - if (boinc_status.quit_request || match_tag(buf, "")) { - BOINCINFO("Received quit message"); - boinc_status.quit_request = true; - if (!in_critical_section && options.direct_process_action) { - release_mutex(); - // we hold mutex, and it's possible that worker - // is waiting on it, so release it - exit_from_timer_thread(0); - } - } - if (boinc_status.abort_request || match_tag(buf, "")) { - BOINCINFO("Received abort message"); - boinc_status.abort_request = true; - if (!in_critical_section && options.direct_process_action) { - diagnostics_set_aborted_via_gui(); -#if defined(_WIN32) - // Cause a controlled assert and dump the callstacks. - DebugBreak(); -#elif defined(__APPLE__) - PrintBacktrace(); -#endif - release_mutex(); - exit_from_timer_thread(EXIT_ABORTED_BY_CLIENT); - } - } - if (match_tag(buf, "")) { - boinc_status.reread_init_data_file = true; - } - if (match_tag(buf, "")) { - have_network = 1; - } - release_mutex(); } + + if (match_tag(buf, "")) { + BOINCINFO("Received resume message"); + if (options.direct_process_action) { + if (boinc_status.suspended) { + resume_activities(); + } else if (suspend_request) { + suspend_request = false; + } + } + boinc_status.suspended = false; + } + + if (boinc_status.quit_request || match_tag(buf, "")) { + BOINCINFO("Received quit message"); + boinc_status.quit_request = true; + if (!in_critical_section && options.direct_process_action) { + release_mutex(); + // we hold mutex, and it's possible that worker + // is waiting on it, so release it + exit_from_timer_thread(0); + } + } + if (boinc_status.abort_request || match_tag(buf, "")) { + BOINCINFO("Received abort message"); + boinc_status.abort_request = true; + if (!in_critical_section && options.direct_process_action) { + diagnostics_set_aborted_via_gui(); +#if defined(_WIN32) + // Cause a controlled assert and dump the callstacks. + DebugBreak(); +#elif defined(__APPLE__) + PrintBacktrace(); +#endif + release_mutex(); + exit_from_timer_thread(EXIT_ABORTED_BY_CLIENT); + } + } + if (match_tag(buf, "")) { + boinc_status.reread_init_data_file = true; + } + if (match_tag(buf, "")) { + have_network = 1; + } +#ifdef ANDROID + // Trigger call to worker_signal_handler() in the worker thread + // + pthread_kill(worker_thread_handle, SIGALRM); +#endif + release_mutex(); } // timer handler; called every 0.1 sec in the timer thread // static void timer_handler() { char buf[512]; -#ifdef VERBOSE - fprintf(stderr, "%s timer handler: disabled %s; in critical section %s; finishing %s\n", +//#ifdef VERBOSE +#if 0 + fprintf(stderr, + "%s timer handler: disabled %s; in critical section %s; finishing %s\n", boinc_msg_prefix(buf, sizeof(buf)), boinc_disable_timer_thread?"yes":"no", in_critical_section?"yes":"no", @@ -1204,6 +1249,9 @@ static void timer_handler() { } // handle messages from the client // +#ifdef MSGS_FROM_FILE + handle_process_control_msg(); +#else if (app_client_shm) { if (options.check_heartbeat) { handle_heartbeat_msg(); @@ -1215,10 +1263,6 @@ static void timer_handler() { handle_process_control_msg(); } } -#ifdef ANDROID - // Trigger call to worker_signal_handler() in the worker thread - // - pthread_kill(worker_thread_handle, SIGALRM); #endif if (interrupt_count % TIMERS_PER_SEC) return; @@ -1319,14 +1363,33 @@ static void* timer_thread(void*) { // It must call only signal-safe functions, and must not do FP math // static void worker_signal_handler(int) { +#ifdef ANDROID + // per-thread signal masking doesn't work on pre-4.1 Android. + // If we're handling this signal in the timer thread, + // send signal explicitly to worker thread. + // + if (pthread_self() != worker_thread_handle) { +#ifdef VERBOSE + fprintf(stderr, "worker signal handler: called in timer thread; forwarding to worker\n"); +#endif + pthread_kill(worker_thread_handle, SIGALRM); + return; + } +#endif #ifndef GETRUSAGE_IN_TIMER_THREAD getrusage(RUSAGE_SELF, &worker_thread_ru); #endif if (worker_thread_exit_flag) { +#ifdef VERBOSE + fprintf(stderr, "worker signal handler: exiting\n"); +#endif boinc_exit(worker_thread_exit_status); } if (options.direct_process_action) { while (boinc_status.suspended && in_critical_section==0) { +#ifdef VERBOSE + fprintf(stderr, "worker signal handler: sleeping\n"); +#endif sleep(1); // don't use boinc_sleep() because it does FP math } }