aboutsummaryrefslogtreecommitdiff
path: root/gdb/async-event.c
AgeCommit message (Collapse)AuthorFilesLines
2021-03-26gdb: defer commit resume until all available events are consumedSimon Marchi1-0/+8
Rationale --------- Let's say you have multiple threads hitting a conditional breakpoint at the same time, and all of these are going to evaluate to false. All these threads will need to be resumed. Currently, GDB fetches one target event (one SIGTRAP representing the breakpoint hit) and decides that the thread should be resumed. It calls resume and commit_resume immediately. It then fetches the second target event, and does the same, until it went through all threads. The result is therefore something like: - consume event for thread A - resume thread A - commit resume (affects thread A) - consume event for thread B - resume thread B - commit resume (affects thread B) - consume event for thread C - resume thread C - commit resume (affects thread C) For targets where it's beneficial to group resumptions requests (most likely those that implement target_ops::commit_resume), it would be much better to have: - consume event for thread A - resume thread A - consume event for thread B - resume thread B - consume event for thread C - resume thread C - commit resume (affects threads A, B and C) Implementation details ---------------------- To achieve this, this patch adds another check in maybe_set_commit_resumed_all_targets to avoid setting the commit-resumed flag of targets that readily have events to provide to infrun. To determine if a target has events readily available to report, this patch adds an `has_pending_events` target_ops method. The method returns a simple bool to say whether or not it has pending events to report. Testing ======= To test this, I start GDBserver with a program that spawns multiple threads: $ ../gdbserver/gdbserver --once :1234 ~/src/many-threads-stepping-over-breakpoints/many-threads-stepping-over-breakpoints I then connect with GDB and install a conditional breakpoint that always evaluates to false (and force the evaluation to be done by GDB): $ ./gdb -nx --data-directory=data-directory \ /home/simark/src/many-threads-stepping-over-breakpoints/many-threads-stepping-over-breakpoints \ -ex "set breakpoint condition-evaluation host" \ -ex "set pag off" \ -ex "set confirm off" \ -ex "maint set target-non-stop on" \ -ex "tar rem :1234" \ -ex "tb main" \ -ex "b 13 if 0" \ -ex c \ -ex "set debug infrun" \ -ex "set debug remote 1" \ -ex "set debug displaced" I then do "continue" and look at the log. The remote target receives a bunch of stop notifications for all threads that have hit the breakpoint. infrun consumes and processes one event, decides it should not cause a stop, prepares a displaced step, after which we should see: [infrun] maybe_set_commit_resumed_all_process_targets: not requesting commit-resumed for target remote, target has pending events Same for a second thread (since we have 2 displaced step buffers). For the following threads, their displaced step is deferred since there are no more buffers available. After consuming the last event the remote target has to offer, we get: [infrun] maybe_set_commit_resumed_all_process_targets: enabling commit-resumed for target remote [infrun] maybe_call_commit_resumed_all_process_targets: calling commit_resumed for target remote [remote] Sending packet: $vCont;s:p14d16b.14d1b1;s:p14d16b.14d1b2#55 [remote] Packet received: OK Without the patch, there would have been one vCont;s just after each prepared displaced step. gdb/ChangeLog: yyyy-mm-dd Simon Marchi <simon.marchi@efficios.com> Pedro Alves <pedro@palves.net> * async-event.c (async_event_handler_marked): New. * async-event.h (async_event_handler_marked): Declare. * infrun.c (maybe_set_commit_resumed_all_targets): Switch to inferior before calling target method. Don't commit-resumed if target_has_pending_events is true. * remote.c (remote_target::has_pending_events): New. * target-delegates.c: Regenerate. * target.c (target_has_pending_events): New. * target.h (target_ops::has_pending_events): New target method. (target_has_pending_events): New. Change-Id: I18112ba19a1ff4986530c660f530d847bb4a1f1d
2021-02-04gdb: make async event handlers clear themselvesSimon Marchi1-1/+0
The `ready` flag of async event handlers is cleared by the async event handler system right before invoking the associated callback, in check_async_event_handlers. This is not ideal with how the infrun subsystem consumes events: all targets' async event handler callbacks essentially just invoke `inferior_event_handler`, which eventually calls `fetch_inferior_event` and `do_target_wait`. `do_target_wait` picks an inferior at random, and thus a target at random (it could be the target whose `ready` flag was cleared, or not), and pulls one event from it. So it's possible that: - the async event handler for a target A is called - we end up consuming an event for target B - all threads of target B are stopped, target_async(0) is called on it, so its async event handler is cleared (e.g. record_btrace_target::async) As a result, target A still has events to report while its async event handler is left unmarked, so these events are not consumed. To counter this, at the end of their async event handler callbacks, targets check if they still have something to report and re-mark their async event handler (e.g. remote_async_inferior_event_handler). The linux_nat target does not suffer from this because it doesn't use an async event handler at the moment. It only uses a pipe registered with the event loop. It is written to in the SIGCHLD handler (and in other spots that want to get target wait method called) and read from in the target's wait method. So if linux_nat happened to be target A in the example above, the pipe would just stay readable, and the event loop would wake up again, until linux_nat's wait method is finally called and consumes the contents of the pipe. I think it would be nicer if targets using async_event_handler worked in a similar way, where the flag would stay set until the target's wait method is actually called. As a first step towards that, this patch moves the responsibility of clearing the ready flags of async event handlers to the invoked callback. All async event handler callbacks are modified to clear their ready flag before doing anything else. So in practice, nothing changes with this patch. It's only the responsibility of clearing the flag that is shifted toward the callee. gdb/ChangeLog: * async-event.h (async_event_handler_func): Add documentation. * async-event.c (check_async_event_handlers): Don't clear async_event_handler ready flag. * infrun.c (infrun_async_inferior_event_handler): Clear ready flag. * record-btrace.c (record_btrace_handle_async_inferior_event): Likewise. * record-full.c (record_full_async_inferior_event_handler): Likewise. * remote-notif.c (remote_async_get_pending_events_handler): Likewise. * remote.c (remote_async_inferior_event_handler): Likewise. Change-Id: I179ef8e99580eae642d332846fd13664dbddc0c1
2021-01-01Update copyright year range in all GDB filesJoel Brobecker1-1/+1
This commits the result of running gdb/copyright.py as per our Start of New Year procedure... gdb/ChangeLog Update copyright year range in copyright header of all GDB files.
2020-10-02gdb: add debug prints in event loopSimon Marchi1-1/+26
Add debug printouts about event loop-related events: - When a file descriptor handler gets invoked - When an async event/signal handler gets invoked gdb/ChangeLog: * async-event.c (invoke_async_signal_handlers): Add debug print. (check_async_event_handlers): Likewise. * event-top.c (show_debug_event_loop): New function. (_initialize_event_top): Register "set debug event-loop" setting. gdbserver/ChangeLog: * server.cc (handle_monitor_command): Handle "set debug-event-loop". (captured_main): Handle "--debug-event-loop". (monitor_show_help): Mention new setting. (gdbserver_usage): Mention new flag. gdbsupport/ChangeLog: * event-loop.h (debug_event_loop): New variable declaration. (event_loop_debug_printf_1): New function declaration. (event_loop_debug_printf): New macro. * event-loop.cc (debug_event_loop): New variable. (handle_file_event): Add debug print. (event_loop_debug_printf_1): New function. Change-Id: If78ed3a69179881368e7895b42940ce13b6a1a05
2020-10-02gdb: give names to async event/signal handlersSimon Marchi1-6/+14
Assign names to async event/signal handlers. They will be used in debug messages when file handlers are invoked. Unlike in the previous patch, the names are not copied in the structure, since we don't need to (all names are string literals for the moment). gdb/ChangeLog: * async-event.h (create_async_signal_handler): Add name parameter. (create_async_event_handler): Likewise. * async-event.c (struct async_signal_handler) <name>: New field. (struct async_event_handler) <name>: New field. (create_async_signal_handler): Assign name. (create_async_event_handler): Assign name. * event-top.c (async_init_signals): Pass name when creating handler. * infrun.c (_initialize_infrun): Likewise. * record-btrace.c (record_btrace_push_target): Likewise. * record-full.c (record_full_open): Likewise. * remote-notif.c (remote_notif_state_allocate): Likewise. * remote.c (remote_target::open_1): Likewise. * tui/tui-win.c (tui_initialize_win): Likewise. Change-Id: Icd9d9f775542ae5fc2cd148c12f481e7885936d5
2020-10-02gdb: give names to event loop file handlersSimon Marchi1-1/+1
Assign names to event loop file handlers. They will be used in debug messages when file handlers are invoked. In GDB, each UI used to get its own unique number, until commit cbe256847e19 ("Remove ui::num"). Re-introduce this field, and use it to make a unique name for the handler. I'm not too sure what goes on in ser-base.c, all I know is that it's what is used when debugging remotely. I've just named the main handler "serial". It would be good to have unique names there too. For instance when debugging with two different remote connections, we'd ideally want the handlers to have unique names. I didn't do it in this patch though. gdb/ChangeLog: * async-event.c (initialize_async_signal_handlers): Pass name to add_file_handler * event-top.c (ui_register_input_event_handler): Likewise. * linux-nat.c (linux_nat_target::async): Likewise. * run-on-main-thread.c (_initialize_run_on_main_thread): Likewise * ser-base.c (reschedule): Likewise. (ser_base_async): Likewise. * tui/tui-io.c: Likewise. * top.h (struct ui) <num>: New field. * top.c (highest_ui_num): New variable. (ui::ui): Initialize num. gdbserver/ChangeLog: * linux-low.cc (linux_process_target::async): Pass name to add_file_handler. * remote-utils.cc (handle_accept_event): Likewise. (remote_open): Likewise. gdbsupport/ChangeLog: * event-loop.h (add_file_handler): Add "name" parameter. * event-loop.cc (struct file_handler) <name>: New field. (create_file_handler): Add "name" parameter, assign it to file handler. (add_file_handler): Add "name" parameter. Change-Id: I9f1545f73888ebb6778eb653a618ca44d105f92c
2020-05-13gdb: update the copyright year in async-event.[ch]Tankut Baris Aktemur1-1/+1
The async-event.[ch] files were introduced recently as a result of splitting the event-loop. I believe the copyright year update was just an oversight. So, this patch fixes that. gdb/ChangeLog: 2020-05-13 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> * async-event.c: Update the copyright year. * async-event.h: Update the copyright year.
2020-05-07gdb: small cleanup of async-event.c structsSimon Marchi1-35/+39
This is a small cleanup to normalize the structures in async-event.c with the rest of the code base: - Remove the unnecessary typedefs - Fix indentation of struct bodies - Put comments above fields No functional changes expected. gdb/ChangeLog: * async-event.c (struct async_signal_handler, struct async_event_handler): Reformat, remove typedef.
2020-04-13Introduce async-event.[ch]Tom Tromey1-0/+325
This patch splits out some gdb-specific code from event-loop, into new files async-event.[ch]. Strictly speaking this code could perhaps be put into gdbsupport/, but because gdbserver does not currently use it, it seemed better, for size reasons, to split it out. gdb/ChangeLog 2020-04-13 Tom Tromey <tom@tromey.com> * tui/tui-win.c: Include async-event.h. * remote.c: Include async-event.h. * remote-notif.c: Include async-event.h. * record-full.c: Include async-event.h. * record-btrace.c: Include async-event.h. * infrun.c: Include async-event.h. * event-top.c: Include async-event.h. * event-loop.h: Move some declarations to async-event.h. * event-loop.c: Don't include ser-event.h or top.h. Move some code to async-event.c. * async-event.h: New file. * async-event.c: New file. * Makefile.in (COMMON_SFILES): Add async-event.c. (HFILES_NO_SRCDIR): Add async-event.h.