int ModeReqSetArg(int mode, const void *arg) { if (mode == MODEREQ_UNLOCK) modereq.filetounlock = (const char *)arg; else if (mode == MODEREQ_IMPORT) modereq.filetoimport = (const char *)arg; else if (mode == MODEREQ_CMDLINE_HELP) modereq.helpoption = (const char *)arg; else if (mode == MODEREQ_CONFIG) modereq.cmdline_config = 1; else return -1; ModeReqSet(mode); return 0; }
unsigned int LoadSaveProblems(Client *client, unsigned int load_problem_count,int mode) { /* Some platforms need to stop asynchronously, for example, Win16 which gets an ENDSESSION message and has to exit then and there. So also win9x when running as a service where windows suspends all threads except the window thread. For these (and perhaps other platforms) we save our last state so calling with (0,0,0) will save the problem states (without hanging). see 'abortive_action' below. */ static Client *previous_client = 0; static unsigned int previous_load_problem_count = 0, reentrant_count = 0; static int abortive_action = 0; unsigned int retval = 0; int changed_flag, first_time; int allclosed, prob_step,bufupd_pending; unsigned int cont_i, prob_for, prob_first, prob_last; unsigned int loaded_problems_count[CONTEST_COUNT]; unsigned int saved_problems_count[CONTEST_COUNT]; unsigned long totalBlocksDone; /* all contests */ unsigned int total_problems_loaded, total_problems_saved; unsigned int norandom_count, getbuff_errs, empty_problems; allclosed = 0; norandom_count = getbuff_errs = empty_problems = 0; changed_flag = (previous_load_problem_count == 0); total_problems_loaded = 0; total_problems_saved = 0; bufupd_pending = 0; totalBlocksDone = 0; /* ============================================================= */ if (abortive_action) /* already aborted once */ { /* no probfill action can happen again */ return 0; } if (!client) /* abnormal end */ { client = previous_client; if (!client) return 0; abortive_action = 1; mode = PROBFILL_UNLOADALL; } previous_client = client; if ((++reentrant_count) > 1) { --reentrant_count; return 0; } /* ============================================================= */ prob_first = 0; prob_step = 0; prob_last = 0; first_time = 0; if (load_problem_count == 0) /* only permitted if unloading all */ { if (mode != PROBFILL_UNLOADALL || previous_load_problem_count == 0) { --reentrant_count; return 0; } load_problem_count = previous_load_problem_count; } if (previous_load_problem_count == 0) /* must be initial load */ { /* [0 ... (load_problem_count - 1)] */ prob_first = 0; prob_last = (load_problem_count - 1); prob_step = 1; first_time = 1; } else if (mode == PROBFILL_RESIZETABLE) { /* [(previousload_problem_count-1) ... load_problem_count] */ prob_first = load_problem_count; prob_last = (previous_load_problem_count - 1); prob_step = -1; } else /* PROBFILL_UNLOADALL, PROBFILL_REFRESH */ { /* [(load_problem_count - 1) ... 0] */ prob_first = 0; prob_last = (load_problem_count - 1); prob_step = -1; } TRACE_BUFFUPD((+1, "LoadSaveProblems(%d)\n", mode)); /* ============================================================= */ for (cont_i = 0; cont_i < CONTEST_COUNT; cont_i++) { unsigned int blocksdone; if (CliGetContestInfoSummaryData( cont_i, &blocksdone, NULL, NULL, NULL, NULL )==0) totalBlocksDone += blocksdone; loaded_problems_count[cont_i] = 0; saved_problems_count[cont_i] = 0; } /* ============================================================= */ ClientEventSyncPost(CLIEVENT_PROBLEM_TFILLSTARTED, &load_problem_count, sizeof(load_problem_count)); for (prob_for = 0; prob_for <= (prob_last - prob_first); prob_for++) { Problem *thisprob; int load_needed; unsigned int prob_i = prob_for + prob_first; if ( prob_step < 0 ) prob_i = prob_last - prob_for; thisprob = GetProblemPointerFromIndex( prob_i ); if (thisprob == 0) { if (prob_step < 0) continue; break; } // ----------------------------------- load_needed = 0; if (__IndividualProblemSave( thisprob, prob_i, client, &load_needed, load_problem_count, &cont_i, &bufupd_pending, (mode == PROBFILL_UNLOADALL || mode == PROBFILL_RESIZETABLE ), abortive_action )) { changed_flag = 1; total_problems_saved++; saved_problems_count[cont_i]++; totalBlocksDone++; } if (load_needed) empty_problems++; TRACE_BUFFUPD((0, "__IndividualProblemSave ==> bufupd_pending = %d\n", bufupd_pending)); //--------------------------------------- if (load_needed && mode!=PROBFILL_UNLOADALL && mode!=PROBFILL_RESIZETABLE) { // Bug #3672 (all clients running at least 2 cores). // Take the number of still active crunchers into account to determine // whether we can load another problem. // Bug #4018: It will not work for initial load: this 'if' will load // packet to LAST cruncher while main loop will start FIRST cruncher. // So here is a second 'if' for inital load (when mode==0), it will // load cruncher from start up to block count. (I wonder can old 'if' // be completely replaced with new one.) if (client->blockcount > 0) { if (mode == 0) { /* Load from beginning to up max. count, skip last crunchers */ if (totalBlocksDone+total_problems_loaded >= (unsigned long)client->blockcount) load_needed = 0; } else { /* Skip first crunchers, load from middle to last */ if (totalBlocksDone+load_problem_count-empty_problems>=((unsigned long)(client->blockcount))) load_needed = 0; } } if (load_needed) { load_needed = 0; if (__IndividualProblemLoad( thisprob, prob_i, client, &load_needed, load_problem_count, &cont_i, &bufupd_pending )) { empty_problems--; total_problems_loaded++; loaded_problems_count[cont_i]++; changed_flag = 1; } TRACE_BUFFUPD((0, "__IndividualProblemLoad ==> bufupd_pending = %d\n", bufupd_pending)); if (load_needed) { getbuff_errs++; if (load_needed == NOLOAD_ALLCONTESTSCLOSED) { allclosed = 1; break; /* the for ... prob_i ... loop */ } else if (load_needed == NOLOAD_NORANDOM) norandom_count++; } } } //if (load_needed) } //for (prob_i = 0; prob_i < load_problem_count; prob_i++ ) ClientEventSyncPost(CLIEVENT_PROBLEM_TFILLFINISHED, ((previous_load_problem_count==0)?(&total_problems_loaded):(&total_problems_saved)), sizeof(total_problems_loaded)); /* ============================================================= */ if (mode == PROBFILL_UNLOADALL) { previous_load_problem_count = 0; if (client->nodiskbuffers == 0) { // close checkpoint file immediately after saving the problems to disk CheckpointAction( client, CHECKPOINT_CLOSE, 0 ); } else if (!CheckRestartRequestTrigger()) /* no disk buffers */ { TRACE_BUFFUPD((0, "BufferUpdate: reason = LoadSaveProblem && unload all && membuffers\n")); BufferUpdate(client,BUFFERUPDATE_FLUSH,0); /* in case the flush fails, empty the membuf table manually */ for (cont_i = 0; cont_i < CONTEST_COUNT; cont_i++) { WorkRecord data; while (GetBufferCount(client, cont_i, 0, 0)>0) GetBufferRecord( client, &data, cont_i, 0 ); while (GetBufferCount(client, cont_i, 0, 0)>0) GetBufferRecord( client, &data, cont_i, 1); } } retval = total_problems_saved; } else /* if (mode != PROBFILL_UNLOADALL) */ { /* ============================================================= // save the number of active problems, so that we can bail out // in an "emergency". Some platforms call us asynchronously when they // need to abort [win16/win32 for example] ------------------------------------------------------------- */ previous_load_problem_count = load_problem_count; if (bufupd_pending && client->blockcount >= 0) { int req = MODEREQ_FLUSH; // always flush while fetching if (!CheckExitRequestTriggerNoIO()) //((bufupd_pending & BUFFERUPDATE_FETCH)!=0) req |= MODEREQ_FETCH; TRACE_BUFFUPD((0, "ModeReqSet(flush=%d, fetch=%d, fquiet=1)\n", (req & MODEREQ_FLUSH) != 0, (req & MODEREQ_FETCH) != 0)); ModeReqSet( req|MODEREQ_FQUIET ); /* delegate to the client.run loop */ } if (!allclosed && mode != PROBFILL_RESIZETABLE) { /* ============================================================= if we are running a limited number of blocks then check if we have exceeded that number. If we have, but one or more crunchers are still at work, bump the limit. ------------------------------------------------------------- */ if (client->blockcount < 0 || (client->blockcount > 0 && totalBlocksDone >= (unsigned long)(client->blockcount))) { if (empty_problems >= load_problem_count) { Log( "Shutdown - packet limit exceeded.\n" ); RaiseExitRequestTrigger(); } // Bug #3672 (all clients running at least 2 cores). // The following two lines prevent the client from stopping as // instructed by option "-n" when running at least two crunchers // simultaneously. //else // client->blockcount = ((u32)(totalBlocksDone))+1; } } if (mode == PROBFILL_RESIZETABLE) retval = total_problems_saved; else if (mode == PROBFILL_GETBUFFERRS) retval = getbuff_errs; else if (mode == PROBFILL_ANYCHANGED) retval = changed_flag; else retval = total_problems_loaded; } /* ============================================================= */ for ( cont_i = 0; cont_i < CONTEST_COUNT; cont_i++) //once for each contest { int show_totals = 0; if (loaded_problems_count[cont_i] || saved_problems_count[cont_i]) show_totals = 1; if (first_time || show_totals) { unsigned int inout; const char *cont_name = CliGetContestNameFromID(cont_i); if (loaded_problems_count[cont_i] && load_problem_count > COMBINEMSG_THRESHOLD ) { Log( "%s: Loaded %u packet%s from %s\n", cont_name, loaded_problems_count[cont_i], ((loaded_problems_count[cont_i]==1)?(""):("s")), (client->nodiskbuffers ? "(memory-in)" : BufferGetDefaultFilename( cont_i, 0, client->in_buffer_basename )) ); } if (saved_problems_count[cont_i] && load_problem_count > COMBINEMSG_THRESHOLD && (client->nodiskbuffers == 0 || (mode != PROBFILL_UNLOADALL))) { Log( "%s: Saved %u packet%s to %s\n", cont_name, saved_problems_count[cont_i], ((saved_problems_count[cont_i]==1)?(""):("s")), (mode == PROBFILL_UNLOADALL)? (client->nodiskbuffers ? "(memory-in)" : BufferGetDefaultFilename( cont_i, 0, client->in_buffer_basename ) ) : (client->nodiskbuffers ? "(memory-out)" : BufferGetDefaultFilename( cont_i, 1, client->out_buffer_basename )) ); } if (show_totals && totalBlocksDone > 0) { // To suppress "odd" problem completion count summaries (and not be // quite so verbose) we only display summaries if the number of // completed problems is even divisible by the number of processors. // Requires a working GetNumberOfDetectedProcessors() [cpucheck.cpp] #if 0 int cpustmp; unsigned int cpus = 1; if ((cpustmp = GetNumberOfDetectedProcessors()) > 1) cpus = (unsigned int)cpustmp; if (load_problem_count > cpus) cpus = load_problem_count; if ((totalBlocksDone%cpus) == 0 ) #endif { __post_summary_for_contest(cont_i); } } /* -------------------------------------------------------------- */ for (inout=0;inout<=1;inout++) { unsigned long stats_count; long block_count = GetBufferCount( client, cont_i, inout, &stats_count ); if (show_totals && block_count >= 0) /* no error */ { char buffer[(3*80)+sizeof(client->in_buffer_basename)]; int len; len = sprintf(buffer, "%s: %ld packet%s ", cont_name, block_count, ((block_count == 1)?(""):("s")) ); if (stats_count) len += sprintf( &buffer[len], "(%lu.%02lu stats units) ", stats_count/100,stats_count%100); len += sprintf( &buffer[len], "%s in\n%s", ((inout!= 0 || mode == PROBFILL_UNLOADALL)? ((block_count==1)?("is"):("are")): ((block_count==1)?("remains"):("remain"))), ((inout== 0)? (client->nodiskbuffers ? "(memory-in)" : BufferGetDefaultFilename( cont_i, 0, client->in_buffer_basename ) ) : (client->nodiskbuffers ? "(memory-out)": BufferGetDefaultFilename( cont_i, 1, client->out_buffer_basename ) )) ); if (len < 55) /* fits on a single line, so unwrap */ { char *nl = strrchr( buffer, '\n' ); if (nl) *nl = ' '; } if (inout != 0) /* out-buffer */ { /* adjust bufupd_pending if outthresh has been crossed */ /* we don't check in-buffer here since we need cumulative count */ if (__check_outbufthresh_limit( client, cont_i, block_count, stats_count, &bufupd_pending )) { //Log("5. bufupd_pending |= BUFFERUPDATE_FLUSH;\n"); } } else /*in*/ if (stats_count && (mode!=PROBFILL_UNLOADALL)) { timeval tv; tv.tv_sec = __get_thresh_secs(client, cont_i, 0, stats_count, 0 ); if (tv.tv_sec > 0) { tv.tv_usec = 0; len += sprintf(&buffer[len], "\nProjected ideal time to completion: %s", CliGetTimeString( &tv, 2)); } } Log( "%s\n", buffer ); } //if (block_count >= 0) } // for (inout=0;inout<=1;inout++) } //if (loaded_problems_count[cont_i] || saved_problems_count[cont_i]) } //for ( cont_i = 0; cont_i < CONTEST_COUNT; cont_i++) /* ============================================================ */ if (mode == PROBFILL_UNLOADALL) { previous_load_problem_count = 0; previous_client = (Client *)0; if (!CheckRestartRequestTrigger()) Log("Shutdown complete.\n"); } --reentrant_count; TRACE_BUFFUPD((-1, "LoadSaveProblems => %d\n", retval)); return retval; }