text: /*
   * This file is part of John the Ripper password cracker,
   * Copyright (c) 1996-2001,2006,2009,2011 by Solar Designer
   *
   * ...with changes in the jumbo patch, by various authors
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted.
   *
   * There's ABSOLUTELY NO WARRANTY, express or implied.
   */
  
  #ifndef _XOPEN_SOURCE
  #define _XOPEN_SOURCE /* for nice(2) */
  #endif
  
  #include "os.h"
  
  #if (!AC_BUILT || HAVE_UNISTD_H) && !_MSC_VER
  #include <unistd.h>
  #endif
  #include <stdio.h>
  
  #ifdef _POSIX_PRIORITY_SCHEDULING
  #include <sched.h>
  #include <time.h>
  #include <sys/times.h>
  
  static int use_yield = 0;
  #endif
  
  #if HAVE_WINDOWS_H
  #include <windows.h>
  #endif
  
  #ifdef __CYGWIN__
  extern int nice(int);
  #endif
  
  #ifdef __BEOS__
  #include <OS.h>
  #endif
  
  #ifdef _OPENMP
  #include <omp.h>
  #endif
  
  #include "params.h"
  #include "config.h"
  #include "options.h"
  #include "signals.h"
  #include "bench.h"
  #include "formats.h"
  #include "memdbg.h"
  
  int idle_requested(struct fmt_main *format)
  {
  	if (!cfg_get_bool(SECTION_OPTIONS, NULL, "Idle", 1))
  		return 0;
  
  #ifdef _OPENMP
  	if ((format->params.flags & FMT_OMP) && omp_get_max_threads() > 1)
  		return 0;
  #endif
  #ifdef HAVE_OPENCL
  	if (strstr(format->params.label, "-opencl"))
  		return 0;
  #endif
  #ifdef HAVE_CUDA
  	if (strstr(format->params.label, "-cuda"))
  		return 0;
  #endif
  
  	return 1;
  }
  
  void idle_init(struct fmt_main *format)
  {
  #if defined(_POSIX_PRIORITY_SCHEDULING) && defined(SCHED_IDLE)
  	struct sched_param param = {0};
  #endif
  
  	if (!idle_requested(format) || (options.flags & FLG_STDOUT))
  		return;
  
  	clk_tck_init();
  
  #if defined(__MINGW32__) || defined (_MSC_VER)
  	SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
  	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
  #elif defined(__BEOS__)
  	set_thread_priority(getpid(), 1);
  #else
  /*
   * Normally, the range is -20 to 19, but some systems can do 20 as well (at
   * least some versions of Linux on Alpha), so we try 20.  We assume that we're
   * started with a non-negative nice value (so no need to increment it by more
   * than 20).
   */
  	if (nice(20) == -1)
  		perror("nice");
  #endif
  
  #if defined(_POSIX_PRIORITY_SCHEDULING) && defined(SCHED_IDLE)
  	use_yield = sched_setscheduler(getpid(), SCHED_IDLE, &param) != 0;
  #elif defined(_POSIX_PRIORITY_SCHEDULING)
  	use_yield = 1;
  #endif
  }
  
  void idle_yield(void)
  {
  #ifdef _POSIX_PRIORITY_SCHEDULING
  	static unsigned int calls_to_skip = 0;
  	static unsigned int calls_per_tick = 0;
  	static unsigned int calls_since_tick = 0;
  	static unsigned int calls_since_adj = 0;
  	static int calls_per_tick_known = 0;
  	static clock_t last_adj = 0;
  	clock_t last_check;
  	clock_t current;
  	int yield_calls;
  	struct tms buf;
  
  	if (!use_yield) return;
  
  	if (++calls_since_tick < calls_to_skip) return;
  	calls_since_adj += calls_since_tick;
  	calls_since_tick = 0;
  
  	current = times(&buf);
  	if (!last_adj) last_adj = current;
  
  	if (current - last_adj >= clk_tck) {
  		calls_per_tick = calls_since_adj / (current - last_adj);
  		calls_since_adj = 0;
  		calls_per_tick_known = 2;
  		last_adj = current;
  	} else if (calls_per_tick_known < 2) {
  		if (current > last_adj) {
  			calls_per_tick = calls_since_adj / (current - last_adj);
  			calls_per_tick_known = 1;
  		} else if (!calls_per_tick_known)
  			calls_per_tick++;
  	}
  
  	yield_calls = 0;
  	do {
  		if (event_pending) break;
  		last_check = current;
  		sched_yield();
  		yield_calls++;
  		current = times(&buf);
  	} while (current - last_check > 1 && current - last_adj < clk_tck);
  
  	if (yield_calls != 1)
  		calls_to_skip = 0;
  	calls_to_skip += calls_per_tick;
  
  	{
  		/* 1/16th of a second */
  		unsigned int max_calls_to_skip = calls_per_tick * clk_tck >> 4;
  		if (max_calls_to_skip < calls_per_tick)
  			max_calls_to_skip = calls_per_tick;
  		if (calls_to_skip > max_calls_to_skip)
  			calls_to_skip = max_calls_to_skip;
  	}
  #endif
  }
  