2016-04-28 19:19:50 -07:00
|
|
|
// Functions for handling event triggers.
|
2016-05-18 22:30:21 +00:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
2019-10-13 15:50:48 -07:00
|
|
|
#include "event.h"
|
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
#include <signal.h>
|
2016-04-20 23:00:54 -07:00
|
|
|
#include <unistd.h>
|
2017-02-10 18:47:02 -08:00
|
|
|
|
2016-04-20 23:00:54 -07:00
|
|
|
#include <algorithm>
|
2022-05-28 13:35:17 -07:00
|
|
|
#include <array>
|
2019-02-20 19:36:29 -08:00
|
|
|
#include <atomic>
|
2022-08-20 23:14:48 -07:00
|
|
|
#include <bitset>
|
2016-04-28 19:19:50 -07:00
|
|
|
#include <memory>
|
2015-07-25 23:14:25 +08:00
|
|
|
#include <string>
|
2005-10-06 08:37:08 +10:00
|
|
|
|
|
|
|
#include "common.h"
|
2016-04-28 19:19:50 -07:00
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
2022-08-20 23:14:48 -07:00
|
|
|
#include "flog.h"
|
2015-07-25 23:14:25 +08:00
|
|
|
#include "io.h"
|
2022-08-20 23:14:48 -07:00
|
|
|
#include "maybe.h"
|
2016-04-28 19:19:50 -07:00
|
|
|
#include "parser.h"
|
|
|
|
#include "proc.h"
|
|
|
|
#include "signal.h"
|
2021-04-14 17:17:22 +02:00
|
|
|
#include "termsize.h"
|
2021-05-17 15:33:33 -07:00
|
|
|
#include "wcstringutil.h"
|
2016-04-28 19:19:50 -07:00
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2006-07-20 08:55:49 +10:00
|
|
|
|
2021-09-28 12:50:27 -07:00
|
|
|
namespace {
|
2019-02-20 19:36:29 -08:00
|
|
|
class pending_signals_t {
|
|
|
|
static constexpr size_t SIGNAL_COUNT = NSIG;
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2019-02-20 19:36:29 -08:00
|
|
|
/// A counter that is incremented each time a pending signal is received.
|
|
|
|
std::atomic<uint32_t> counter_{0};
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2019-02-20 19:36:29 -08:00
|
|
|
/// List of pending signals.
|
2022-05-08 15:49:19 -07:00
|
|
|
std::array<relaxed_atomic_bool_t, SIGNAL_COUNT> received_{};
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2019-02-20 19:36:29 -08:00
|
|
|
/// The last counter visible in acquire_pending().
|
|
|
|
/// This is not accessed from a signal handler.
|
|
|
|
owning_lock<uint32_t> last_counter_{0};
|
|
|
|
|
2019-05-05 12:09:25 +02:00
|
|
|
public:
|
2019-02-20 19:36:29 -08:00
|
|
|
pending_signals_t() = default;
|
|
|
|
|
|
|
|
/// No copying.
|
2021-08-17 16:49:00 -07:00
|
|
|
pending_signals_t(const pending_signals_t &) = delete;
|
2021-11-02 12:46:32 -07:00
|
|
|
pending_signals_t &operator=(const pending_signals_t &) = delete;
|
2019-02-20 19:36:29 -08:00
|
|
|
|
|
|
|
/// Mark a signal as pending. This may be called from a signal handler.
|
|
|
|
/// We expect only one signal handler to execute at once.
|
|
|
|
/// Also note that these may be coalesced.
|
|
|
|
void mark(int which) {
|
|
|
|
if (which >= 0 && static_cast<size_t>(which) < received_.size()) {
|
|
|
|
// Must mark our received first, then pending.
|
2022-05-08 15:49:19 -07:00
|
|
|
received_[which] = true;
|
2019-02-20 19:36:29 -08:00
|
|
|
uint32_t count = counter_.load(std::memory_order_relaxed);
|
|
|
|
counter_.store(1 + count, std::memory_order_release);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return the list of signals that were set, clearing them.
|
|
|
|
std::bitset<SIGNAL_COUNT> acquire_pending() {
|
|
|
|
auto current = last_counter_.acquire();
|
|
|
|
|
|
|
|
// Check the counter first. If it hasn't changed, no signals have been received.
|
|
|
|
uint32_t count = counter_.load(std::memory_order_acquire);
|
|
|
|
if (count == *current) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-05-08 15:49:19 -07:00
|
|
|
// The signal count has changed. Store the new counter and fetch all set signals.
|
2019-02-20 19:36:29 -08:00
|
|
|
*current = count;
|
|
|
|
std::bitset<SIGNAL_COUNT> result{};
|
2022-05-08 15:49:19 -07:00
|
|
|
for (size_t i = 0; i < NSIG; i++) {
|
|
|
|
if (received_[i]) {
|
|
|
|
result.set(i);
|
|
|
|
received_[i] = false;
|
2019-02-20 19:36:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
2021-09-28 12:50:27 -07:00
|
|
|
} // namespace
|
2019-02-20 19:36:29 -08:00
|
|
|
|
|
|
|
static pending_signals_t s_pending_signals;
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
/// List of event handlers.
|
2019-06-03 12:33:10 -07:00
|
|
|
static owning_lock<event_handler_list_t> s_event_handlers;
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2022-05-28 13:35:17 -07:00
|
|
|
/// Tracks the number of registered event handlers for each signal.
|
|
|
|
/// This is inspected by a signal handler. We assume no values in here overflow.
|
|
|
|
static std::array<relaxed_atomic_t<uint32_t>, NSIG> s_observed_signals;
|
2019-06-03 00:02:22 -07:00
|
|
|
|
2022-05-28 13:35:17 -07:00
|
|
|
static inline void inc_signal_observed(int sig) {
|
|
|
|
if (0 <= sig && sig < NSIG) {
|
|
|
|
s_observed_signals[sig]++;
|
2014-12-29 00:34:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-28 13:35:17 -07:00
|
|
|
static inline void dec_signal_observed(int sig) {
|
|
|
|
if (0 <= sig && sig < NSIG) {
|
|
|
|
s_observed_signals[sig]--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool event_is_signal_observed(int sig) {
|
|
|
|
// We are in a signal handler!
|
|
|
|
uint32_t count = 0;
|
|
|
|
if (0 <= sig && sig < NSIG) {
|
|
|
|
count = s_observed_signals[sig];
|
|
|
|
}
|
|
|
|
return count > 0;
|
|
|
|
}
|
|
|
|
|
2022-05-08 16:42:51 -07:00
|
|
|
/// \return true if a handler is "one shot": it fires at most once.
|
|
|
|
static bool handler_is_one_shot(const event_handler_t &handler) {
|
|
|
|
switch (handler.desc.type) {
|
|
|
|
case event_type_t::process_exit:
|
|
|
|
return handler.desc.param1.pid != EVENT_ANY_PID;
|
|
|
|
case event_type_t::job_exit:
|
|
|
|
return handler.desc.param1.jobspec.pid != EVENT_ANY_PID;
|
|
|
|
case event_type_t::caller_exit:
|
|
|
|
return true;
|
|
|
|
case event_type_t::signal:
|
|
|
|
case event_type_t::variable:
|
|
|
|
case event_type_t::generic:
|
|
|
|
case event_type_t::any:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
DIE("Unreachable");
|
|
|
|
}
|
|
|
|
|
2021-03-05 22:32:57 -06:00
|
|
|
/// Tests if one event instance matches the definition of an event class.
|
|
|
|
/// In case of a match, \p only_once indicates that the event cannot match again by nature.
|
2022-05-08 16:42:51 -07:00
|
|
|
static bool handler_matches(const event_handler_t &handler, const event_t &instance) {
|
|
|
|
if (handler.desc.type == event_type_t::any) return true;
|
|
|
|
if (handler.desc.type != instance.desc.type) return false;
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2022-05-08 16:42:51 -07:00
|
|
|
switch (handler.desc.type) {
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::signal: {
|
2022-05-08 16:42:51 -07:00
|
|
|
return handler.desc.param1.signal == instance.desc.param1.signal;
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::variable: {
|
2022-05-08 16:42:51 -07:00
|
|
|
return instance.desc.str_param1 == handler.desc.str_param1;
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::process_exit: {
|
2022-05-08 16:42:51 -07:00
|
|
|
if (handler.desc.param1.pid == EVENT_ANY_PID) return true;
|
|
|
|
return handler.desc.param1.pid == instance.desc.param1.pid;
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::job_exit: {
|
2022-05-08 16:42:51 -07:00
|
|
|
const auto &jobspec = handler.desc.param1.jobspec;
|
2021-05-20 11:25:32 -07:00
|
|
|
if (jobspec.pid == EVENT_ANY_PID) return true;
|
|
|
|
return jobspec.internal_job_id == instance.desc.param1.jobspec.internal_job_id;
|
2021-05-19 11:29:03 -07:00
|
|
|
}
|
2020-02-08 16:08:26 -08:00
|
|
|
case event_type_t::caller_exit: {
|
2022-05-08 16:42:51 -07:00
|
|
|
return handler.desc.param1.caller_id == instance.desc.param1.caller_id;
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::generic: {
|
2022-05-08 16:42:51 -07:00
|
|
|
return handler.desc.str_param1 == instance.desc.str_param1;
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-03-12 15:27:13 -07:00
|
|
|
case event_type_t::any:
|
|
|
|
default: {
|
2016-10-29 17:25:48 -07:00
|
|
|
DIE("unexpected classv.type");
|
2019-02-23 01:04:05 -08:00
|
|
|
return false;
|
2016-10-29 17:25:48 -07:00
|
|
|
}
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
/// Test if specified event is blocked.
|
2021-12-09 00:52:45 -08:00
|
|
|
static bool event_is_blocked(parser_t &parser, const event_t &e) {
|
2019-05-12 18:23:00 -07:00
|
|
|
(void)e;
|
2013-12-20 17:41:21 -08:00
|
|
|
const block_t *block;
|
|
|
|
size_t idx = 0;
|
2016-04-28 19:19:50 -07:00
|
|
|
while ((block = parser.block_at_index(idx++))) {
|
2019-02-20 22:42:58 -08:00
|
|
|
if (event_block_list_blocks_type(block->event_blocks)) return true;
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2019-02-20 22:42:58 -08:00
|
|
|
return event_block_list_blocks_type(parser.global_event_blocks);
|
2005-12-12 08:21:01 +10:00
|
|
|
}
|
|
|
|
|
2020-02-08 12:39:03 -08:00
|
|
|
wcstring event_get_desc(const parser_t &parser, const event_t &evt) {
|
2019-02-23 01:04:05 -08:00
|
|
|
const event_description_t &ed = evt.desc;
|
|
|
|
switch (ed.type) {
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::signal: {
|
2019-02-23 01:04:05 -08:00
|
|
|
return format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(ed.param1.signal),
|
|
|
|
signal_get_desc(ed.param1.signal));
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::variable: {
|
2019-02-23 01:04:05 -08:00
|
|
|
return format_string(_(L"handler for variable '%ls'"), ed.str_param1.c_str());
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::process_exit: {
|
|
|
|
return format_string(_(L"exit handler for process %d"), ed.param1.pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
case event_type_t::job_exit: {
|
2021-05-20 11:25:32 -07:00
|
|
|
const auto &jobspec = ed.param1.jobspec;
|
|
|
|
if (const job_t *j = parser.job_get_from_pid(jobspec.pid)) {
|
2021-05-19 11:29:03 -07:00
|
|
|
return format_string(_(L"exit handler for job %d, '%ls'"), j->job_id(),
|
|
|
|
j->command_wcstr());
|
2016-04-28 19:19:50 -07:00
|
|
|
} else {
|
2021-05-20 11:25:32 -07:00
|
|
|
return format_string(_(L"exit handler for job with pid %d"), jobspec.pid);
|
2012-11-19 00:31:03 -08:00
|
|
|
}
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
|
2020-02-08 16:08:26 -08:00
|
|
|
case event_type_t::caller_exit: {
|
|
|
|
return _(L"exit handler for command substitution caller");
|
2012-11-19 00:31:03 -08:00
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::generic: {
|
2019-02-23 01:04:05 -08:00
|
|
|
return format_string(_(L"handler for generic event '%ls'"), ed.str_param1.c_str());
|
2016-04-28 19:19:50 -07:00
|
|
|
}
|
2019-05-05 12:09:25 +02:00
|
|
|
case event_type_t::any: {
|
|
|
|
DIE("Unreachable");
|
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
default:
|
2019-03-05 07:27:56 +08:00
|
|
|
DIE("Unknown event type");
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2006-02-02 01:49:11 +10:00
|
|
|
}
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
void event_add_handler(std::shared_ptr<event_handler_t> eh) {
|
|
|
|
if (eh->desc.type == event_type_t::signal) {
|
2019-06-28 10:33:03 -07:00
|
|
|
signal_handle(eh->desc.param1.signal);
|
2022-05-28 13:35:17 -07:00
|
|
|
inc_signal_observed(eh->desc.param1.signal);
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2005-10-06 08:37:08 +10:00
|
|
|
|
2019-06-03 12:33:10 -07:00
|
|
|
s_event_handlers.acquire()->push_back(std::move(eh));
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2022-05-08 16:42:51 -07:00
|
|
|
// \remove handlers for which \p func returns true.
|
2022-05-28 13:35:17 -07:00
|
|
|
// Simultaneously update our signal_observed array.
|
2022-05-08 16:42:51 -07:00
|
|
|
template <typename T>
|
|
|
|
static void remove_handlers_if(const T &func) {
|
2019-06-03 12:33:10 -07:00
|
|
|
auto handlers = s_event_handlers.acquire();
|
2022-05-08 16:42:51 -07:00
|
|
|
auto iter = handlers->begin();
|
|
|
|
while (iter != handlers->end()) {
|
|
|
|
event_handler_t *handler = iter->get();
|
|
|
|
if (func(*handler)) {
|
|
|
|
handler->removed = true;
|
2022-05-28 13:35:17 -07:00
|
|
|
if (handler->desc.type == event_type_t::signal) {
|
|
|
|
dec_signal_observed(handler->desc.param1.signal);
|
|
|
|
}
|
2022-05-08 16:42:51 -07:00
|
|
|
iter = handlers->erase(iter);
|
|
|
|
} else {
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void event_remove_function_handlers(const wcstring &name) {
|
|
|
|
remove_handlers_if(
|
|
|
|
[&](const event_handler_t &handler) { return handler.function_name == name; });
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
event_handler_list_t event_get_function_handlers(const wcstring &name) {
|
2019-06-03 12:33:10 -07:00
|
|
|
auto handlers = s_event_handlers.acquire();
|
2019-02-23 01:04:05 -08:00
|
|
|
event_handler_list_t result;
|
2019-06-03 12:33:10 -07:00
|
|
|
for (const shared_ptr<event_handler_t> &eh : *handlers) {
|
2019-02-23 01:04:05 -08:00
|
|
|
if (eh->function_name == name) {
|
|
|
|
result.push_back(eh);
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
return result;
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
/// Perform the specified event. Since almost all event firings will not be matched by even a single
|
|
|
|
/// event handler, we make sure to optimize the 'no matches' path. This means that nothing is
|
|
|
|
/// allocated/initialized unless needed.
|
2019-06-03 02:31:13 -07:00
|
|
|
static void event_fire_internal(parser_t &parser, const event_t &event) {
|
|
|
|
auto &ld = parser.libdata();
|
2019-05-12 18:02:57 -07:00
|
|
|
assert(ld.is_event >= 0 && "is_event should not be negative");
|
|
|
|
scoped_push<decltype(ld.is_event)> inc_event{&ld.is_event, ld.is_event + 1};
|
2019-02-20 19:36:29 -08:00
|
|
|
|
2019-10-18 18:08:22 -07:00
|
|
|
// Suppress fish_trace during events.
|
|
|
|
scoped_push<bool> suppress_trace{&ld.suppress_fish_trace, true};
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
// Capture the event handlers that match this event.
|
2022-05-08 16:42:51 -07:00
|
|
|
std::vector<std::shared_ptr<event_handler_t>> fire;
|
2021-03-05 22:32:57 -06:00
|
|
|
{
|
2021-11-02 12:46:32 -07:00
|
|
|
auto event_handlers = s_event_handlers.acquire();
|
|
|
|
for (const auto &handler : *event_handlers) {
|
2022-05-08 16:42:51 -07:00
|
|
|
if (handler_matches(*handler, event)) {
|
|
|
|
fire.push_back(handler);
|
2021-03-05 22:32:57 -06:00
|
|
|
}
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
}
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
// Iterate over our list of matching events. Fire the ones that are still present.
|
2022-06-06 12:09:04 -07:00
|
|
|
bool fired_one_shot = false;
|
2022-05-08 16:42:51 -07:00
|
|
|
for (const auto &handler : fire) {
|
|
|
|
// A previous handlers may have erased this one.
|
|
|
|
if (handler->removed) continue;
|
2012-11-18 16:30:30 -08:00
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
// Construct a buffer to evaluate, starting with the function name and then all the
|
|
|
|
// arguments.
|
|
|
|
wcstring buffer = handler->function_name;
|
|
|
|
for (const wcstring &arg : event.arguments) {
|
|
|
|
buffer.push_back(L' ');
|
2022-07-25 16:25:04 +02:00
|
|
|
buffer.append(escape_string(arg));
|
2011-12-27 00:06:07 -08:00
|
|
|
}
|
2005-10-12 05:23:43 +10:00
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
// Event handlers are not part of the main flow of code, so they are marked as
|
|
|
|
// non-interactive.
|
2019-05-27 14:52:48 -07:00
|
|
|
scoped_push<bool> interactive{&ld.is_interactive, false};
|
2019-05-12 14:00:44 -07:00
|
|
|
auto prev_statuses = parser.get_last_statuses();
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2022-08-01 15:29:35 +02:00
|
|
|
FLOGF(event, L"Firing event '%ls' to handler '%ls'", event.desc.str_param1.c_str(),
|
|
|
|
handler->function_name.c_str());
|
2019-05-19 14:40:06 -07:00
|
|
|
block_t *b = parser.push_block(block_t::event_block(event));
|
2019-12-22 16:27:03 -08:00
|
|
|
parser.eval(buffer, io_chain_t());
|
2017-01-21 15:35:35 -08:00
|
|
|
parser.pop_block(b);
|
2019-05-12 14:00:44 -07:00
|
|
|
parser.set_last_statuses(std::move(prev_statuses));
|
2022-06-06 12:09:04 -07:00
|
|
|
|
|
|
|
handler->fired = true;
|
|
|
|
fired_one_shot |= handler_is_one_shot(*handler);
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2022-05-08 16:42:51 -07:00
|
|
|
|
2022-06-06 12:09:04 -07:00
|
|
|
// Remove any fired one-shot handlers.
|
|
|
|
if (fired_one_shot) {
|
|
|
|
remove_handlers_if([](const event_handler_t &handler) {
|
|
|
|
return handler.fired && handler_is_one_shot(handler);
|
|
|
|
});
|
2022-05-08 16:42:51 -07:00
|
|
|
}
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2016-04-28 19:19:50 -07:00
|
|
|
/// Handle all pending signal events.
|
2019-06-03 02:31:13 -07:00
|
|
|
void event_fire_delayed(parser_t &parser) {
|
|
|
|
auto &ld = parser.libdata();
|
2019-02-20 19:36:29 -08:00
|
|
|
// Do not invoke new event handlers from within event handlers.
|
2019-06-03 02:31:13 -07:00
|
|
|
if (ld.is_event) return;
|
2020-03-01 13:27:34 -08:00
|
|
|
// Do not invoke new event handlers if we are unwinding (#6649).
|
2020-07-12 11:35:27 -07:00
|
|
|
if (signal_check_cancel()) return;
|
2019-02-20 19:36:29 -08:00
|
|
|
|
2020-07-19 12:03:10 -07:00
|
|
|
std::vector<shared_ptr<const event_t>> to_send;
|
2019-06-03 02:31:13 -07:00
|
|
|
to_send.swap(ld.blocked_events);
|
|
|
|
assert(ld.blocked_events.empty());
|
2019-02-20 19:36:29 -08:00
|
|
|
|
|
|
|
// Append all signal events to to_send.
|
|
|
|
auto signals = s_pending_signals.acquire_pending();
|
|
|
|
if (signals.any()) {
|
2019-05-05 12:09:25 +02:00
|
|
|
for (uint32_t sig = 0; sig < signals.size(); sig++) {
|
2019-02-20 19:36:29 -08:00
|
|
|
if (signals.test(sig)) {
|
2021-04-14 17:17:22 +02:00
|
|
|
// HACK: The only variables we change in response to a *signal*
|
|
|
|
// are $COLUMNS and $LINES.
|
|
|
|
// Do that now.
|
|
|
|
if (sig == SIGWINCH) {
|
|
|
|
(void)termsize_container_t::shared().updating(parser);
|
|
|
|
}
|
2019-02-20 22:42:58 -08:00
|
|
|
auto e = std::make_shared<event_t>(event_type_t::signal);
|
2019-02-23 01:04:05 -08:00
|
|
|
e->desc.param1.signal = sig;
|
2019-02-20 19:36:29 -08:00
|
|
|
e->arguments.push_back(sig2wcs(sig));
|
|
|
|
to_send.push_back(std::move(e));
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2019-02-20 19:36:29 -08:00
|
|
|
// Fire or re-block all events.
|
|
|
|
for (const auto &evt : to_send) {
|
2019-06-03 02:31:13 -07:00
|
|
|
if (event_is_blocked(parser, *evt)) {
|
|
|
|
ld.blocked_events.push_back(evt);
|
2019-02-20 19:36:29 -08:00
|
|
|
} else {
|
2019-06-03 02:31:13 -07:00
|
|
|
event_fire_internal(parser, *evt);
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
|
|
|
}
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2019-02-20 19:36:29 -08:00
|
|
|
void event_enqueue_signal(int signal) {
|
|
|
|
// Beware, we are in a signal handler
|
|
|
|
s_pending_signals.mark(signal);
|
2012-06-04 14:20:01 -07:00
|
|
|
}
|
|
|
|
|
2019-06-03 02:31:13 -07:00
|
|
|
void event_fire(parser_t &parser, const event_t &event) {
|
2019-02-20 19:36:29 -08:00
|
|
|
// Fire events triggered by signals.
|
2019-06-03 02:31:13 -07:00
|
|
|
event_fire_delayed(parser);
|
2019-02-20 19:36:29 -08:00
|
|
|
|
2019-06-03 02:31:13 -07:00
|
|
|
if (event_is_blocked(parser, event)) {
|
|
|
|
parser.libdata().blocked_events.push_back(std::make_shared<event_t>(event));
|
2019-02-23 01:04:05 -08:00
|
|
|
} else {
|
2019-06-03 02:31:13 -07:00
|
|
|
event_fire_internal(parser, event);
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2005-10-06 08:37:08 +10:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:29:03 -07:00
|
|
|
static const wchar_t *event_name_for_type(event_type_t type) {
|
|
|
|
switch (type) {
|
|
|
|
case event_type_t::any:
|
|
|
|
return L"any";
|
|
|
|
case event_type_t::signal:
|
|
|
|
return L"signal";
|
|
|
|
case event_type_t::variable:
|
|
|
|
return L"variable";
|
|
|
|
case event_type_t::process_exit:
|
|
|
|
return L"process-exit";
|
|
|
|
case event_type_t::job_exit:
|
|
|
|
return L"job-exit";
|
|
|
|
case event_type_t::caller_exit:
|
|
|
|
return L"caller-exit";
|
|
|
|
case event_type_t::generic:
|
|
|
|
return L"generic";
|
2018-03-10 02:08:33 -08:00
|
|
|
}
|
2021-05-19 11:29:03 -07:00
|
|
|
return L"";
|
2018-01-31 18:47:23 +01:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:29:03 -07:00
|
|
|
const wchar_t *const event_filter_names[] = {L"signal", L"variable", L"exit",
|
|
|
|
L"process-exit", L"job-exit", L"caller-exit",
|
|
|
|
L"generic", nullptr};
|
|
|
|
|
|
|
|
static bool filter_matches_event(const wcstring &filter, event_type_t type) {
|
|
|
|
if (filter.empty()) return true;
|
|
|
|
switch (type) {
|
|
|
|
case event_type_t::any:
|
|
|
|
return false;
|
|
|
|
case event_type_t::signal:
|
|
|
|
return filter == L"signal";
|
|
|
|
case event_type_t::variable:
|
|
|
|
return filter == L"variable";
|
|
|
|
case event_type_t::process_exit:
|
|
|
|
return filter == L"process-exit" || filter == L"exit";
|
|
|
|
case event_type_t::job_exit:
|
|
|
|
return filter == L"job-exit" || filter == L"exit";
|
|
|
|
case event_type_t::caller_exit:
|
|
|
|
return filter == L"process-exit" || filter == L"exit";
|
|
|
|
case event_type_t::generic:
|
|
|
|
return filter == L"generic";
|
2018-01-31 18:47:23 +01:00
|
|
|
}
|
2021-05-19 11:29:03 -07:00
|
|
|
DIE("Unreachable");
|
2018-01-31 18:47:23 +01:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:29:03 -07:00
|
|
|
void event_print(io_streams_t &streams, const wcstring &type_filter) {
|
2019-06-03 12:33:10 -07:00
|
|
|
event_handler_list_t tmp = *s_event_handlers.acquire();
|
2018-01-31 18:47:23 +01:00
|
|
|
std::sort(tmp.begin(), tmp.end(),
|
2019-02-23 01:04:05 -08:00
|
|
|
[](const shared_ptr<event_handler_t> &e1, const shared_ptr<event_handler_t> &e2) {
|
|
|
|
const event_description_t &d1 = e1->desc;
|
|
|
|
const event_description_t &d2 = e2->desc;
|
|
|
|
if (d1.type != d2.type) {
|
|
|
|
return d1.type < d2.type;
|
|
|
|
}
|
|
|
|
switch (d1.type) {
|
|
|
|
case event_type_t::signal:
|
2021-06-28 18:06:04 -05:00
|
|
|
return d1.param1.signal < d2.param1.signal;
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::process_exit:
|
2019-02-23 01:04:05 -08:00
|
|
|
return d1.param1.pid < d2.param1.pid;
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::job_exit:
|
2021-05-20 11:25:32 -07:00
|
|
|
return d1.param1.jobspec.pid < d2.param1.jobspec.pid;
|
2020-02-08 16:08:26 -08:00
|
|
|
case event_type_t::caller_exit:
|
2020-02-08 15:43:21 -08:00
|
|
|
return d1.param1.caller_id < d2.param1.caller_id;
|
2019-02-23 01:04:05 -08:00
|
|
|
case event_type_t::variable:
|
|
|
|
case event_type_t::any:
|
|
|
|
case event_type_t::generic:
|
|
|
|
return d1.str_param1 < d2.str_param1;
|
|
|
|
}
|
2019-02-23 14:09:17 -08:00
|
|
|
DIE("Unreachable");
|
2019-02-23 01:04:05 -08:00
|
|
|
});
|
2018-01-31 18:47:23 +01:00
|
|
|
|
2018-03-10 02:08:33 -08:00
|
|
|
maybe_t<event_type_t> last_type{};
|
2019-02-23 01:04:05 -08:00
|
|
|
for (const shared_ptr<event_handler_t> &evt : tmp) {
|
2018-03-10 02:08:33 -08:00
|
|
|
// If we have a filter, skip events that don't match.
|
2021-05-19 11:29:03 -07:00
|
|
|
if (!filter_matches_event(type_filter, evt->desc.type)) {
|
2018-03-10 02:08:33 -08:00
|
|
|
continue;
|
|
|
|
}
|
2018-01-31 18:47:23 +01:00
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
if (!last_type || *last_type != evt->desc.type) {
|
2019-05-05 12:09:25 +02:00
|
|
|
if (last_type) streams.out.append(L"\n");
|
2020-09-08 22:33:44 +02:00
|
|
|
last_type = evt->desc.type;
|
2018-03-10 02:08:33 -08:00
|
|
|
streams.out.append_format(L"Event %ls\n", event_name_for_type(*last_type));
|
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
switch (evt->desc.type) {
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::signal:
|
2019-02-23 01:04:05 -08:00
|
|
|
streams.out.append_format(L"%ls %ls\n", sig2wcs(evt->desc.param1.signal),
|
|
|
|
evt->function_name.c_str());
|
2018-03-10 02:08:33 -08:00
|
|
|
break;
|
2021-05-19 11:29:03 -07:00
|
|
|
case event_type_t::process_exit:
|
|
|
|
case event_type_t::job_exit:
|
2020-02-08 16:08:26 -08:00
|
|
|
break;
|
|
|
|
case event_type_t::caller_exit:
|
|
|
|
streams.out.append_format(L"caller-exit %ls\n", evt->function_name.c_str());
|
2018-03-10 02:08:33 -08:00
|
|
|
break;
|
2019-02-20 22:42:58 -08:00
|
|
|
case event_type_t::variable:
|
|
|
|
case event_type_t::generic:
|
2019-02-23 01:04:05 -08:00
|
|
|
streams.out.append_format(L"%ls %ls\n", evt->desc.str_param1.c_str(),
|
|
|
|
evt->function_name.c_str());
|
2018-03-10 02:08:33 -08:00
|
|
|
break;
|
2019-05-05 12:09:25 +02:00
|
|
|
case event_type_t::any:
|
|
|
|
DIE("Unreachable");
|
2018-03-10 02:08:33 -08:00
|
|
|
default:
|
|
|
|
streams.out.append_format(L"%ls\n", evt->function_name.c_str());
|
|
|
|
break;
|
2018-01-31 18:47:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-08 17:07:34 -07:00
|
|
|
void event_fire_generic(parser_t &parser, wcstring name, wcstring_list_t args) {
|
2019-02-20 22:42:58 -08:00
|
|
|
event_t ev(event_type_t::generic);
|
2022-03-25 15:14:24 +01:00
|
|
|
ev.desc.str_param1 = std::move(name);
|
2022-05-08 17:07:34 -07:00
|
|
|
ev.arguments = std::move(args);
|
2019-06-03 02:31:13 -07:00
|
|
|
event_fire(parser, ev);
|
2007-08-20 02:42:30 +10:00
|
|
|
}
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
event_description_t event_description_t::signal(int sig) {
|
|
|
|
event_description_t event(event_type_t::signal);
|
2012-02-08 19:02:25 -08:00
|
|
|
event.param1.signal = sig;
|
|
|
|
return event;
|
|
|
|
}
|
2007-08-20 02:42:30 +10:00
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
event_description_t event_description_t::variable(wcstring str) {
|
|
|
|
event_description_t event(event_type_t::variable);
|
|
|
|
event.str_param1 = std::move(str);
|
2012-02-08 19:02:25 -08:00
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
2019-02-23 01:04:05 -08:00
|
|
|
event_description_t event_description_t::generic(wcstring str) {
|
|
|
|
event_description_t event(event_type_t::generic);
|
|
|
|
event.str_param1 = std::move(str);
|
2012-02-08 19:02:25 -08:00
|
|
|
return event;
|
|
|
|
}
|
2019-02-23 01:04:05 -08:00
|
|
|
|
2021-05-17 15:33:33 -07:00
|
|
|
// static
|
2021-11-14 17:39:52 -08:00
|
|
|
event_t event_t::variable_erase(wcstring name) {
|
2019-02-23 01:04:05 -08:00
|
|
|
event_t evt{event_type_t::variable};
|
2021-11-14 17:39:52 -08:00
|
|
|
evt.arguments = {L"VARIABLE", L"ERASE", name};
|
2019-02-23 01:04:05 -08:00
|
|
|
evt.desc.str_param1 = std::move(name);
|
|
|
|
return evt;
|
|
|
|
}
|
2021-05-17 15:33:33 -07:00
|
|
|
|
2021-10-26 17:03:45 +02:00
|
|
|
// static
|
|
|
|
event_t event_t::variable_set(wcstring name) {
|
2021-11-14 17:39:52 -08:00
|
|
|
event_t evt{event_type_t::variable};
|
|
|
|
evt.arguments = {L"VARIABLE", L"SET", name};
|
|
|
|
evt.desc.str_param1 = std::move(name);
|
|
|
|
return evt;
|
2021-10-26 17:03:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2021-05-17 15:33:33 -07:00
|
|
|
event_t event_t::process_exit(pid_t pid, int status) {
|
2021-05-19 11:29:03 -07:00
|
|
|
event_t evt{event_type_t::process_exit};
|
2021-05-17 15:33:33 -07:00
|
|
|
evt.desc.param1.pid = pid;
|
|
|
|
evt.arguments.reserve(3);
|
|
|
|
evt.arguments.push_back(L"PROCESS_EXIT");
|
|
|
|
evt.arguments.push_back(to_string(pid));
|
|
|
|
evt.arguments.push_back(to_string(status));
|
|
|
|
return evt;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2021-07-31 15:26:09 -05:00
|
|
|
event_t event_t::job_exit(pid_t pgid, internal_job_id_t jid) {
|
2021-05-19 11:29:03 -07:00
|
|
|
event_t evt{event_type_t::job_exit};
|
2021-07-31 15:26:09 -05:00
|
|
|
evt.desc.param1.jobspec = {pgid, jid};
|
2021-05-17 15:33:33 -07:00
|
|
|
evt.arguments.reserve(3);
|
|
|
|
evt.arguments.push_back(L"JOB_EXIT");
|
2021-07-31 15:26:09 -05:00
|
|
|
evt.arguments.push_back(to_string(pgid));
|
2021-05-17 15:33:33 -07:00
|
|
|
evt.arguments.push_back(L"0"); // historical
|
|
|
|
return evt;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2021-07-31 15:26:09 -05:00
|
|
|
event_t event_t::caller_exit(uint64_t internal_job_id, int job_id) {
|
2021-05-17 15:33:33 -07:00
|
|
|
event_t evt{event_type_t::caller_exit};
|
2021-07-31 15:26:09 -05:00
|
|
|
evt.desc.param1.caller_id = internal_job_id;
|
2021-05-17 15:33:33 -07:00
|
|
|
evt.arguments.reserve(3);
|
|
|
|
evt.arguments.push_back(L"JOB_EXIT");
|
|
|
|
evt.arguments.push_back(to_string(job_id));
|
|
|
|
evt.arguments.push_back(L"0"); // historical
|
|
|
|
return evt;
|
|
|
|
}
|