Moved fix_tmux_panes() into a background thread
This commit is contained in:
parent
4a04e92caf
commit
e40b0b98e4
2 changed files with 66 additions and 57 deletions
|
|
@ -6,6 +6,7 @@ import time
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functions.sensors import *
|
from functions.sensors import *
|
||||||
|
from functions.threading import *
|
||||||
from functions.tmux import *
|
from functions.tmux import *
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -79,9 +80,15 @@ TESTS_DISK = [
|
||||||
]
|
]
|
||||||
TOP_PANE_TEXT = '{GREEN}Hardware Diagnostics{CLEAR}'.format(**COLORS)
|
TOP_PANE_TEXT = '{GREEN}Hardware Diagnostics{CLEAR}'.format(**COLORS)
|
||||||
TMUX_LAYOUT = OrderedDict({
|
TMUX_LAYOUT = OrderedDict({
|
||||||
'Top': {'y': 2, 'Check': True},
|
'Top': {'y': 2, 'Check': True},
|
||||||
'Started': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
'Started': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
||||||
'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True},
|
||||||
|
# Testing panes
|
||||||
|
'Prime95': {'y': 11, 'Check': False},
|
||||||
|
'Temps': {'y': 1000, 'Check': False},
|
||||||
|
'SMART': {'y': 3, 'Check': True},
|
||||||
|
'badblocks': {'y': 5, 'Check': True},
|
||||||
|
'I/O Benchmark': {'y': 1000, 'Check': False},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -640,12 +647,25 @@ def build_status_string(label, status, info_label=False):
|
||||||
**COLORS)
|
**COLORS)
|
||||||
|
|
||||||
|
|
||||||
def fix_tmux_panes(state, tmux_layout):
|
def fix_tmux_panes_loop(state):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
fix_tmux_panes(state)
|
||||||
|
sleep(1)
|
||||||
|
except AttributeError:
|
||||||
|
# tmux_layout attribute has been deleted, exit function
|
||||||
|
return
|
||||||
|
except RuntimeError:
|
||||||
|
# Assuming layout definitions changes mid-run, ignoring
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def fix_tmux_panes(state):
|
||||||
"""Fix pane sizes if the window has been resized."""
|
"""Fix pane sizes if the window has been resized."""
|
||||||
needs_fixed = False
|
needs_fixed = False
|
||||||
|
|
||||||
# Check layout
|
# Check layout
|
||||||
for k, v in tmux_layout.items():
|
for k, v in state.tmux_layout.items():
|
||||||
if not v.get('Check'):
|
if not v.get('Check'):
|
||||||
# Not concerned with the size of this pane
|
# Not concerned with the size of this pane
|
||||||
continue
|
continue
|
||||||
|
|
@ -670,7 +690,7 @@ def fix_tmux_panes(state, tmux_layout):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Update layout
|
# Update layout
|
||||||
for k, v in tmux_layout.items():
|
for k, v in state.tmux_layout.items():
|
||||||
# Get target
|
# Get target
|
||||||
target = None
|
target = None
|
||||||
if k != 'Current':
|
if k != 'Current':
|
||||||
|
|
@ -886,10 +906,6 @@ def run_badblocks_test(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'badblocks': {'y': 5, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Create monitor pane
|
# Create monitor pane
|
||||||
test.badblocks_out = '{}/badblocks_{}.out'.format(
|
test.badblocks_out = '{}/badblocks_{}.out'.format(
|
||||||
|
|
@ -908,14 +924,7 @@ def run_badblocks_test(state, test):
|
||||||
test.badblocks_proc = popen_program(
|
test.badblocks_proc = popen_program(
|
||||||
['sudo', 'hw-diags-badblocks', test.dev.path, test.badblocks_out],
|
['sudo', 'hw-diags-badblocks', test.dev.path, test.badblocks_out],
|
||||||
pipe=True)
|
pipe=True)
|
||||||
while True:
|
test.badblocks_proc.wait()
|
||||||
try:
|
|
||||||
test.badblocks_proc.wait(timeout=1)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
else:
|
|
||||||
# badblocks finished, exit loop
|
|
||||||
break
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
test.aborted = True
|
test.aborted = True
|
||||||
|
|
@ -960,7 +969,7 @@ def run_badblocks_test(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['badblocks'])
|
tmux_kill_pane(state.panes.pop('badblocks', None))
|
||||||
|
|
||||||
|
|
||||||
def run_hw_tests(state):
|
def run_hw_tests(state):
|
||||||
|
|
@ -971,6 +980,7 @@ def run_hw_tests(state):
|
||||||
# Build Panes
|
# Build Panes
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
build_outer_panes(state)
|
build_outer_panes(state)
|
||||||
|
start_tmux_repair_thread(state)
|
||||||
|
|
||||||
# Show selected tests and create TestObj()s
|
# Show selected tests and create TestObj()s
|
||||||
print_info('Selected Tests:')
|
print_info('Selected Tests:')
|
||||||
|
|
@ -1018,11 +1028,13 @@ def run_hw_tests(state):
|
||||||
v['Objects'][-1].update_status('N/A')
|
v['Objects'][-1].update_status('N/A')
|
||||||
except GenericAbort:
|
except GenericAbort:
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
stop_tmux_repair_thread(state)
|
||||||
tmux_kill_pane(*state.panes.values())
|
tmux_kill_pane(*state.panes.values())
|
||||||
|
|
||||||
# Rebuild panes
|
# Rebuild panes
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
build_outer_panes(state)
|
build_outer_panes(state)
|
||||||
|
start_tmux_repair_thread(state)
|
||||||
|
|
||||||
# Mark unfinished tests as aborted
|
# Mark unfinished tests as aborted
|
||||||
for k, v in state.tests.items():
|
for k, v in state.tests.items():
|
||||||
|
|
@ -1036,12 +1048,14 @@ def run_hw_tests(state):
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
show_results(state)
|
show_results(state)
|
||||||
|
sleep(1)
|
||||||
if state.quick_mode:
|
if state.quick_mode:
|
||||||
pause('Press Enter to exit...')
|
pause('Press Enter to exit... ')
|
||||||
else:
|
else:
|
||||||
pause('Press Enter to return to main menu... ')
|
pause('Press Enter to return to main menu... ')
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
stop_tmux_repair_thread(state)
|
||||||
tmux_kill_pane(*state.panes.values())
|
tmux_kill_pane(*state.panes.values())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1062,11 +1076,7 @@ def run_io_benchmark(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
state.tmux_layout['Current'] = {'y': 15, 'Check': True}
|
||||||
test.tmux_layout.update({
|
|
||||||
'io_benchmark': {'y': 1000, 'Check': False},
|
|
||||||
'Current': {'y': 15, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Create monitor pane
|
# Create monitor pane
|
||||||
test.io_benchmark_out = '{}/io_benchmark_{}.out'.format(
|
test.io_benchmark_out = '{}/io_benchmark_{}.out'.format(
|
||||||
|
|
@ -1123,9 +1133,6 @@ def run_io_benchmark(state, test):
|
||||||
# Update offset
|
# Update offset
|
||||||
offset += test.dev.dd_chunk_blocks + skip
|
offset += test.dev.dd_chunk_blocks + skip
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
except DeviceTooSmallError:
|
except DeviceTooSmallError:
|
||||||
# Device too small, skipping test
|
# Device too small, skipping test
|
||||||
test.update_status('N/A')
|
test.update_status('N/A')
|
||||||
|
|
@ -1200,7 +1207,8 @@ def run_io_benchmark(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['io_benchmark'])
|
state.tmux_layout.pop('Current', None)
|
||||||
|
tmux_kill_pane(state.panes.pop('io_benchmark', None))
|
||||||
|
|
||||||
|
|
||||||
def run_keyboard_test():
|
def run_keyboard_test():
|
||||||
|
|
@ -1226,12 +1234,6 @@ def run_mprime_test(state, test):
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(TOP_PANE_TEXT, test.dev.name))
|
text='{}\n{}'.format(TOP_PANE_TEXT, test.dev.name))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'Temps': {'y': 1000, 'Check': False},
|
|
||||||
'mprime': {'y': 11, 'Check': False},
|
|
||||||
'Current': {'y': 3, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# Start live sensor monitor
|
# Start live sensor monitor
|
||||||
test.sensors_out = '{}/sensors.out'.format(global_vars['TmpDir'])
|
test.sensors_out = '{}/sensors.out'.format(global_vars['TmpDir'])
|
||||||
|
|
@ -1244,11 +1246,12 @@ def run_mprime_test(state, test):
|
||||||
pipe=True)
|
pipe=True)
|
||||||
|
|
||||||
# Create monitor and worker panes
|
# Create monitor and worker panes
|
||||||
state.panes['mprime'] = tmux_split_window(
|
state.panes['Prime95'] = tmux_split_window(
|
||||||
lines=10, vertical=True, text=' ')
|
lines=10, vertical=True, text=' ')
|
||||||
state.panes['Temps'] = tmux_split_window(
|
state.panes['Temps'] = tmux_split_window(
|
||||||
behind=True, percent=80, vertical=True, watch=test.sensors_out)
|
behind=True, percent=80, vertical=True, watch=test.sensors_out)
|
||||||
tmux_resize_pane(global_vars['Env']['TMUX_PANE'], y=3)
|
tmux_resize_pane(global_vars['Env']['TMUX_PANE'], y=3)
|
||||||
|
state.tmux_layout['Current'] = {'y': 3, 'Check': True}
|
||||||
|
|
||||||
# Get idle temps
|
# Get idle temps
|
||||||
clear_screen()
|
clear_screen()
|
||||||
|
|
@ -1263,7 +1266,7 @@ def run_mprime_test(state, test):
|
||||||
test.abort_msg = 'If running too hot, press CTRL+c to abort the test'
|
test.abort_msg = 'If running too hot, press CTRL+c to abort the test'
|
||||||
run_program(['apple-fans', 'max'])
|
run_program(['apple-fans', 'max'])
|
||||||
tmux_update_pane(
|
tmux_update_pane(
|
||||||
state.panes['mprime'],
|
state.panes['Prime95'],
|
||||||
command=['hw-diags-prime95', global_vars['TmpDir']],
|
command=['hw-diags-prime95', global_vars['TmpDir']],
|
||||||
working_dir=global_vars['TmpDir'])
|
working_dir=global_vars['TmpDir'])
|
||||||
time_limit = int(MPRIME_LIMIT) * 60
|
time_limit = int(MPRIME_LIMIT) * 60
|
||||||
|
|
@ -1285,9 +1288,6 @@ def run_mprime_test(state, test):
|
||||||
print('{YELLOW}{msg}{CLEAR}'.format(msg=test.abort_msg, **COLORS))
|
print('{YELLOW}{msg}{CLEAR}'.format(msg=test.abort_msg, **COLORS))
|
||||||
update_sensor_data(test.sensor_data)
|
update_sensor_data(test.sensor_data)
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
# Wait
|
# Wait
|
||||||
sleep(1)
|
sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
@ -1305,7 +1305,7 @@ def run_mprime_test(state, test):
|
||||||
# Stop Prime95 (twice for good measure)
|
# Stop Prime95 (twice for good measure)
|
||||||
run_program(['killall', '-s', 'INT', 'mprime'], check=False)
|
run_program(['killall', '-s', 'INT', 'mprime'], check=False)
|
||||||
sleep(1)
|
sleep(1)
|
||||||
tmux_kill_pane(state.panes['mprime'])
|
tmux_kill_pane(state.panes.pop('Prime95', None))
|
||||||
|
|
||||||
# Get cooldown temp
|
# Get cooldown temp
|
||||||
run_program(['apple-fans', 'auto'])
|
run_program(['apple-fans', 'auto'])
|
||||||
|
|
@ -1399,7 +1399,11 @@ def run_mprime_test(state, test):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['mprime'], state.panes['Temps'])
|
state.tmux_layout.pop('Current', None)
|
||||||
|
tmux_kill_pane(
|
||||||
|
state.panes.pop('Prime95', None),
|
||||||
|
state.panes.pop('Temps', None),
|
||||||
|
)
|
||||||
test.monitor_proc.kill()
|
test.monitor_proc.kill()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1428,10 +1432,6 @@ def run_nvme_smart_tests(state, test):
|
||||||
state.panes['Top'],
|
state.panes['Top'],
|
||||||
text='{}\n{}'.format(
|
text='{}\n{}'.format(
|
||||||
TOP_PANE_TEXT, test.dev.description))
|
TOP_PANE_TEXT, test.dev.description))
|
||||||
test.tmux_layout = TMUX_LAYOUT.copy()
|
|
||||||
test.tmux_layout.update({
|
|
||||||
'smart': {'y': 3, 'Check': True},
|
|
||||||
})
|
|
||||||
|
|
||||||
# NVMe
|
# NVMe
|
||||||
if test.dev.nvme_attributes:
|
if test.dev.nvme_attributes:
|
||||||
|
|
@ -1471,7 +1471,7 @@ def run_nvme_smart_tests(state, test):
|
||||||
global_vars['LogDir'], test.dev.name)
|
global_vars['LogDir'], test.dev.name)
|
||||||
with open(test.smart_out, 'w') as f:
|
with open(test.smart_out, 'w') as f:
|
||||||
f.write('SMART self-test status:\n Starting...')
|
f.write('SMART self-test status:\n Starting...')
|
||||||
state.panes['smart'] = tmux_split_window(
|
state.panes['SMART'] = tmux_split_window(
|
||||||
lines=3, vertical=True, watch=test.smart_out)
|
lines=3, vertical=True, watch=test.smart_out)
|
||||||
|
|
||||||
# Show attributes
|
# Show attributes
|
||||||
|
|
@ -1486,15 +1486,8 @@ def run_nvme_smart_tests(state, test):
|
||||||
|
|
||||||
# Monitor progress
|
# Monitor progress
|
||||||
try:
|
try:
|
||||||
for i in range(int(test.timeout*60)):
|
for i in range(int(test.timeout*60/5)):
|
||||||
sleep(1)
|
sleep(5)
|
||||||
|
|
||||||
# Fix panes
|
|
||||||
fix_tmux_panes(state, test.tmux_layout)
|
|
||||||
|
|
||||||
# Only update SMART progress every 5 seconds
|
|
||||||
if i % 5 != 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Update SMART data
|
# Update SMART data
|
||||||
test.dev.get_smart_details()
|
test.dev.get_smart_details()
|
||||||
|
|
@ -1544,7 +1537,7 @@ def run_nvme_smart_tests(state, test):
|
||||||
test.dev.disable_test(t, 'Denied')
|
test.dev.disable_test(t, 'Denied')
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
tmux_kill_pane(state.panes['smart'])
|
tmux_kill_pane(state.panes.pop('SMART', None))
|
||||||
|
|
||||||
# Save report
|
# Save report
|
||||||
test.report = test.dev.generate_attribute_report(
|
test.report = test.dev.generate_attribute_report(
|
||||||
|
|
@ -1607,6 +1600,19 @@ def show_results(state):
|
||||||
update_progress_pane(state)
|
update_progress_pane(state)
|
||||||
|
|
||||||
|
|
||||||
|
def start_tmux_repair_thread(state):
|
||||||
|
"""Fix tmux panes as long as state.tmux_layout attribute exists."""
|
||||||
|
state.tmux_layout = TMUX_LAYOUT.copy()
|
||||||
|
start_thread(fix_tmux_panes_loop, args=[state])
|
||||||
|
|
||||||
|
|
||||||
|
def stop_tmux_repair_thread(state):
|
||||||
|
"""Stop previous thread by causing an AttributeError in the thread."""
|
||||||
|
if hasattr(state, 'tmux_layout'):
|
||||||
|
del state.tmux_layout
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def update_main_options(state, selection, main_options):
|
def update_main_options(state, selection, main_options):
|
||||||
"""Update menu and state based on selection."""
|
"""Update menu and state based on selection."""
|
||||||
index = int(selection) - 1
|
index = int(selection) - 1
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ def tmux_kill_pane(*panes):
|
||||||
"""Kill tmux pane by id."""
|
"""Kill tmux pane by id."""
|
||||||
cmd = ['tmux', 'kill-pane', '-t']
|
cmd = ['tmux', 'kill-pane', '-t']
|
||||||
for pane_id in panes:
|
for pane_id in panes:
|
||||||
|
if not pane_id:
|
||||||
|
# Skip empty strings, None values, etc
|
||||||
|
continue
|
||||||
run_program(cmd+[pane_id], check=False)
|
run_program(cmd+[pane_id], check=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue