Esempio n. 1
0
void event_remove(const event_t &criterion) {
    event_list_t new_list;

    if (debug_level >= 3) {
        wcstring desc = event_desc_compact(criterion);
        debug(3, "unregister: %ls\n", desc.c_str());
    }

    // Because of concurrency issues (env_remove could remove an event that is currently being
    // executed), env_remove does not actually free any events - instead it simply moves all events
    // that should be removed from the event list to the killme list, and the ones that shouldn't be
    // killed to new_list, and then drops the empty events-list.
    if (s_event_handlers.empty()) return;

    for (size_t i = 0; i < s_event_handlers.size(); i++) {
        event_t *n = s_event_handlers.at(i);
        if (event_match(criterion, *n)) {
            killme.push_back(n);

            // If this event was a signal handler and no other handler handles the specified signal
            // type, do not handle that type of signal any more.
            if (n->type == EVENT_SIGNAL) {
                event_t e = event_t::signal_event(n->param1.signal);
                if (event_get(e, 0) == 1) {
                    signal_handle(e.param1.signal, 0);
                    set_signal_observed(e.param1.signal, 0);
                }
            }
        } else {
            new_list.push_back(n);
        }
    }
    s_event_handlers.swap(new_list);
}
Esempio n. 2
0
static void show_all_handlers(void)
{
    puts("event handlers:");
    for (event_list_t::const_iterator iter = events.begin(); iter != events.end(); ++iter)
    {
        const event_t *foo = *iter;
        wcstring tmp = event_get_desc(foo);
        printf("    handler now %ls\n", tmp.c_str());
    }
}
Esempio n. 3
0
int event_get(const event_t &criterion, std::vector<event_t *> *out) {
    int found = 0;
    for (size_t i = 0; i < s_event_handlers.size(); i++) {
        event_t *n = s_event_handlers.at(i);
        if (event_match(criterion, *n)) {
            found++;
            if (out) out->push_back(n);
        }
    }
    return found;
}
Esempio n. 4
0
/// Handle all pending signal events.
static void event_fire_delayed() {
    // If is_event is one, we are running the event-handler non-recursively.
    //
    // When the event handler has called a piece of code that triggers another event, we do not want
    // to fire delayed events because of concurrency problems.
    if (!blocked.empty() && is_event == 1) {
        event_list_t new_blocked;

        for (size_t i = 0; i < blocked.size(); i++) {
            event_t *e = blocked.at(i);
            if (event_is_blocked(*e)) {
                new_blocked.push_back(new event_t(*e));
            } else {
                event_fire_internal(*e);
                event_free(e);
            }
        }
        blocked.swap(new_blocked);
    }

    int al = active_list;

    while (sig_list[al].count > 0) {
        signal_list_t *lst;

        // Switch signal lists.
        sig_list[1 - al].count = 0;
        sig_list[1 - al].overflow = 0;
        al = 1 - al;
        active_list = al;

        // Set up.
        lst = &sig_list[1 - al];
        event_t e = event_t::signal_event(0);
        e.arguments.resize(1);

        if (lst->overflow) {
            debug(0, _(L"Signal list overflow. Signals have been ignored."));
        }

        // Send all signals in our private list.
        for (int i = 0; i < lst->count; i++) {
            e.param1.signal = lst->signal[i];
            e.arguments.at(0) = sig2wcs(e.param1.signal);
            if (event_is_blocked(e)) {
                blocked.push_back(new event_t(e));
            } else {
                event_fire_internal(e);
            }
        }
    }
}
Esempio n. 5
0
void event_remove(event_t *criterion)
{

    size_t i;
    event_list_t new_list;

    CHECK(criterion,);

    /*
      Because of concurrency issues (env_remove could remove an event
      that is currently being executed), env_remove does not actually
      free any events - instead it simply moves all events that should
      be removed from the event list to the killme list, and the ones
      that shouldn't be killed to new_list, and then drops the empty
      events-list.
    */

    if (events.empty())
        return;

    for (i=0; i<events.size(); i++)
    {
        event_t *n = events.at(i);
        if (event_match(criterion, n))
        {
            killme.push_back(n);

            /*
              If this event was a signal handler and no other handler handles
              the specified signal type, do not handle that type of signal any
              more.
            */
            if (n->type == EVENT_SIGNAL)
            {
                event_t e = event_t::signal_event(n->param1.signal);
                if (event_get(&e, 0) == 1)
                {
                    signal_handle(e.param1.signal, 0);
                }
            }
        }
        else
        {
            new_list.push_back(n);
        }
    }
    signal_block();
    events.swap(new_list);
    signal_unblock();
}
Esempio n. 6
0
void event_fire(const event_t *event)
{

    if (event && event->type == EVENT_SIGNAL)
    {
        event_fire_signal(event->param1.signal);
    }
    else
    {
        is_event++;

        /*
          Fire events triggered by signals
        */
        event_fire_delayed();

        if (event)
        {
            if (event_is_blocked(*event))
            {
                blocked.push_back(new event_t(*event));
            }
            else
            {
                event_fire_internal(*event);
            }
        }
        is_event--;
    }
}
Esempio n. 7
0
int event_get(const event_t &criterion, std::vector<event_t *> *out)
{
    size_t i;
    int found = 0;

    if (events.empty())
        return 0;

    for (i=0; i<events.size(); i++)
    {
        event_t *n = events.at(i);
        if (event_match(criterion, *n))
        {
            found++;
            if (out)
                out->push_back(n);
        }
    }
    return found;
}
Esempio n. 8
0
void event_destroy() {
    for_each(s_event_handlers.begin(), s_event_handlers.end(), event_free);
    s_event_handlers.clear();

    for_each(killme.begin(), killme.end(), event_free);
    killme.clear();
}
Esempio n. 9
0
void event_destroy()
{

    for_each(events.begin(), events.end(), event_free);
    events.clear();

    for_each(killme.begin(), killme.end(), event_free);
    killme.clear();
}
Esempio n. 10
0
void event_add_handler(const event_t &event) {
    event_t *e;

    if (debug_level >= 3) {
        wcstring desc = event_desc_compact(event);
        debug(3, "register: %ls\n", desc.c_str());
    }

    e = new event_t(event);
    if (e->type == EVENT_SIGNAL) {
        signal_handle(e->param1.signal, 1);
        set_signal_observed(e->param1.signal, true);
    }

    s_event_handlers.push_back(e);
}
Esempio n. 11
0
void event_add_handler(const event_t *event)
{
    event_t *e;

    CHECK(event,);

    e = event_copy(event, 0);

    if (e->type == EVENT_SIGNAL)
    {
        signal_handle(e->param1.signal, 1);
    }

    // Block around updating the events vector
    signal_block();
    events.push_back(e);
    signal_unblock();
}
Esempio n. 12
0
bool event_is_signal_observed(int sig)
{
    /* We are in a signal handler! Don't allocate memory, etc.
       This does what event_match does, except it doesn't require passing in an event_t.
    */
    size_t i, max = events.size();
    for (i=0; i < max; i++)
    {
        const event_t *event = events[i];
        if (event->type == EVENT_ANY)
        {
            return true;
        }
        else if (event->type == EVENT_SIGNAL)
        {
            if (event->param1.signal == EVENT_ANY_SIGNAL || event->param1.signal == sig)
                return true;
        }
    }
    return false;
}
Esempio n. 13
0
void event_add_handler(const event_t &event)
{
    event_t *e;

    if (debug_level >= 3)
    {
        wcstring desc = event_desc_compact(event);
        debug(3, "register: %ls\n", desc.c_str());
    }

    e = new event_t(event);

    if (e->type == EVENT_SIGNAL)
    {
        signal_handle(e->param1.signal, 1);
    }

    // Block around updating the events vector
    signal_block();
    events.push_back(e);
    signal_unblock();
}
Esempio n. 14
0
/**
   Handle all pending signal events
*/
static void event_fire_delayed()
{

    size_t i;

    /*
      If is_event is one, we are running the event-handler non-recursively.

      When the event handler has called a piece of code that triggers
      another event, we do not want to fire delayed events because of
      concurrency problems.
    */
    if (! blocked.empty() && is_event==1)
    {
        event_list_t new_blocked;

        for (i=0; i<blocked.size(); i++)
        {
            event_t *e = blocked.at(i);
            if (event_is_blocked(e))
            {
                new_blocked.push_back(e);
            }
            else
            {
                event_fire_internal(e);
                event_free(e);
            }
        }
        blocked.swap(new_blocked);
    }

    while (sig_list[active_list].count > 0)
    {
        signal_list_t *lst;

        /*
          Switch signal lists
        */
        sig_list[1-active_list].count=0;
        sig_list[1-active_list].overflow=0;
        active_list=1-active_list;

        /*
          Set up
        */
        event_t e = event_t::signal_event(0);
        e.arguments.reset(new wcstring_list_t(1)); //one element
        lst = &sig_list[1-active_list];

        if (lst->overflow)
        {
            debug(0, _(L"Signal list overflow. Signals have been ignored."));
        }

        /*
          Send all signals in our private list
        */
        for (int i=0; i < lst->count; i++)
        {
            e.param1.signal = lst->signal[i];
            e.arguments->at(0) = sig2wcs(e.param1.signal);
            if (event_is_blocked(&e))
            {
                blocked.push_back(event_copy(&e, 1));
            }
            else
            {
                event_fire_internal(&e);
            }
        }

        e.arguments.reset(NULL);

    }
}
Esempio n. 15
0
/**
   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.
*/
static void event_fire_internal(const event_t &event)
{

    event_list_t fire;

    /*
      First we free all events that have been removed, but only if this
    		invocation of event_fire_internal is not a recursive call.
    */
    if (is_event <= 1)
        event_free_kills();

    if (events.empty())
        return;

    /*
      Then we iterate over all events, adding events that should be
      fired to a second list. We need to do this in a separate step
      since an event handler might call event_remove or
      event_add_handler, which will change the contents of the \c
      events list.
    */
    for (size_t i=0; i<events.size(); i++)
    {
        event_t *criterion = events.at(i);

        /*
          Check if this event is a match
        */
        if (event_match(*criterion, event))
        {
            fire.push_back(criterion);
        }
    }

    /*
      No matches. Time to return.
    */
    if (fire.empty())
        return;

    if (signal_is_blocked())
    {
        /* Fix for https://github.com/fish-shell/fish-shell/issues/608. Don't run event handlers while signals are blocked. */
        event_t *heap_event = new event_t(event);
        input_common_add_callback(fire_event_callback, heap_event);
        return;
    }

    /*
      Iterate over our list of matching events
    */

    for (size_t i=0; i<fire.size(); i++)
    {
        event_t *criterion = fire.at(i);
        int prev_status;

        /*
          Check if this event has been removed, if so, dont fire it
        */
        if (event_is_killed(*criterion))
            continue;

        /*
          Fire event
        */
        wcstring buffer = criterion->function_name;

        for (size_t j=0; j < event.arguments.size(); j++)
        {
            wcstring arg_esc = escape_string(event.arguments.at(j), 1);
            buffer += L" ";
            buffer += arg_esc;
        }

        // debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );

        /*
          Event handlers are not part of the main flow of code, so
          they are marked as non-interactive
        */
        proc_push_interactive(0);
        prev_status = proc_get_last_status();
        parser_t &parser = parser_t::principal_parser();

        block_t *block = new event_block_t(event);
        parser.push_block(block);
        parser.eval(buffer, io_chain_t(), TOP);
        parser.pop_block();
        proc_pop_interactive();
        proc_set_last_status(prev_status);
    }

    /*
      Free killed events
    */
    if (is_event <= 1)
        event_free_kills();

}
Esempio n. 16
0
/**
   Test if the specified event is waiting to be killed
*/
static int event_is_killed(const event_t &e)
{
    return std::find(killme.begin(), killme.end(), &e) != killme.end();
}
Esempio n. 17
0
/**
   Free all events in the kill list
*/
static void event_free_kills()
{
    for_each(killme.begin(), killme.end(), event_free);
    killme.resize(0);
}
Esempio n. 18
0
/**
   Test if the specified event is waiting to be killed
*/
static int event_is_killed(event_t *e)
{
    return std::find(killme.begin(), killme.end(), e) != killme.end();
}
Esempio n. 19
0
/**
   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.
*/
static void event_fire_internal(const event_t *event)
{

    size_t i, j;
    event_list_t fire;

    /*
      First we free all events that have been removed
    */
    event_free_kills();

    if (events.empty())
        return;

    /*
      Then we iterate over all events, adding events that should be
      fired to a second list. We need to do this in a separate step
      since an event handler might call event_remove or
      event_add_handler, which will change the contents of the \c
      events list.
    */
    for (i=0; i<events.size(); i++)
    {
        event_t *criterion = events.at(i);

        /*
          Check if this event is a match
        */
        if (event_match(criterion, event))
        {
            fire.push_back(criterion);
        }
    }

    /*
      No matches. Time to return.
    */
    if (fire.empty())
        return;

    /*
      Iterate over our list of matching events
    */

    for (i=0; i<fire.size(); i++)
    {
        event_t *criterion = fire.at(i);
        int prev_status;

        /*
          Check if this event has been removed, if so, dont fire it
        */
        if (event_is_killed(criterion))
            continue;

        /*
          Fire event
        */
        wcstring buffer = criterion->function_name;

        if (event->arguments.get())
        {
            for (j=0; j< event->arguments->size(); j++)
            {
                wcstring arg_esc = escape_string(event->arguments->at(j), 1);
                buffer += L" ";
                buffer += arg_esc;
            }
        }

//    debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );

        /*
          Event handlers are not part of the main flow of code, so
          they are marked as non-interactive
        */
        proc_push_interactive(0);
        prev_status = proc_get_last_status();
        parser_t &parser = parser_t::principal_parser();

        block_t *block = new event_block_t(event);
        parser.push_block(block);
        parser.eval(buffer, io_chain_t(), TOP);
        parser.pop_block();
        proc_pop_interactive();
        proc_set_last_status(prev_status);
    }

    /*
      Free killed events
    */
    event_free_kills();

}