[RFC 13/17] Switch gdbserver to common event loop

Tom Tromey
2019-02-24T16:52:10Z

This changes gdbserver to use the common event loop, removing the
ancient fork.

gdb/gdbserver/ChangeLog
2019-02-24 Tom Tromey <tom@tromey.com>

* server.h (handle_serial_event, handle_target_event): Update.
* server.c: Don't call initialize_event_loop.
(handle_serial_event): Return void. Call stop_event_loop.
(handle_target_event): Return void.
* remote-utils.c (handle_accept_event): Return void.
(reset_readchar): Use delete_timer.
(process_remaining): Return void.
(reschedule): Use create_timer.
* event-loop.h: Remove.
* event-loop.c: Remove.
* Makefile.in (OBS): Use common/event-loop.o, not event-loop.o.
---
gdb/gdbserver/ChangeLog | 14 +
gdb/gdbserver/Makefile.in | 2 +-
gdb/gdbserver/event-loop.c | 567 -----------------------------------
gdb/gdbserver/event-loop.h | 36 ---
gdb/gdbserver/remote-utils.c | 18 +-
gdb/gdbserver/server.c | 14 +-
gdb/gdbserver/server.h | 6 +-
7 files changed, 29 insertions(+), 628 deletions(-)
delete mode 100644 gdb/gdbserver/event-loop.c
delete mode 100644 gdb/gdbserver/event-loop.h

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index f5fc55034ee..66a5940b4ce 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -250,6 +250,7 @@ OBS = \
common/common-utils.o \
common/errors.o \
common/environ.o \
+ common/event-loop.o \
common/fileio.o \
common/filestuff.o \
common/format.o \
@@ -268,7 +269,6 @@ OBS = \
common/xml-utils.o \
debug.o \
dll.o \
- event-loop.o \
hostio.o \
inferiors.o \
mem-break.o \
diff --git a/gdb/gdbserver/event-loop.c b/gdb/gdbserver/event-loop.c
deleted file mode 100644
index 0442680c237..00000000000
--- a/gdb/gdbserver/event-loop.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/* Event loop machinery for the remote server for GDB.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Based on src/gdb/event-loop.c. */
-
-#include "server.h"
-
-#include <sys/types.h>
-#include "common/gdb_sys_time.h"
-
-#ifdef USE_WIN32API
-#include <windows.h>
-#include <io.h>
-#endif
-
-#include <unistd.h>
-#include <queue>
-
-typedef int (event_handler_func) (gdb_fildes_t);
-
-/* Tell create_file_handler what events we are interested in. */
-
-#define GDB_READABLE (1<<1)
-#define GDB_WRITABLE (1<<2)
-#define GDB_EXCEPTION (1<<3)
-
-/* Events are queued by on the event_queue and serviced later
- on by do_one_event. An event can be, for instance, a file
- descriptor becoming ready to be read. Servicing an event simply
- means that the procedure PROC will be called. We have 2 queues,
- one for file handlers that we listen to in the event loop, and one
- for the file handlers+events that are ready. The procedure PROC
- associated with each event is always the same (handle_file_event).
- Its duty is to invoke the handler associated with the file
- descriptor whose state change generated the event, plus doing other
- cleanups and such. */
-
-struct gdb_event
- {
- /* Procedure to call to service this event. */
- event_handler_func *proc;
-
- /* File descriptor that is ready. */
- gdb_fildes_t fd;
- };
-
-/* Information about each file descriptor we register with the event
- loop. */
-
-typedef struct file_handler
- {
- /* File descriptor. */
- gdb_fildes_t fd;
-
- /* Events we want to monitor. */
- int mask;
-
- /* Events that have been seen since the last time. */
- int ready_mask;
-
- /* Procedure to call when fd is ready. */
- handler_func *proc;
-
- /* Argument to pass to proc. */
- gdb_client_data client_data;
-
- /* Was an error detected on this fd? */
- int error;
-
- /* Next registered file descriptor. */
- struct file_handler *next_file;
- }
-file_handler;
-
-typedef gdb::unique_xmalloc_ptr<gdb_event> gdb_event_up;
-
-static std::queue<gdb_event_up, std::list<gdb_event_up>> event_queue;
-
-/* Gdb_notifier is just a list of file descriptors gdb is interested
- in. These are the input file descriptor, and the target file
- descriptor. Each of the elements in the gdb_notifier list is
- basically a description of what kind of events gdb is interested
- in, for each fd. */
-
-static struct
- {
- /* Ptr to head of file handler list. */
- file_handler *first_file_handler;
-
- /* Masks to be used in the next call to select. Bits are set in
- response to calls to create_file_handler. */
- fd_set check_masks[3];
-
- /* What file descriptors were found ready by select. */
- fd_set ready_masks[3];
-
- /* Number of valid bits (highest fd value + 1). (for select) */
- int num_fds;
- }
-gdb_notifier;
-
-/* Callbacks are just routines that are executed before waiting for the
- next event. In GDB this is struct gdb_timer. We don't need timers
- so rather than copy all that complexity in gdbserver, we provide what
- we need, but we do so in a way that if/when the day comes that we need
- that complexity, it'll be easier to add - replace callbacks with timers
- and use a delta of zero (which is all gdb currently uses timers for anyway).
-
- PROC will be executed before gdbserver goes to sleep to wait for the
- next event. */
-
-struct callback_event
- {
- int id;
- callback_handler_func *proc;
- gdb_client_data data;
- struct callback_event *next;
- };
-
-/* Table of registered callbacks. */
-
-static struct
- {
- struct callback_event *first;
- struct callback_event *last;
-
- /* Id of the last callback created. */
- int num_callbacks;
- }
-callback_list;
-
-void
-initialize_event_loop (void)
-{
-}
-
-/* Process one event. If an event was processed, 1 is returned
- otherwise 0 is returned. Scan the queue from head to tail,
- processing therefore the high priority events first, by invoking
- the associated event handler procedure. */
-
-static int
-process_event (void)
-{
- /* Let's get rid of the event from the event queue. We need to
- do this now because while processing the event, since the
- proc function could end up jumping out to the caller of this
- function. In that case, we would have on the event queue an
- event which has been processed, but not deleted. */
- if (!event_queue.empty ())
- {
- gdb_event_up event_ptr = std::move (event_queue.front ());
- event_queue.pop ();
-
- event_handler_func *proc = event_ptr->proc;
- gdb_fildes_t fd = event_ptr->fd;
-
- /* Now call the procedure associated with the event. */
- if ((*proc) (fd))
- return -1;
- return 1;
- }
-
- /* This is the case if there are no event on the event queue. */
- return 0;
-}
-
-/* Append PROC to the callback list.
- The result is the "id" of the callback that can be passed back to
- delete_callback_event. */
-
-int
-append_callback_event (callback_handler_func *proc, gdb_client_data data)
-{
- struct callback_event *event_ptr = XNEW (struct callback_event);
-
- event_ptr->id = callback_list.num_callbacks++;
- event_ptr->proc = proc;
- event_ptr->data = data;
- event_ptr->next = NULL;
- if (callback_list.first == NULL)
- callback_list.first = event_ptr;
- if (callback_list.last != NULL)
- callback_list.last->next = event_ptr;
- callback_list.last = event_ptr;
- return event_ptr->id;
-}
-
-/* Delete callback ID.
- It is not an error callback ID doesn't exist. */
-
-void
-delete_callback_event (int id)
-{
- struct callback_event **p;
-
- for (p = &callback_list.first; *p != NULL; p = &(*p)->next)
- {
- struct callback_event *event_ptr = *p;
-
- if (event_ptr->id == id)
- {
- *p = event_ptr->next;
- if (event_ptr == callback_list.last)
- callback_list.last = NULL;
- free (event_ptr);
- break;
- }
- }
-}
-
-/* Run the next callback.
- The result is 1 if a callback was called and event processing
- should continue, -1 if the callback wants the event loop to exit,
- and 0 if there are no more callbacks. */
-
-static int
-process_callback (void)
-{
- struct callback_event *event_ptr;
-
- event_ptr = callback_list.first;
- if (event_ptr != NULL)
- {
- callback_handler_func *proc = event_ptr->proc;
- gdb_client_data data = event_ptr->data;
-
- /* Remove the event before calling PROC,
- more events may get added by PROC. */
- callback_list.first = event_ptr->next;
- if (callback_list.first == NULL)
- callback_list.last = NULL;
- free (event_ptr);
- if ((*proc) (data))
- return -1;
- return 1;
- }
-
- return 0;
-}
-
-/* Add a file handler/descriptor to the list of descriptors we are
- interested in. FD is the file descriptor for the file/stream to be
- listened to. MASK is a combination of READABLE, WRITABLE,
- EXCEPTION. PROC is the procedure that will be called when an event
- occurs for FD. CLIENT_DATA is the argument to pass to PROC. */
-
-static void
-create_file_handler (gdb_fildes_t fd, int mask, handler_func *proc,
- gdb_client_data client_data)
-{
- file_handler *file_ptr;
-
- /* Do we already have a file handler for this file? (We may be
- changing its associated procedure). */
- for (file_ptr = gdb_notifier.first_file_handler;
- file_ptr != NULL;
- file_ptr = file_ptr->next_file)
- if (file_ptr->fd == fd)
- break;
-
- /* It is a new file descriptor. Add it to the list. Otherwise,
- just change the data associated with it. */
- if (file_ptr == NULL)
- {
- file_ptr = XNEW (struct file_handler);
- file_ptr->fd = fd;
- file_ptr->ready_mask = 0;
- file_ptr->next_file = gdb_notifier.first_file_handler;
- gdb_notifier.first_file_handler = file_ptr;
-
- if (mask & GDB_READABLE)
- FD_SET (fd, &gdb_notifier.check_masks[0]);
- else
- FD_CLR (fd, &gdb_notifier.check_masks[0]);
-
- if (mask & GDB_WRITABLE)
- FD_SET (fd, &gdb_notifier.check_masks[1]);
- else
- FD_CLR (fd, &gdb_notifier.check_masks[1]);
-
- if (mask & GDB_EXCEPTION)
- FD_SET (fd, &gdb_notifier.check_masks[2]);
- else
- FD_CLR (fd, &gdb_notifier.check_masks[2]);
-
- if (gdb_notifier.num_fds <= fd)
- gdb_notifier.num_fds = fd + 1;
- }
-
- file_ptr->proc = proc;
- file_ptr->client_data = client_data;
- file_ptr->mask = mask;
-}
-
-/* Wrapper function for create_file_handler. */
-
-void
-add_file_handler (gdb_fildes_t fd,
- handler_func *proc, gdb_client_data client_data)
-{
- create_file_handler (fd, GDB_READABLE | GDB_EXCEPTION, proc, client_data);
-}
-
-/* Remove the file descriptor FD from the list of monitored fd's:
- i.e. we don't care anymore about events on the FD. */
-
-void
-delete_file_handler (gdb_fildes_t fd)
-{
- file_handler *file_ptr, *prev_ptr = NULL;
- int i;
-
- /* Find the entry for the given file. */
-
- for (file_ptr = gdb_notifier.first_file_handler;
- file_ptr != NULL;
- file_ptr = file_ptr->next_file)
- if (file_ptr->fd == fd)
- break;
-
- if (file_ptr == NULL)
- return;
-
- if (file_ptr->mask & GDB_READABLE)
- FD_CLR (fd, &gdb_notifier.check_masks[0]);
- if (file_ptr->mask & GDB_WRITABLE)
- FD_CLR (fd, &gdb_notifier.check_masks[1]);
- if (file_ptr->mask & GDB_EXCEPTION)
- FD_CLR (fd, &gdb_notifier.check_masks[2]);
-
- /* Find current max fd. */
-
- if ((fd + 1) == gdb_notifier.num_fds)
- {
- gdb_notifier.num_fds--;
- for (i = gdb_notifier.num_fds; i; i--)
- {
- if (FD_ISSET (i - 1, &gdb_notifier.check_masks[0])
- || FD_ISSET (i - 1, &gdb_notifier.check_masks[1])
- || FD_ISSET (i - 1, &gdb_notifier.check_masks[2]))
- break;
- }
- gdb_notifier.num_fds = i;
- }
-
- /* Deactivate the file descriptor, by clearing its mask, so that it
- will not fire again. */
-
- file_ptr->mask = 0;
-
- /* Get rid of the file handler in the file handler list. */
- if (file_ptr == gdb_notifier.first_file_handler)
- gdb_notifier.first_file_handler = file_ptr->next_file;
- else
- {
- for (prev_ptr = gdb_notifier.first_file_handler;
- prev_ptr->next_file != file_ptr;
- prev_ptr = prev_ptr->next_file)
- ;
- prev_ptr->next_file = file_ptr->next_file;
- }
- free (file_ptr);
-}
-
-/* Handle the given event by calling the procedure associated to the
- corresponding file handler. Called by process_event indirectly,
- through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the
- event in the front of the event queue. */
-
-static int
-handle_file_event (gdb_fildes_t event_file_desc)
-{
- file_handler *file_ptr;
- int mask;
-
- /* Search the file handler list to find one that matches the fd in
- the event. */
- for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
- file_ptr = file_ptr->next_file)
- {
- if (file_ptr->fd == event_file_desc)
- {
- /* See if the desired events (mask) match the received
- events (ready_mask). */
-
- if (file_ptr->ready_mask & GDB_EXCEPTION)
- {
- warning ("Exception condition detected on fd %s",
- pfildes (file_ptr->fd));
- file_ptr->error = 1;
- }
- else
- file_ptr->error = 0;
- mask = file_ptr->ready_mask & file_ptr->mask;
-
- /* Clear the received events for next time around. */
- file_ptr->ready_mask = 0;
-
- /* If there was a match, then call the handler. */
- if (mask != 0)
- {
- if ((*file_ptr->proc) (file_ptr->error,
- file_ptr->client_data) < 0)
- return -1;
- }
- break;
- }
- }
-
- return 0;
-}
-
-/* Create a file event, to be enqueued in the event queue for
- processing. The procedure associated to this event is always
- handle_file_event, which will in turn invoke the one that was
- associated to FD when it was registered with the event loop. */
-
-static gdb_event *
-create_file_event (gdb_fildes_t fd)
-{
- gdb_event *file_event_ptr;
-
- file_event_ptr = XNEW (gdb_event);
- file_event_ptr->proc = handle_file_event;
- file_event_ptr->fd = fd;
-
- return file_event_ptr;
-}
-
-/* Called by do_one_event to wait for new events on the monitored file
- descriptors. Queue file events as they are detected by the poll.
- If there are no events, this function will block in the call to
- select. Return -1 if there are no files descriptors to monitor,
- otherwise return 0. */
-
-static int
-wait_for_event (void)
-{
- file_handler *file_ptr;
- int num_found = 0;
-
- /* Make sure all output is done before getting another event. */
- fflush (stdout);
- fflush (stderr);
-
- if (gdb_notifier.num_fds == 0)
- return -1;
-
- gdb_notifier.ready_masks[0] = gdb_notifier.check_masks[0];
- gdb_notifier.ready_masks[1] = gdb_notifier.check_masks[1];
- gdb_notifier.ready_masks[2] = gdb_notifier.check_masks[2];
- num_found = select (gdb_notifier.num_fds,
- &gdb_notifier.ready_masks[0],
- &gdb_notifier.ready_masks[1],
- &gdb_notifier.ready_masks[2],
- NULL);
-
- /* Clear the masks after an error from select. */
- if (num_found == -1)
- {
- FD_ZERO (&gdb_notifier.ready_masks[0]);
- FD_ZERO (&gdb_notifier.ready_masks[1]);
- FD_ZERO (&gdb_notifier.ready_masks[2]);
-#ifdef EINTR
- /* Dont print anything if we got a signal, let gdb handle
- it. */
- if (errno != EINTR)
- perror_with_name ("select");
-#endif
- }
-
- /* Enqueue all detected file events. */
-
- for (file_ptr = gdb_notifier.first_file_handler;
- file_ptr != NULL && num_found > 0;
- file_ptr = file_ptr->next_file)
- {
- int mask = 0;
-
- if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[0]))
- mask |= GDB_READABLE;
- if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[1]))
- mask |= GDB_WRITABLE;
- if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[2]))
- mask |= GDB_EXCEPTION;
-
- if (!mask)
- continue;
- else
- num_found--;
-
- /* Enqueue an event only if this is still a new event for this
- fd. */
-
- if (file_ptr->ready_mask == 0)
- {
- gdb_event *file_event_ptr = create_file_event (file_ptr->fd);
-
- event_queue.emplace (file_event_ptr);
- }
- file_ptr->ready_mask = mask;
- }
-
- return 0;
-}
-
-/* Start up the event loop. This is the entry point to the event
- loop. */
-
-void
-start_event_loop (void)
-{
- /* Loop until there is nothing to do. This is the entry point to
- the event loop engine. If nothing is ready at this time, wait
- for something to happen (via wait_for_event), then process it.
- Return when there are no longer event sources to wait for. */
-
- while (1)
- {
- /* Any events already waiting in the queue? */
- int res = process_event ();
-
- /* Did the event handler want the event loop to stop? */
- if (res == -1)
- return;
-
- if (res)
- continue;
-
- /* Process any queued callbacks before we go to sleep. */
- res = process_callback ();
-
- /* Did the callback want the event loop to stop? */
- if (res == -1)
- return;
-
- if (res)
- continue;
-
- /* Wait for a new event. If 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. */
-
- if (wait_for_event () < 0)
- return;
- }
-
- /* We are done with the event loop. There are no more event sources
- to listen to. So we exit gdbserver. */
-}
diff --git a/gdb/gdbserver/event-loop.h b/gdb/gdbserver/event-loop.h
deleted file mode 100644
index a09a6ad4355..00000000000
--- a/gdb/gdbserver/event-loop.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Event loop machinery for the remote server for GDB.
- Copyright (C) 1993-2019 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef GDBSERVER_EVENT_LOOP_H
-#define GDBSERVER_EVENT_LOOP_H
-
-typedef void *gdb_client_data;
-typedef int (handler_func) (int, gdb_client_data);
-typedef int (callback_handler_func) (gdb_client_data);
-
-extern void delete_file_handler (gdb_fildes_t fd);
-extern void add_file_handler (gdb_fildes_t fd, handler_func *proc,
- gdb_client_data client_data);
-extern int append_callback_event (callback_handler_func *proc,
- gdb_client_data client_data);
-extern void delete_callback_event (int id);
-
-extern void start_event_loop (void);
-extern void initialize_event_loop (void);
-
-#endif /* GDBSERVER_EVENT_LOOP_H */
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index ad0228db99c..bda261a4a9f 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -150,7 +150,7 @@ enable_async_notification (int fd)
#endif
}

-static int
+static void
handle_accept_event (int err, gdb_client_data client_data)
{
struct sockaddr_storage sockaddr;
@@ -219,8 +219,6 @@ handle_accept_event (int err, gdb_client_data client_data)
until GDB as selected all-stop/non-stop, and has queried the
threads' status ('?'). */
target_async (0);
-
- return 0;
}

/* Prepare for a later connection to a remote debugger.
@@ -936,27 +934,21 @@ reset_readchar (void)
readchar_bufcnt = 0;
if (readchar_callback != NOT_SCHEDULED)
{
- delete_callback_event (readchar_callback);
+ delete_timer (readchar_callback);
readchar_callback = NOT_SCHEDULED;
}
}

/* Process remaining data in readchar_buf. */

-static int
+static void
process_remaining (void *context)
{
- int res;
-
/* This is a one-shot event. */
readchar_callback = NOT_SCHEDULED;

if (readchar_bufcnt > 0)
- res = handle_serial_event (0, NULL);
- else
- res = 0;
-
- return res;
+ handle_serial_event (0, NULL);
}

/* If there is still data in the buffer, queue another event to process it,
@@ -966,7 +958,7 @@ static void
reschedule (void)
{
if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED)
- readchar_callback = append_callback_event (process_remaining, NULL);
+ readchar_callback = create_timer (0, process_remaining, NULL);
}

/* Read a packet from the remote machine, with error checking,
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 1b2b86813fb..42147c1d836 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -3785,7 +3785,6 @@ captured_main (int argc, char *argv[])
initialize_async_io ();
initialize_low ();
have_job_control ();
- initialize_event_loop ();
if (target_supports_tracepoints ())
initialize_tracepoint ();
initialize_notif ();
@@ -4390,7 +4389,7 @@ process_serial_event (void)

/* Event-loop callback for serial events. */

-int
+void
handle_serial_event (int err, gdb_client_data client_data)
{
if (debug_threads)
@@ -4398,13 +4397,14 @@ handle_serial_event (int err, gdb_client_data client_data)

/* Really handle it. */
if (process_serial_event () < 0)
- return -1;
+ {
+ stop_event_loop ();
+ return;
+ }

/* Be sure to not change the selected thread behind GDB's back.
Important in the non-stop mode asynchronous protocol. */
set_desired_thread ();
-
- return 0;
}

/* Push a stop notification on the notification queue. */
@@ -4422,7 +4422,7 @@ push_stop_notification (ptid_t ptid, struct target_waitstatus *status)

/* Event-loop callback for target events. */

-int
+void
handle_target_event (int err, gdb_client_data client_data)
{
client_state &cs = get_client_state ();
@@ -4499,8 +4499,6 @@ handle_target_event (int err, gdb_client_data client_data)
/* Be sure to not change the selected thread behind GDB's back.
Important in the non-stop mode asynchronous protocol. */
set_desired_thread ();
-
- return 0;
}

/* See common/event-loop.h. */
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 400001addd3..5b359c8bae0 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -85,13 +85,13 @@ typedef SOCKET gdb_fildes_t;
typedef int gdb_fildes_t;
#endif

-#include "event-loop.h"
+#include "common/event-loop.h"

/* Functions from server.c. */
extern void handle_v_requests (char *own_buf, int packet_len,
int *new_packet_len);
-extern int handle_serial_event (int err, gdb_client_data client_data);
-extern int handle_target_event (int err, gdb_client_data client_data);
+extern void handle_serial_event (int err, gdb_client_data client_data);
+extern void handle_target_event (int err, gdb_client_data client_data);

/* Get rid of the currently pending stop replies that match PTID. */
extern void discard_queued_stop_replies (ptid_t ptid);
--
2.17.2