This commit is contained in:
Alexey Avramov 2019-02-15 20:39:51 +09:00
parent c208f9c940
commit 3b5eafdaeb
2 changed files with 74 additions and 66 deletions

138
nohang
View File

@ -29,21 +29,21 @@ if len(argv) == 1:
elif len(argv) == 2: elif len(argv) == 2:
if argv[1] == '--help' or argv[1] == '-h': if argv[1] == '--help' or argv[1] == '-h':
print(help_mess) errprint(help_mess)
exit(1) exit(1)
else: else:
print('Invalid CLI input') errprint('Invalid CLI input')
exit(1) exit(1)
elif len(argv) > 3: elif len(argv) > 3:
print('Invalid CLI input') errprint('Invalid CLI input')
exit(1) exit(1)
else: else:
if argv[1] == '--config' or argv[1] == '-c': if argv[1] == '--config' or argv[1] == '-c':
config = argv[2] config = argv[2]
else: else:
print('Invalid option: {}'.format(argv[1])) errprint('Invalid option: {}'.format(argv[1]))
exit(1) exit(1)
@ -89,6 +89,10 @@ debug = False
# define functions # define functions
def errprint(text):
print(text, file=stderr, flush=True)
def mlockall(): def mlockall():
MCL_CURRENT = 1 MCL_CURRENT = 1
@ -236,8 +240,8 @@ def conf_parse_string(param):
if param in config_dict: if param in config_dict:
return config_dict[param].strip() return config_dict[param].strip()
else: else:
print('All the necessary parameters must be in the config') errprint('All the necessary parameters must be in the config')
print('There is no "{}" parameter in the config'.format(param)) errprint('There is no "{}" parameter in the config'.format(param))
exit(1) exit(1)
@ -255,13 +259,13 @@ def conf_parse_bool(param):
elif param_str == 'False': elif param_str == 'False':
return False return False
else: else:
print('Invalid value of the "{}" parameter.'.format(param)) errprint('Invalid value of the "{}" parameter.'.format(param))
print('Valid values are True and False.') errprint('Valid values are True and False.')
print('Exit') errprint('Exit')
exit(1) exit(1)
else: else:
print('All the necessary parameters must be in the config') errprint('All the necessary parameters must be in the config')
print('There is no "{}" parameter in the config'.format(param)) errprint('There is no "{}" parameter in the config'.format(param))
exit(1) exit(1)
@ -795,7 +799,11 @@ def find_victim_and_send_signal(signal):
try: try:
realpath = os.path.realpath('/proc/' + pid + '/exe') realpath = os.path.realpath('/proc/' + pid + '/exe')
except FileNotFoundError: except FileNotFoundError:
print('Victim died: /proc/{}/exe does not exists'.format(pid)) print(mem_info)
print('The victim died in the search process: FileNotFoundError')
update_stat_dict_and_print(
'The victim died in the search process: FileNotFoundError')
return None
#state = pid_to_state(pid) #state = pid_to_state(pid)
@ -982,7 +990,7 @@ def sleep_after_check_mem():
t_mem = mem_point / rate_mem t_mem = mem_point / rate_mem
t_swap = swap_point / rate_swap t_swap = swap_point / rate_swap
t_zram = (mem_total * 0.9 - mem_used_zram) / rate_zram t_zram = (mem_total * 0.8 - mem_used_zram) / rate_zram
if t_zram < 0: if t_zram < 0:
t_zram = 0 t_zram = 0
@ -1039,11 +1047,11 @@ def calculate_percent(arg_key):
# then 'float test' # then 'float test'
mem_min_percent = string_to_float_convert_test(mem_min_percent) mem_min_percent = string_to_float_convert_test(mem_min_percent)
if mem_min_percent is None: if mem_min_percent is None:
print('Invalid {} value, not float\nExit'.format(arg_key)) errprint('Invalid {} value, not float\nExit'.format(arg_key))
exit(1) exit(1)
# Final validations... # Final validations...
if mem_min_percent < 0 or mem_min_percent > 100: if mem_min_percent < 0 or mem_min_percent > 100:
print( errprint(
'{}, as percents value, out of range [0; 100]\nExit'.format(arg_key)) '{}, as percents value, out of range [0; 100]\nExit'.format(arg_key))
exit(1) exit(1)
@ -1055,11 +1063,11 @@ def calculate_percent(arg_key):
elif mem_min.endswith('M'): elif mem_min.endswith('M'):
mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip()) mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip())
if mem_min_mb is None: if mem_min_mb is None:
print('Invalid {} value, not float\nExit'.format(arg_key)) errprint('Invalid {} value, not float\nExit'.format(arg_key))
exit(1) exit(1)
mem_min_kb = mem_min_mb * 1024 mem_min_kb = mem_min_mb * 1024
if mem_min_kb > mem_total: if mem_min_kb > mem_total:
print( errprint(
'{} value can not be greater then MemTotal ({} MiB)\nExit'.format( '{} value can not be greater then MemTotal ({} MiB)\nExit'.format(
arg_key, round( arg_key, round(
mem_total / 1024))) mem_total / 1024)))
@ -1099,7 +1107,7 @@ for s in mem_list:
mem_list_names.append(s.split(':')[0]) mem_list_names.append(s.split(':')[0])
if mem_list_names[2] != 'MemAvailable': if mem_list_names[2] != 'MemAvailable':
print('Your Linux kernel is too old, Linux 3.14+ requied\nExit') errprint('Your Linux kernel is too old, Linux 3.14+ requied\nExit')
exit(1) exit(1)
swap_total_index = mem_list_names.index('SwapTotal') swap_total_index = mem_list_names.index('SwapTotal')
@ -1183,7 +1191,7 @@ try:
etc_name = a[0].strip() etc_name = a[0].strip()
etc_command = a[1].strip() etc_command = a[1].strip()
if len(etc_name) > 15: if len(etc_name) > 15:
print('Invalid config, the length of the process ' errprint('Invalid config, the length of the process '
'name must not exceed 15 characters\nExit') 'name must not exceed 15 characters\nExit')
exit(1) exit(1)
etc_dict[etc_name] = etc_command etc_dict[etc_name] = etc_command
@ -1204,19 +1212,19 @@ try:
uid_re_list.append((a[0].strip(' '), a[2].strip(' '))) uid_re_list.append((a[0].strip(' '), a[2].strip(' ')))
except PermissionError: except PermissionError:
print('PermissionError', conf_err_mess) errprint('PermissionError', conf_err_mess)
exit(1) exit(1)
except UnicodeDecodeError: except UnicodeDecodeError:
print('UnicodeDecodeError', conf_err_mess) errprint('UnicodeDecodeError', conf_err_mess)
exit(1) exit(1)
except IsADirectoryError: except IsADirectoryError:
print('IsADirectoryError', conf_err_mess) errprint('IsADirectoryError', conf_err_mess)
exit(1) exit(1)
except IndexError: except IndexError:
print('IndexError', conf_err_mess) errprint('IndexError', conf_err_mess)
exit(1) exit(1)
except FileNotFoundError: except FileNotFoundError:
print('FileNotFoundError', conf_err_mess) errprint('FileNotFoundError', conf_err_mess)
exit(1) exit(1)
@ -1272,53 +1280,53 @@ zram_max_warnings_kb, zram_max_warnings_mb, zram_max_warnings_percent = calculat
if 'rate_mem' in config_dict: if 'rate_mem' in config_dict:
rate_mem = string_to_float_convert_test(config_dict['rate_mem']) rate_mem = string_to_float_convert_test(config_dict['rate_mem'])
if rate_mem is None: if rate_mem is None:
print('Invalid rate_mem value, not float\nExit') errprint('Invalid rate_mem value, not float\nExit')
exit(1) exit(1)
if rate_mem <= 0: if rate_mem <= 0:
print('rate_mem MUST be > 0\nExit') errprint('rate_mem MUST be > 0\nExit')
exit(1) exit(1)
else: else:
print('rate_mem not in config\nExit') errprint('rate_mem not in config\nExit')
exit(1) exit(1)
if 'rate_swap' in config_dict: if 'rate_swap' in config_dict:
rate_swap = string_to_float_convert_test(config_dict['rate_swap']) rate_swap = string_to_float_convert_test(config_dict['rate_swap'])
if rate_swap is None: if rate_swap is None:
print('Invalid rate_swap value, not float\nExit') errprint('Invalid rate_swap value, not float\nExit')
exit(1) exit(1)
if rate_swap <= 0: if rate_swap <= 0:
print('rate_swap MUST be > 0\nExit') errprint('rate_swap MUST be > 0\nExit')
exit(1) exit(1)
else: else:
print('rate_swap not in config\nExit') errprint('rate_swap not in config\nExit')
exit(1) exit(1)
if 'rate_zram' in config_dict: if 'rate_zram' in config_dict:
rate_zram = string_to_float_convert_test(config_dict['rate_zram']) rate_zram = string_to_float_convert_test(config_dict['rate_zram'])
if rate_zram is None: if rate_zram is None:
print('Invalid rate_zram value, not float\nExit') errprint('Invalid rate_zram value, not float\nExit')
exit(1) exit(1)
if rate_zram <= 0: if rate_zram <= 0:
print('rate_zram MUST be > 0\nExit') errprint('rate_zram MUST be > 0\nExit')
exit(1) exit(1)
else: else:
print('rate_zram not in config\nExit') errprint('rate_zram not in config\nExit')
exit(1) exit(1)
if 'swap_min_sigterm' in config_dict: if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm'] swap_min_sigterm = config_dict['swap_min_sigterm']
else: else:
print('swap_min_sigterm not in config\nExit') errprint('swap_min_sigterm not in config\nExit')
exit(1) exit(1)
if 'swap_min_sigkill' in config_dict: if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill'] swap_min_sigkill = config_dict['swap_min_sigkill']
else: else:
print('swap_min_sigkill not in config\nExit') errprint('swap_min_sigkill not in config\nExit')
exit(1) exit(1)
@ -1326,13 +1334,13 @@ if 'min_delay_after_sigterm' in config_dict:
min_delay_after_sigterm = string_to_float_convert_test( min_delay_after_sigterm = string_to_float_convert_test(
config_dict['min_delay_after_sigterm']) config_dict['min_delay_after_sigterm'])
if min_delay_after_sigterm is None: if min_delay_after_sigterm is None:
print('Invalid min_delay_after_sigterm value, not float\nExit') errprint('Invalid min_delay_after_sigterm value, not float\nExit')
exit(1) exit(1)
if min_delay_after_sigterm < 0: if min_delay_after_sigterm < 0:
print('min_delay_after_sigterm must be positiv\nExit') errprint('min_delay_after_sigterm must be positiv\nExit')
exit(1) exit(1)
else: else:
print('min_delay_after_sigterm not in config\nExit') errprint('min_delay_after_sigterm not in config\nExit')
exit(1) exit(1)
@ -1340,13 +1348,13 @@ if 'min_delay_after_sigkill' in config_dict:
min_delay_after_sigkill = string_to_float_convert_test( min_delay_after_sigkill = string_to_float_convert_test(
config_dict['min_delay_after_sigkill']) config_dict['min_delay_after_sigkill'])
if min_delay_after_sigkill is None: if min_delay_after_sigkill is None:
print('Invalid min_delay_after_sigkill value, not float\nExit') errprint('Invalid min_delay_after_sigkill value, not float\nExit')
exit(1) exit(1)
if min_delay_after_sigkill < 0: if min_delay_after_sigkill < 0:
print('min_delay_after_sigkill must be positive\nExit') errprint('min_delay_after_sigkill must be positive\nExit')
exit(1) exit(1)
else: else:
print('min_delay_after_sigkill not in config\nExit') errprint('min_delay_after_sigkill not in config\nExit')
exit(1) exit(1)
@ -1354,13 +1362,13 @@ if 'psi_avg10_sleep_time' in config_dict:
psi_avg10_sleep_time = string_to_float_convert_test( psi_avg10_sleep_time = string_to_float_convert_test(
config_dict['psi_avg10_sleep_time']) config_dict['psi_avg10_sleep_time'])
if psi_avg10_sleep_time is None: if psi_avg10_sleep_time is None:
print('Invalid psi_avg10_sleep_time value, not float\nExit') errprint('Invalid psi_avg10_sleep_time value, not float\nExit')
exit(1) exit(1)
if psi_avg10_sleep_time < 0: if psi_avg10_sleep_time < 0:
print('psi_avg10_sleep_time must be positive\nExit') errprint('psi_avg10_sleep_time must be positive\nExit')
exit(1) exit(1)
else: else:
print('psi_avg10_sleep_time not in config\nExit') errprint('psi_avg10_sleep_time not in config\nExit')
exit(1) exit(1)
@ -1368,13 +1376,13 @@ if 'sigkill_psi_avg10' in config_dict:
sigkill_psi_avg10 = string_to_float_convert_test( sigkill_psi_avg10 = string_to_float_convert_test(
config_dict['sigkill_psi_avg10']) config_dict['sigkill_psi_avg10'])
if sigkill_psi_avg10 is None: if sigkill_psi_avg10 is None:
print('Invalid sigkill_psi_avg10 value, not float\nExit') errprint('Invalid sigkill_psi_avg10 value, not float\nExit')
exit(1) exit(1)
if sigkill_psi_avg10 < 0 or sigkill_psi_avg10 > 100: if sigkill_psi_avg10 < 0 or sigkill_psi_avg10 > 100:
print('sigkill_psi_avg10 must be in the range [0; 100]\nExit') errprint('sigkill_psi_avg10 must be in the range [0; 100]\nExit')
exit(1) exit(1)
else: else:
print('sigkill_psi_avg10 not in config\nExit') errprint('sigkill_psi_avg10 not in config\nExit')
exit(1) exit(1)
@ -1382,13 +1390,13 @@ if 'sigterm_psi_avg10' in config_dict:
sigterm_psi_avg10 = string_to_float_convert_test( sigterm_psi_avg10 = string_to_float_convert_test(
config_dict['sigterm_psi_avg10']) config_dict['sigterm_psi_avg10'])
if sigterm_psi_avg10 is None: if sigterm_psi_avg10 is None:
print('Invalid sigterm_psi_avg10 value, not float\nExit') errprint('Invalid sigterm_psi_avg10 value, not float\nExit')
exit(1) exit(1)
if sigterm_psi_avg10 < 0 or sigterm_psi_avg10 > 100: if sigterm_psi_avg10 < 0 or sigterm_psi_avg10 > 100:
print('sigterm_psi_avg10 must be in the range [0; 100]\nExit') errprint('sigterm_psi_avg10 must be in the range [0; 100]\nExit')
exit(1) exit(1)
else: else:
print('sigterm_psi_avg10 not in config\nExit') errprint('sigterm_psi_avg10 not in config\nExit')
exit(1) exit(1)
@ -1396,13 +1404,13 @@ if 'min_badness' in config_dict:
min_badness = string_to_int_convert_test( min_badness = string_to_int_convert_test(
config_dict['min_badness']) config_dict['min_badness'])
if min_badness is None: if min_badness is None:
print('Invalid min_badness value, not integer\nExit') errprint('Invalid min_badness value, not integer\nExit')
exit(1) exit(1)
if min_badness < 0 or min_badness > 1000: if min_badness < 0 or min_badness > 1000:
print('Invalud min_badness value\nExit') errprint('Invalud min_badness value\nExit')
exit(1) exit(1)
else: else:
print('min_badness not in config\nExit') errprint('min_badness not in config\nExit')
exit(1) exit(1)
@ -1410,13 +1418,13 @@ if 'oom_score_adj_max' in config_dict:
oom_score_adj_max = string_to_int_convert_test( oom_score_adj_max = string_to_int_convert_test(
config_dict['oom_score_adj_max']) config_dict['oom_score_adj_max'])
if oom_score_adj_max is None: if oom_score_adj_max is None:
print('Invalid oom_score_adj_max value, not integer\nExit') errprint('Invalid oom_score_adj_max value, not integer\nExit')
exit(1) exit(1)
if oom_score_adj_max < 0 or oom_score_adj_max > 1000: if oom_score_adj_max < 0 or oom_score_adj_max > 1000:
print('Invalid oom_score_adj_max value\nExit') errprint('Invalid oom_score_adj_max value\nExit')
exit(1) exit(1)
else: else:
print('oom_score_adj_max not in config\nExit') errprint('oom_score_adj_max not in config\nExit')
exit(1) exit(1)
@ -1424,20 +1432,20 @@ if 'min_time_between_warnings' in config_dict:
min_time_between_warnings = string_to_float_convert_test( min_time_between_warnings = string_to_float_convert_test(
config_dict['min_time_between_warnings']) config_dict['min_time_between_warnings'])
if min_time_between_warnings is None: if min_time_between_warnings is None:
print('Invalid min_time_between_warnings value, not float\nExit') errprint('Invalid min_time_between_warnings value, not float\nExit')
exit(1) exit(1)
if min_time_between_warnings < 1 or min_time_between_warnings > 300: if min_time_between_warnings < 1 or min_time_between_warnings > 300:
print('min_time_between_warnings value out of range [1; 300]\nExit') errprint('min_time_between_warnings value out of range [1; 300]\nExit')
exit(1) exit(1)
else: else:
print('min_time_between_warnings not in config\nExit') errprint('min_time_between_warnings not in config\nExit')
exit(1) exit(1)
if 'swap_min_warnings' in config_dict: if 'swap_min_warnings' in config_dict:
swap_min_warnings = config_dict['swap_min_warnings'] swap_min_warnings = config_dict['swap_min_warnings']
else: else:
print('swap_min_warnings not in config\nExit') errprint('swap_min_warnings not in config\nExit')
exit(1) exit(1)
@ -1458,12 +1466,12 @@ def get_swap_threshold_tuple(string):
if string.endswith('%'): if string.endswith('%'):
valid = string_to_float_convert_test(string[:-1]) valid = string_to_float_convert_test(string[:-1])
if valid is None: if valid is None:
print('somewhere swap unit is not float_%') errprint('somewhere swap unit is not float_%')
exit(1) exit(1)
value = float(string[:-1].strip()) value = float(string[:-1].strip())
if value < 0 or value > 100: if value < 0 or value > 100:
print('invalid value, must be from the range[0; 100] %') errprint('invalid value, must be from the range[0; 100] %')
exit(1) exit(1)
return value, True return value, True
@ -1471,18 +1479,18 @@ def get_swap_threshold_tuple(string):
elif string.endswith('M'): elif string.endswith('M'):
valid = string_to_float_convert_test(string[:-1]) valid = string_to_float_convert_test(string[:-1])
if valid is None: if valid is None:
print('somewhere swap unit is not float_M') errprint('somewhere swap unit is not float_M')
exit(1) exit(1)
value = float(string[:-1].strip()) * 1024 value = float(string[:-1].strip()) * 1024
if value < 0: if value < 0:
print('invalid unit in config (negative value)') errprint('invalid unit in config (negative value)')
exit(1) exit(1)
return value, False return value, False
else: else:
print('Invalid config file. There are invalid units somewhere\nExit') errprint('Invalid config file. There are invalid units somewhere\nExit')
exit(1) exit(1)

View File

@ -95,7 +95,7 @@ psi_avg10_sleep_time = 60
rate_mem = 3 rate_mem = 3
rate_swap = 1.5 rate_swap = 1.5
rate_zram = 1 rate_zram = 0.5
See also https://github.com/rfjakob/earlyoom/issues/61 See also https://github.com/rfjakob/earlyoom/issues/61