-
Notifications
You must be signed in to change notification settings - Fork 851
thread_config test - add visibility and some defensive improvements.
#12916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,26 +20,45 @@ | |||||||
| import psutil | ||||||||
| import argparse | ||||||||
| import sys | ||||||||
| import time | ||||||||
|
|
||||||||
|
|
||||||||
| def count_threads(ts_path, etnet_threads, accept_threads, task_threads, aio_threads): | ||||||||
|
|
||||||||
| for p in psutil.process_iter(['name', 'cwd', 'threads']): | ||||||||
|
|
||||||||
| # Use cached info from process_iter attrs to avoid race conditions | ||||||||
| # where the process exits between iteration and inspection. | ||||||||
| try: | ||||||||
| proc_name = p.info.get('name', '') | ||||||||
| proc_cwd = p.info.get('cwd', '') | ||||||||
| except (psutil.NoSuchProcess, psutil.AccessDenied): | ||||||||
| continue | ||||||||
|
|
||||||||
| # Find the pid corresponding to the ats process we started in autest. | ||||||||
| # It needs to match the process name and the binary path. | ||||||||
| # If autest can expose the pid of the process this is not needed anymore. | ||||||||
| if p.name() == '[TS_MAIN]' and p.cwd() == ts_path: | ||||||||
| if proc_name == '[TS_MAIN]' and proc_cwd == ts_path: | ||||||||
|
|
||||||||
| etnet_check = set() | ||||||||
| accept_check = set() | ||||||||
| task_check = set() | ||||||||
| aio_check = set() | ||||||||
|
|
||||||||
| for t in p.threads(): | ||||||||
| try: | ||||||||
| threads = p.threads() | ||||||||
| except (psutil.NoSuchProcess, psutil.AccessDenied): | ||||||||
| sys.stderr.write(f'Process {p.pid} disappeared while reading threads.\n') | ||||||||
| return 1 | ||||||||
|
||||||||
| return 1 | |
| return 12 |
Copilot
AI
Mar 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a thread exits between p.threads() and the per-thread psutil.Process(t.id).name() call, the thread is silently skipped via continue at line 61. This means that thread is not added to the relevant check set (e.g., etnet_check, task_check). When the final size checks run (lines 110–121), the set will have fewer entries than expected, triggering a "wrong count" error with exit codes 4, 6, 9, or 11.
The retry logic in main() only retries on exit code 1 ("process not found"). Exit codes 4, 6, 9, or 11 are treated as definitive failures and not retried. This creates a scenario where a transient TOCTOU race causes a non-retried definitive failure, which is worse than the original behavior.
One option is to also retry on these exit codes, or alternatively, to count the number of skipped threads and fall back to exit code 1 (to trigger a retry) if any threads were skipped.
| continue | |
| sys.stderr.write(f'Thread {t.id} disappeared while reading name.\n') | |
| return 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
try/except (psutil.NoSuchProcess, psutil.AccessDenied)block wrappingp.info.get()at lines 32–36 is incorrect.p.infois an ordinary Python dict; calling.get()on it never raises psutil exceptions. Whenprocess_itercan't fetch an attribute (e.g.,cwdis denied), it stores the exception object as the dict value rather than raising it. As a result:exceptclause never fires, giving a false sense of protection.proc_cwdmay silently be an exception object instead of a string, which causes the== ts_pathcomparison to silently fail — harmless but misleading.The correct approach here is to check whether the value stored in
p.infois an exception instance before using it, e.g.,proc_cwd = p.info.get('cwd', '') if not isinstance(p.info.get('cwd'), Exception) else ''. Alternatively, for modern psutil versions (≥6), attribute errors are represented differently, so consult the psutil docs for the version in use. Thetry/exceptblock can simply be removed since it provides no protection.