[RFC][PATCH 1/2][PR cli/34409] gdb: event-loop: Rework poll's version of round robin
kurku <[email protected]> Wed, 22 Jul 2026 10:21:36 +0300
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
GDB had 2 implementations for round robin over file descriptors.
version for poll
version for select
poll version uses:
- std::vector index in gdb_notifier
- linked list from gdb_notifier
it does:
- circular scan over std::vector to find a slot
with revents filled in by the kernel
- additional linear scan of the linked list to find
the matched file_handler with the same fd
select version uses:
- linked list in gdb_notifier
it does:
- circular scan of the linked list
to find the node which has events
I can't find no clear reason to distinguish the two, or make the shape
of the code to be so vastly different. In both cases we do circular
linear scan over something and if flag of the fired event has been set -
we stop the scan and handle the event.
The only difference is the source of events. One comes directly from the
linked list. The other is from poll_fds std::vector.
Thus I propose to unify the shape of code paths. And unification would
be made on select's version because it already does the tracking of
events for select, we just need to extend it so that now revents issued
by poll api are accessible through the linked list.
( the real use case to do this change
is due to many readline macros hazards
I was trying to fix: gdb/34409 )
---
gdbsupport/event-loop.cc | 72 ++++++++++++++++++++++------------------
1 file changed, 39 insertions(+), 33 deletions(-)
diff --git a/gdbsupport/event-loop.cc b/gdbsupport/event-loop.cc
index c6e1b5b4634..deca3d86e5d 100644
--- a/gdbsupport/event-loop.cc
+++ b/gdbsupport/event-loop.cc
@@ -77,6 +77,11 @@ struct file_handler
/* Next registered file descriptor. */
struct file_handler *next_file;
+
+#ifdef HAVE_POLL
+ /* Reverse index from linked list into vector poll_fds vector */
+ int poll_fds_index;
+#endif
};
#ifdef HAVE_POLL
@@ -104,7 +109,7 @@ static struct
/* Ptr to head of file handler list. */
file_handler *first_file_handler;
- /* Next file handler to handle, for the select variant. To level
+ /* Next file handler to handle. To level
the fairness across event sources, we serve file handlers in a
round-robin-like fashion. The number and order of the polled
file handlers may change between invocations, but this is good
@@ -115,13 +120,6 @@ static struct
/* Descriptors to poll. */
std::vector<struct pollfd> poll_fds;
- /* Next file descriptor to handle, for the poll variant. To level
- the fairness across event sources, we poll the file descriptors
- in a round-robin-like fashion. The number and order of the
- polled file descriptors may change between invocations, but
- this is good enough. */
- int next_poll_fds_index;
-
/* Timeout in milliseconds for calls to poll(). */
int poll_timeout;
#endif
@@ -335,6 +333,7 @@ create_file_handler (int fd, int mask, handler_func * proc,
#ifdef HAVE_POLL
if (use_poll)
{
+ file_ptr->poll_fds_index = gdb_notifier.num_fds;
gdb_notifier.num_fds++;
struct pollfd new_fd;
new_fd.fd = fd;
@@ -420,13 +419,30 @@ delete_file_handler (int fd)
#ifdef HAVE_POLL
if (use_poll)
{
- auto iter = std::remove_if (gdb_notifier.poll_fds.begin (),
- gdb_notifier.poll_fds.end (),
- [=] (const pollfd &item)
- {
- return item.fd == fd;
- });
- gdb_notifier.poll_fds.erase (iter, gdb_notifier.poll_fds.end());
+ /* Swap last with the provided file_ptr in poll_fds vector
+ then do repair of a reverse index */
+
+ int i = file_ptr->poll_fds_index;
+ int j = gdb_notifier.num_fds - 1;
+
+ file_handler *i_ptr = file_ptr;
+ file_handler *j_ptr;
+
+ for (j_ptr = gdb_notifier.first_file_handler;
+ j_ptr != NULL;
+ j_ptr = j_ptr->next_file)
+ {
+ if (j_ptr->poll_fds_index == j)
+ break;
+ }
+
+ gdb_assert (i_ptr != NULL);
+ gdb_assert (j_ptr != NULL);
+
+ std::swap(gdb_notifier.poll_fds[i], gdb_notifier.poll_fds[j]);
+ std::swap(j_ptr->poll_fds_index, i_ptr->poll_fds_index);
+
+ gdb_notifier.poll_fds.pop_back();
gdb_notifier.num_fds--;
}
else
@@ -645,30 +661,20 @@ gdb_wait_for_event (int block)
#ifdef HAVE_POLL
if (use_poll)
{
- int i;
- int mask;
+ int mask = 0;
- while (1)
+ do
{
- if (gdb_notifier.next_poll_fds_index >= gdb_notifier.num_fds)
- gdb_notifier.next_poll_fds_index = 0;
- i = gdb_notifier.next_poll_fds_index++;
+ file_ptr = get_next_file_handler_to_handle_and_advance ();
- gdb_assert (i < gdb_notifier.num_fds);
- if (gdb_notifier.poll_fds[i].revents)
- break;
- }
+ int i = file_ptr->poll_fds_index;
+ short revents = gdb_notifier.poll_fds[i].revents;
- for (file_ptr = gdb_notifier.first_file_handler;
- file_ptr != NULL;
- file_ptr = file_ptr->next_file)
- {
- if (file_ptr->fd == gdb_notifier.poll_fds[i].fd)
- break;
+ if (revents)
+ mask |= revents;
}
- gdb_assert (file_ptr != NULL);
+ while (mask == 0);
- mask = gdb_notifier.poll_fds[i].revents;
handle_file_event (file_ptr, mask);
return 1;
}
--
2.43.0