Add portable wrapper for POSIX kill(2)#2331
Add portable wrapper for POSIX kill(2)#2331kinkie wants to merge 6 commits intosquid-cache:masterfrom
Conversation
| #if !(_SQUID_WINDOWS_ || _SQUID_MINGW_) | ||
|
|
||
| inline int xkill(pid_t pid, int sig) | ||
| { | ||
| return kill(pid, sig); | ||
| } | ||
|
|
||
| inline bool | ||
| IsPidValid(pid_t pid) | ||
| { | ||
| return kill(pid, 0) == 0; | ||
| } | ||
|
|
||
| #endif /* !(_SQUID_WINDOWS_ || _SQUID_MINGW_) */ |
There was a problem hiding this comment.
| #if !(_SQUID_WINDOWS_ || _SQUID_MINGW_) | |
| inline int xkill(pid_t pid, int sig) | |
| { | |
| return kill(pid, sig); | |
| } | |
| inline bool | |
| IsPidValid(pid_t pid) | |
| { | |
| return kill(pid, 0) == 0; | |
| } | |
| #endif /* !(_SQUID_WINDOWS_ || _SQUID_MINGW_) */ | |
| /// POSIX kill(2) equivalent | |
| int xkill(pid_t, int); | |
| #if _SQUID_WINDOWS_ || _SQUID_MINGW_ | |
| inline int xkill(pid_t pid, int sig) { return kill(pid, sig); } | |
| #endif |
| /// true if pid can be sent a signal (no signal is sent) | ||
| inline bool | ||
| IsPidValid(pid_t pid); | ||
|
|
There was a problem hiding this comment.
This is not part of the POSIX API. We should be using that API instead of local wrappers.
| /// true if pid can be sent a signal (no signal is sent) | |
| inline bool | |
| IsPidValid(pid_t pid); |
There was a problem hiding this comment.
I agree that compat/signal.h should not provide IsPidValid() API.
Instead, xkill() implementation for Windows may (and probably should!) use a static helper function, hopefully with a more revealing name, to implement xkill(signal=0) support).
Old higher-level code should continue to use ProcessIsRunning() and raw xkill(signal=0) calls.
| static bool | ||
| ProcessIsRunning(const pid_t pid) | ||
| { | ||
| const auto result = kill(pid, 0); |
There was a problem hiding this comment.
Please continue to use the POSIX API equivalent call.
const auto result = xkill(pid, 0);
| } | ||
|
|
||
| /// true if the given pid is the current process, false otherwise | ||
| bool |
There was a problem hiding this comment.
When the caller is restored to using xkill(pid, 0) to check for validity this can be made static
| bool | |
| static bool |
| xkill(pid_t pid, int sig) | ||
| { | ||
| auto hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); | ||
|
|
| char MyProcessName[MAX_PATH]; | ||
| GetProcessName(getpid(), MyProcessName); | ||
| char ProcessNameToCheck[MAX_PATH]; |
There was a problem hiding this comment.
MAX_PATH is not always a small value. Please allocate these dynamically.
| switch (sig) { | ||
| // Windows does not support sending generic POSIX signals. | ||
| // TODO: implement a signal sending and handling mechanism | ||
| // using Windows messages | ||
| case SIGKILL: | ||
| if (TerminateProcess(hProcess, 0)) { | ||
| CloseHandle(hProcess); | ||
| return 0; | ||
| } | ||
| break; | ||
| case 0: | ||
| CloseHandle(hProcess); | ||
| if (IsPidValid(pid)) | ||
| return 0; | ||
| return -1; | ||
| break; | ||
| default: | ||
| // Unsupported signal | ||
| CloseHandle(hProcess); | ||
| } | ||
|
|
||
| return -1; |
There was a problem hiding this comment.
The break; case for SIGKILL handling leaves the process handle hanging.
This whole section would be better implemented such that the handle is always closed at a single point of return.
| switch (sig) { | |
| // Windows does not support sending generic POSIX signals. | |
| // TODO: implement a signal sending and handling mechanism | |
| // using Windows messages | |
| case SIGKILL: | |
| if (TerminateProcess(hProcess, 0)) { | |
| CloseHandle(hProcess); | |
| return 0; | |
| } | |
| break; | |
| case 0: | |
| CloseHandle(hProcess); | |
| if (IsPidValid(pid)) | |
| return 0; | |
| return -1; | |
| break; | |
| default: | |
| // Unsupported signal | |
| CloseHandle(hProcess); | |
| } | |
| return -1; | |
| // Windows does not support sending generic POSIX signals. | |
| // TODO: implement a signal sending and handling mechanism | |
| // using Windows messages | |
| bool result = false; | |
| switch (sig) { | |
| case SIGKILL: | |
| result = TerminateProcess(hProcess, 0); | |
| break; | |
| case 0: | |
| result = IsPidValid(pid); | |
| break; | |
| default: | |
| // Unsupported signal | |
| } | |
| CloseHandle(hProcess); | |
| return (result ? 0 : -1); |
| #ifndef SQUID_COMPAT_SIGNAL_H | ||
| #define SQUID_COMPAT_SIGNAL_H | ||
|
|
||
| #if !defined(SIGHUP) |
There was a problem hiding this comment.
Please add a reference for where these values come from.
| #if !defined(SIGHUP) | |
| // Signal definitions from POSIX API. see https://www.man7.org/linux/man-pages/man7/signal.7.html | |
| // TODO: use x86 or arch-specific defines instead of these SPARC CPU values. | |
| #if !defined(SIGHUP) |
| #if !defined(WIFEXITED) | ||
| inline int | ||
| WIFEXITED(int status) { | ||
| return (status & 0x7f) == 0; | ||
| } | ||
| #endif | ||
|
|
||
| #if !defined(WEXITSTATUS) | ||
| inline int | ||
| WEXITSTATUS(int status) { | ||
| return (status & 0xff00) >> 8; | ||
| } | ||
| #endif | ||
|
|
||
| #if !defined(WIFSIGNALED) | ||
| inline int | ||
| WIFSIGNALED(int status) { | ||
| return (status & 0x7f) != 0; | ||
| } | ||
| #endif | ||
|
|
||
| #if !defined(WTERMSIG) | ||
| inline int | ||
| WTERMSIG(int status) { | ||
| return (status & 0x7f); | ||
| } | ||
| #endif |
There was a problem hiding this comment.
All these W...() definitions are part of the POSIX sys/wait.h header. Not part of signal.h.
Please remove.
|
FYI, reference fro what symbols should be in each POSIX header file can be found at https://pubs.opengroup.org/onlinepubs/9799919799/ |
remove redundant code Co-authored-by: Amos Jeffries <yadij@users.noreply.github.com>
rousskov
left a comment
There was a problem hiding this comment.
This is not a comprehensive review, but it may help you remove quite a bit of noise/distractions from this draft PR.
| /// true if pid can be sent a signal (no signal is sent) | ||
| inline bool | ||
| IsPidValid(pid_t pid); | ||
|
|
There was a problem hiding this comment.
I agree that compat/signal.h should not provide IsPidValid() API.
Instead, xkill() implementation for Windows may (and probably should!) use a static helper function, hopefully with a more revealing name, to implement xkill(signal=0) support).
Old higher-level code should continue to use ProcessIsRunning() and raw xkill(signal=0) calls.
| GetProcessName(getpid(), MyProcessName); | ||
| char ProcessNameToCheck[MAX_PATH]; | ||
| GetProcessName(pid, ProcessNameToCheck); | ||
| if (strcmp(MyProcessName, ProcessNameToCheck) == 0) |
There was a problem hiding this comment.
It is not clear to me why IsPidValid(getpid()) should return false. It is usually possible to send a signal to oneself, right? Please either refactor or add a C++ comment to explain why we need to compare getpid() process name with ours.
N.B. I am aware that existing Windows code has similar logic.
P.S. I am writing this change request while assuming that this or similar function is going to be preserved despite the requested removal of "public" IsPidValid() API.
| static void | ||
| GetProcessName(pid_t pid, char *ProcessName) | ||
| { | ||
| strcpy(ProcessName, "unknown"); |
There was a problem hiding this comment.
If this code survives, please return a nil name instead of using a special value to mean "we do not know what the process name is [because some system calls have failed]" (that callers do not know about!).
N.B. I am aware that official code uses this hack.
|
I adjusted PR title to highlight that PR changes are going to affect all Please note that PR description talks about |
Windows does not really offer kill() and signal(), only limited wrappers.
Refactor emulation code, rename kill() to xkill() to highlight it's a wrapper