gdbsupport/event-loop: add a timeout parameter to gdb_do_one_event

Since commit b2d8657, having a per-interpreter event/command loop is not
possible anymore.

As Insight uses a GUI that has its own event loop, gdb and GUI event
loops have then to be "merged" (i.e.: work together). But this is
problematic as gdb_do_one_event is not aware of this alternate event
loop and thus may wait forever.

A solution is to delegate GUI events handling to the gdb events handler.
Insight uses Tck/Tk as GUI and the latter offers a "notifier" feature to
implement such a delegation. The Tcl notifier spec requires the event wait
function to support a timeout parameter. Unfortunately gdb_do_one_event
does not feature such a parameter.
This timeout cannot be implemented externally with a gdb timer, because
it would become an event by itself and thus can cause a legitimate event to
be missed if the timeout is 0.
Tcl implements "idle events" that are (internally) triggered only when no
other event is pending. For this reason, it can call the event wait function
with a 0 timeout quite often.

This patch implements a wait timeout to gdb_do_one_event. The initial
pending events monitoring is performed as before without the possibility
to enter a wait state. If no pending event has been found during this
phase, a timer is then created for the given timeout in order to re-use
the implemented timeout logic and the event wait is then performed.
This "internal" timer only limits the wait time and should never be triggered.
It is deleted upon gdb_do_one_event exit.

The new parameter defaults to "no timeout" (-1): as it is used by Insight
only, there is no need to update calls from the gdb source tree.
This commit is contained in:
Patrick Monnerat 2022-07-15 17:18:32 +02:00
parent 8255dbf0dd
commit bac814af17
2 changed files with 36 additions and 11 deletions

View File

@ -33,6 +33,8 @@
#include <sys/types.h>
#include "gdbsupport/gdb_sys_time.h"
#include "gdbsupport/gdb_select.h"
#include "gdbsupport/gdb_optional.h"
#include "gdbsupport/scope-exit.h"
/* See event-loop.h. */
@ -175,12 +177,17 @@ static int update_wait_timeout (void);
static int poll_timers (void);
/* Process one high level event. If nothing is ready at this time,
wait for something to happen (via gdb_wait_for_event), then process
it. Returns >0 if something was done otherwise returns <0 (this
can happen if there are no event sources to wait for). */
wait at most MSTIMEOUT milliseconds for something to happen (via
gdb_wait_for_event), then process it. Returns >0 if something was
done, <0 if there are no event sources to wait for, =0 if timeout occurred.
A timeout of 0 allows to serve an already pending event, but does not
wait if none found.
Setting the timeout to a negative value disables it.
The timeout is never used by gdb itself, it is however needed to
integrate gdb event handling within Insight's GUI event loop. */
int
gdb_do_one_event (void)
gdb_do_one_event (int mstimeout)
{
static int event_source_head = 0;
const int number_of_sources = 3;
@ -227,17 +234,35 @@ gdb_do_one_event (void)
return 1;
}
if (!mstimeout)
return 0; /* Null timeout: do not wait for an event. */
/* Block waiting for a new event. If gdb_wait_for_event returns -1,
we should get out because this means that there are no event
sources left. This will make the event loop stop, and the
application exit. */
application exit.
If a timeout has been given, a new timer is set accordingly
to abort event wait. It is deleted upon gdb_wait_for_event
termination and thus should never be triggered.
When the timeout is reached, events are not monitored again:
they already have been checked in the loop above. */
if (gdb_wait_for_event (1) < 0)
return -1;
gdb::optional<int> timer_id;
/* If gdb_wait_for_event has returned 1, it means that one event has
been handled. We break out of the loop. */
return 1;
SCOPE_EXIT
{
if (timer_id.has_value ())
delete_timer (*timer_id);
};
if (mstimeout > 0)
timer_id = create_timer (mstimeout,
[] (gdb_client_data arg)
{
((gdb::optional<int> *) arg)->reset ();
},
&timer_id);
return gdb_wait_for_event (1);
}
/* See event-loop.h */

View File

@ -76,7 +76,7 @@ typedef void (timer_handler_func) (gdb_client_data);
/* Exported functions from event-loop.c */
extern int gdb_do_one_event (void);
extern int gdb_do_one_event (int mstimeout = -1);
extern void delete_file_handler (int fd);
/* Add a file handler/descriptor to the list of descriptors we are