-
Notifications
You must be signed in to change notification settings - Fork 492
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
NAS-133058 / 25.04 / simplify service.terminate_process #15194
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
45c55ed
remove unused import
yocalebo 4c5e4fe
simplify service.terminate_process
yocalebo b210fce
add terminate_pid helper function
yocalebo 73327ae
call terminate_pid in service.terminate_process
yocalebo 596a97a
add unit test
yocalebo 2f7cea2
fix tests
yocalebo 02e1bba
make signal handle a fixture
yocalebo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
import psutil | ||
import time | ||
|
||
from middlewared.event import EventSource | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,53 @@ | ||
import logging | ||
import os | ||
import resource | ||
from os import closerange, kill | ||
from resource import getrlimit, RLIMIT_NOFILE, RLIM_INFINITY | ||
from signal import SIGKILL, SIGTERM | ||
from time import sleep, time | ||
|
||
logger = logging.getLogger(__name__) | ||
__all__ = ['close_fds', 'terminate_pid'] | ||
|
||
__all__ = ['close_fds'] | ||
ALIVE_SIGNAL = 0 | ||
|
||
|
||
def close_fds(low_fd, max_fd=None): | ||
if max_fd is None: | ||
max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] | ||
# Avoid infinity as thats not practical | ||
if max_fd == resource.RLIM_INFINITY: | ||
max_fd = getrlimit(RLIMIT_NOFILE)[1] | ||
if max_fd == RLIM_INFINITY: | ||
# Avoid infinity as thats not practical | ||
max_fd = 8192 | ||
|
||
os.closerange(low_fd, max_fd) | ||
closerange(low_fd, max_fd) | ||
|
||
|
||
def terminate_pid(pid: int, timeout: int = 10) -> bool: | ||
# Send SIGTERM to request the process to terminate | ||
kill(pid, SIGTERM) | ||
|
||
try: | ||
kill(pid, ALIVE_SIGNAL) | ||
except ProcessLookupError: | ||
# SIGTERM was honored | ||
return True | ||
|
||
# process still alive (could take awhile) | ||
start_time = time() | ||
while True: | ||
try: | ||
kill(pid, ALIVE_SIGNAL) | ||
except ProcessLookupError: | ||
# SIGTERM was honored (eventually) | ||
return True | ||
|
||
if time() - start_time >= timeout: | ||
# Timeout reached; break out of the loop to send SIGKILL | ||
break | ||
|
||
# Wait a bit before checking again | ||
sleep(0.1) | ||
|
||
try: | ||
# Send SIGKILL to forcefully terminate the process | ||
kill(pid, SIGKILL) | ||
return False | ||
except ProcessLookupError: | ||
# Process may have terminated between checks | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from os import kill | ||
from signal import signal, SIGCHLD, SIG_IGN | ||
from subprocess import Popen | ||
from textwrap import dedent | ||
from time import sleep | ||
|
||
import pytest | ||
|
||
from middlewared.utils.os import terminate_pid | ||
|
||
|
||
@pytest.fixture(scope="module", autouse=True) | ||
def signal_handler(): | ||
# ignore SIGCHLD so child process is removed | ||
# from process table immediately without parent | ||
# process having to do any (formal) clean-up | ||
orig = signal(SIGCHLD, SIG_IGN) | ||
yield | ||
signal(SIGCHLD, orig) | ||
|
||
|
||
def test_sigterm(): | ||
p = Popen(['python', '-c', 'import time; time.sleep(60)']) | ||
# Allow process to start | ||
sleep(0.2) | ||
|
||
# Call terminate_pid with timeout | ||
terminate_pid(p.pid, timeout=5) | ||
# Wait a bit to ensure process has time to terminate | ||
sleep(0.5) | ||
|
||
# Check if process has terminated | ||
try: | ||
kill(p.pid, 0) | ||
assert False, f"{p.pid!r} still running" | ||
except ProcessLookupError: | ||
# Process has terminated | ||
pass | ||
|
||
|
||
def test_sigkill(): | ||
script = dedent(""" | ||
import signal | ||
import os | ||
signal.signal(signal.SIGTERM, signal.SIG_IGN) | ||
max_sleep = 60 | ||
slept_time = 0 | ||
while slept_time < max_sleep: | ||
time.sleep(1) | ||
slept_time += 1 | ||
""") | ||
p = Popen(['python', '-c', script]) | ||
|
||
# Call terminate_pid with short timeout | ||
terminate_pid(p.pid, timeout=1) | ||
# Wait a bit to ensure process has time to terminate | ||
sleep(0.5) | ||
|
||
# Check if process has terminated | ||
try: | ||
kill(p.pid, 0) | ||
assert False, f"{p.pid!r} still running" | ||
except ProcessLookupError: | ||
# Process has terminated | ||
pass |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Looking at
kill(2)
man page I wonder whether we should also eliminate all negative values ofpid
.