#ifndef RBIMPL_INTERN_SIGNAL_H /*-*-C++-*-vi:se ft=cpp:*/ #define RBIMPL_INTERN_SIGNAL_H /** * @file * @author Ruby developers * @copyright This file is a part of the programming language Ruby. * Permission is hereby granted, to either redistribute and/or * modify this file, provided that the conditions mentioned in the * file COPYING are met. Consult the file for details. * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are * implementation details. Don't take them as canon. They could * rapidly appear then vanish. The name (path) of this header file * is also an implementation detail. Do not expect it to persist * at the place it is now. Developers are free to move it anywhere * anytime at will. * @note To ruby-core: remember that this header can be possibly * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of * extension libraries. They could be written in C++98. * @brief Signal handling APIs. */ #include "ruby/internal/attr/nonnull.h" #include "ruby/internal/attr/pure.h" #include "ruby/internal/dllexport.h" #include "ruby/internal/value.h" RBIMPL_SYMBOL_EXPORT_BEGIN() /* signal.c */ RBIMPL_ATTR_NONNULL(()) /** * Sends a signal ("kills") to processes. * * The first argument is the signal, either in: * * - Numerical representation (e.g. `9`), or * - Textual representation of canonical (e.g. `:SIGKILL`) name or * abbreviated (e.g. `:KILL`) name, either in ::rb_cSymbol or ::rb_cString. * * All the remaining arguments are numerical representations of process IDs. * This function iterates over them to send the specified signal. * * You can specify both negative PIDs and negative signo to this function: * * ``` * sig \ pid | >= 1 | == 0 | == -1 | <= -2 * ===========+======+======+=======+======= * > 0 | #1 | #2 | #3 | #4 * == 0 | #5 | #6 | #7 | #8 * < 0 | #9 | #10 | #11 * ``` * * - Case #1: When signo and PID are both positive, this function sends the * specified signal to the specified process (intuitive). * * - Case #2: When signo is positive and PID is zero, this function sends * that signal to the current process group. * * - Case #3: When signo is positive and PID is -1, this function sends that * signal to everything that the current process is allowed to kill. * * - Case #4: When signo is positive and PID is negative (but not -1), this * function sends that signal to every processes in a process group, whose * process group ID is the absolute value of the passed PID. * * - Case #5: When signo is zero and PID is positive, this function just * checks for the existence of the specified process and doesn't send * anything to anyone. In case the process is absent `Errno::ESRCH` is * raised. * * - Case #6: When signo and PID are both zero, this function checks for the * existence of the current process group. And it must do. This function * is effectively a no-op then. * * - Case #7: When signo is zero and PID is -1, this function checks if there * is any other process that the current process can kill. At least init * (PID 1) must exist, so this must not fail. * * - Case #8: When signo is zero and PID is negative (but not -1), this * function checks if there is a process group whose process group ID is * the absolute value of the passed PID. In case the process group is * absent `Errno::ESRCH` is raised. * * - Case #9: When signo is negative and PID is positive, this function sends * the absolute value of the passed signo to the process group specified as * the PID. * * - Case #10: When signo is negative and PID is zero, it is highly expected * that this function sends the absolute value of the passed signo to the * current process group. Strictly speaking, IEEE Std 1003.1-2017 * specifies that this (`killpg(3posix)` with an argument of zero) is an * undefined behaviour. But no operating system is known so far that does * things differently. * * - Case #11: When signo and PID are both negative, the behaviour of this * function depends on how `killpg(3)` works. On Linux, it seems such * attempt is strictly prohibited and `Errno::EINVAL` is raised. But on * macOS, it seems it tries to to send the signal actually to the process * group. * * @note Above description is in fact different from how `kill(2)` works. * We interpret the passed arguments before passing them through to * system calls. * @param[in] argc Number of objects in `argv`. * @param[in] argv Signal, followed by target PIDs. * @exception rb_eArgError Unknown signal name. * @exception rb_eSystemCallError Various errors sending signal to processes. * @return Something numeric. The meaning of this return value is unclear. * It seems in case of #1 above, this could be the body count. But * other cases remain mysterious. */ VALUE rb_f_kill(int argc, const VALUE *argv); /* This must be private, @shyouhei guesses. */ #ifdef POSIX_SIGNAL #define posix_signal ruby_posix_signal void (*posix_signal(int, void (*)(int)))(int); #endif RBIMPL_ATTR_PURE() /** * Queries the name of the signal. It returns for instance `"KILL"` for * SIGKILL. * * @param[in] signo Signal number to query. * @retval 0 No such signal. * @retval otherwise A pointer to a static C string that is the name of * the signal. * @warning Don't free the return value. */ const char *ruby_signal_name(int signo); /** * Pretends as if there was no custom signal handler. This function sets the * signal action to SIG_DFL, then kills itself. * * @param[in] sig The signal. * @post Previous signal handler is lost. * @post Passed signal is sent to the current process. * * @internal * * @shyouhei doesn't understand the needs of this function being visible from * extension libraries. */ void ruby_default_signal(int sig); RBIMPL_SYMBOL_EXPORT_END() #endif /* RBIMPL_INTERN_SIGNAL_H */