X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fevent-loop.c;h=0442680c23793af9c6f117ed9030fcb19fafb841;hb=3d6e9d2336c9ffcedb10f89631981a23dd518e8e;hp=6471772e16478d3a07ca661ff4933233481bff09;hpb=8336d594d5107cb86bf1b569962bf1496e2c7c30;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/event-loop.c b/gdb/gdbserver/event-loop.c index 6471772e16..0442680c23 100644 --- a/gdb/gdbserver/event-loop.c +++ b/gdb/gdbserver/event-loop.c @@ -1,6 +1,5 @@ /* Event loop machinery for the remote server for GDB. - Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006, 2007, 2008, 2010 - Free Software Foundation, Inc. + Copyright (C) 1999-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -22,24 +21,17 @@ #include "server.h" #include -#include -#include +#include "common/gdb_sys_time.h" #ifdef USE_WIN32API #include #include #endif -#ifdef HAVE_ERRNO_H -#include -#endif - -#ifdef HAVE_UNISTD_H #include -#endif +#include -typedef struct gdb_event gdb_event; -typedef int (event_handler_func) (int); +typedef int (event_handler_func) (gdb_fildes_t); /* Tell create_file_handler what events we are interested in. */ @@ -47,7 +39,7 @@ typedef int (event_handler_func) (int); #define GDB_WRITABLE (1<<2) #define GDB_EXCEPTION (1<<3) -/* Events are queued by calling async_queue_event and serviced later +/* 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, @@ -64,10 +56,7 @@ struct gdb_event event_handler_func *proc; /* File descriptor that is ready. */ - int fd; - - /* Next in list of events or NULL. */ - struct gdb_event *next_event; + gdb_fildes_t fd; }; /* Information about each file descriptor we register with the event @@ -76,7 +65,7 @@ struct gdb_event typedef struct file_handler { /* File descriptor. */ - int fd; + gdb_fildes_t fd; /* Events we want to monitor. */ int mask; @@ -98,25 +87,9 @@ typedef struct file_handler } file_handler; -/* Event queue: - - Events can be inserted at the front of the queue or at the end of - the queue. Events will be extracted from the queue for processing - starting from the head. Therefore, events inserted at the head of - the queue will be processed in a last in first out fashion, while - those inserted at the tail of the queue will be processed in a - first in first out manner. All the fields are NULL if the queue is - empty. */ - -static struct - { - /* The first pending event. */ - gdb_event *first_event; +typedef gdb::unique_xmalloc_ptr gdb_event_up; - /* The last pending event. */ - gdb_event *last_event; - } -event_queue; +static std::queue> 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 @@ -141,25 +114,39 @@ static struct } gdb_notifier; -/* Insert an event object into the gdb event queue. +/* 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). - EVENT_PTR points to the event to be inserted into the queue. The - caller must allocate memory for the event. It is freed after the - event has ben handled. Events in the queue will be processed head - to tail, therefore, events will be processed first in first - out. */ + PROC will be executed before gdbserver goes to sleep to wait for the + next event. */ -static void -async_queue_event (gdb_event *event_ptr) -{ - /* The event will become the new last_event. */ +struct callback_event + { + int id; + callback_handler_func *proc; + gdb_client_data data; + struct callback_event *next; + }; - event_ptr->next_event = NULL; - if (event_queue.first_event == NULL) - event_queue.first_event = event_ptr; - else - event_queue.last_event->next_event = event_ptr; - event_queue.last_event = event_ptr; +/* 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 @@ -170,53 +157,100 @@ async_queue_event (gdb_event *event_ptr) static int process_event (void) { - gdb_event *event_ptr, *prev_ptr; - event_handler_func *proc; - int fd; + /* 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 (); - /* Look in the event queue to find an event that is ready - to be processed. */ + event_handler_func *proc = event_ptr->proc; + gdb_fildes_t fd = event_ptr->fd; - for (event_ptr = event_queue.first_event; - event_ptr != NULL; - event_ptr = event_ptr->next_event) - { - /* Call the handler for the event. */ + /* 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. */ - proc = event_ptr->proc; - fd = event_ptr->fd; +void +delete_callback_event (int id) +{ + struct callback_event **p; - /* 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. */ + for (p = &callback_list.first; *p != NULL; p = &(*p)->next) + { + struct callback_event *event_ptr = *p; - if (event_queue.first_event == event_ptr) + if (event_ptr->id == id) { - event_queue.first_event = event_ptr->next_event; - if (event_ptr->next_event == NULL) - event_queue.last_event = NULL; + *p = event_ptr->next; + if (event_ptr == callback_list.last) + callback_list.last = NULL; + free (event_ptr); + break; } - else - { - prev_ptr = event_queue.first_event; - while (prev_ptr->next_event != event_ptr) - prev_ptr = prev_ptr->next_event; + } +} - prev_ptr->next_event = event_ptr->next_event; - if (event_ptr->next_event == NULL) - event_queue.last_event = prev_ptr; - } - free (event_ptr); +/* 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. */ - /* Now call the procedure associated with the event. */ - if ((*proc) (fd)) +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; } - /* This is the case if there are no event on the event queue. */ return 0; } @@ -227,7 +261,7 @@ process_event (void) occurs for FD. CLIENT_DATA is the argument to pass to PROC. */ static void -create_file_handler (int fd, int mask, handler_func *proc, +create_file_handler (gdb_fildes_t fd, int mask, handler_func *proc, gdb_client_data client_data) { file_handler *file_ptr; @@ -244,7 +278,7 @@ create_file_handler (int fd, int mask, handler_func *proc, just change the data associated with it. */ if (file_ptr == NULL) { - file_ptr = xmalloc (sizeof (*file_ptr)); + file_ptr = XNEW (struct file_handler); file_ptr->fd = fd; file_ptr->ready_mask = 0; file_ptr->next_file = gdb_notifier.first_file_handler; @@ -277,7 +311,8 @@ create_file_handler (int fd, int mask, handler_func *proc, /* Wrapper function for create_file_handler. */ void -add_file_handler (int fd, handler_func *proc, gdb_client_data client_data) +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); } @@ -286,7 +321,7 @@ add_file_handler (int fd, handler_func *proc, gdb_client_data client_data) i.e. we don't care anymore about events on the FD. */ void -delete_file_handler (int fd) +delete_file_handler (gdb_fildes_t fd) { file_handler *file_ptr, *prev_ptr = NULL; int i; @@ -349,7 +384,7 @@ delete_file_handler (int fd) event in the front of the event queue. */ static int -handle_file_event (int event_file_desc) +handle_file_event (gdb_fildes_t event_file_desc) { file_handler *file_ptr; int mask; @@ -366,8 +401,8 @@ handle_file_event (int event_file_desc) if (file_ptr->ready_mask & GDB_EXCEPTION) { - fprintf (stderr, "Exception condition detected on fd %d\n", - file_ptr->fd); + warning ("Exception condition detected on fd %s", + pfildes (file_ptr->fd)); file_ptr->error = 1; } else @@ -397,13 +432,14 @@ handle_file_event (int event_file_desc) associated to FD when it was registered with the event loop. */ static gdb_event * -create_file_event (int fd) +create_file_event (gdb_fildes_t fd) { gdb_event *file_event_ptr; - file_event_ptr = xmalloc (sizeof (gdb_event)); + file_event_ptr = XNEW (gdb_event); file_event_ptr->proc = handle_file_event; file_event_ptr->fd = fd; + return file_event_ptr; } @@ -417,7 +453,6 @@ static int wait_for_event (void) { file_handler *file_ptr; - gdb_event *file_event_ptr; int num_found = 0; /* Make sure all output is done before getting another event. */ @@ -475,8 +510,9 @@ wait_for_event (void) if (file_ptr->ready_mask == 0) { - file_event_ptr = create_file_event (file_ptr->fd); - async_queue_event (file_event_ptr); + gdb_event *file_event_ptr = create_file_event (file_ptr->fd); + + event_queue.emplace (file_event_ptr); } file_ptr->ready_mask = mask; } @@ -507,6 +543,16 @@ start_event_loop (void) 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