(callback_list): New global.
(append_callback_event, delete_callback_event): New functions.
(process_callback): New function.
(start_event_loop): Call it.
* remote-utils.c (NOT_SCHEDULED): Define.
(readchar_buf, readchar_bufcnt, readchar_bufp): New static globals,
moved out of readchar.
(readchar): Rewrite. Call reschedule before returning.
(reset_readchar): New function.
(remote_close): Call it.
(process_remaining, reschedule): New functions.
* server.h (callback_handler_func): New typedef.
(append_callback_event, delete_callback_event): Declare.
+2010-05-03 Doug Evans <dje@google.com>
+
+ * event-loop.c (struct callback_event): New struct.
+ (callback_list): New global.
+ (append_callback_event, delete_callback_event): New functions.
+ (process_callback): New function.
+ (start_event_loop): Call it.
+ * remote-utils.c (NOT_SCHEDULED): Define.
+ (readchar_buf, readchar_bufcnt, readchar_bufp): New static globals,
+ moved out of readchar.
+ (readchar): Rewrite. Call reschedule before returning.
+ (reset_readchar): New function.
+ (remote_close): Call it.
+ (process_remaining, reschedule): New functions.
+ * server.h (callback_handler_func): New typedef.
+ (append_callback_event, delete_callback_event): Declare.
+
2010-05-03 Pedro Alves <pedro@codesourcery.com>
* proc-service.c (ps_pglobal_lookup): Use
}
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;
+
/* Insert an event object into the gdb event queue.
EVENT_PTR points to the event to be inserted into the queue. The
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;
+
+ event_ptr = xmalloc (sizeof (*event_ptr));
+ 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,
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
# define INVALID_DESCRIPTOR -1
#endif
+/* Extra value for readchar_callback. */
+enum {
+ /* The callback is currently not scheduled. */
+ NOT_SCHEDULED = -1
+};
+
+/* Status of the readchar callback.
+ Either NOT_SCHEDULED or the callback id. */
+static int readchar_callback = NOT_SCHEDULED;
+
static int readchar (void);
+static void reset_readchar (void);
+static void reschedule (void);
/* A cache entry for a successfully looked-up symbol. */
struct sym_cache
close (remote_desc);
#endif
remote_desc = INVALID_DESCRIPTOR;
+
+ reset_readchar ();
}
/* Convert hex digit A to a number. */
unblock_async_io ();
}
+/* Internal buffer used by readchar.
+ These are global to readchar because reschedule_remote needs to be
+ able to tell whether the buffer is empty. */
+
+static unsigned char readchar_buf[BUFSIZ];
+static int readchar_bufcnt = 0;
+static unsigned char *readchar_bufp;
+
/* Returns next char from remote GDB. -1 if error. */
static int
readchar (void)
{
- static unsigned char buf[BUFSIZ];
- static int bufcnt = 0;
- static unsigned char *bufp;
+ int ch;
- if (bufcnt-- > 0)
- return *bufp++;
+ if (readchar_bufcnt == 0)
+ {
+ readchar_bufcnt = read (remote_desc, readchar_buf, sizeof (readchar_buf));
- bufcnt = read (remote_desc, buf, sizeof (buf));
+ if (readchar_bufcnt <= 0)
+ {
+ if (readchar_bufcnt == 0)
+ fprintf (stderr, "readchar: Got EOF\n");
+ else
+ perror ("readchar");
- if (bufcnt <= 0)
- {
- if (bufcnt == 0)
- fprintf (stderr, "readchar: Got EOF\n");
- else
- perror ("readchar");
+ return -1;
+ }
- return -1;
+ readchar_bufp = readchar_buf;
}
- bufp = buf;
- bufcnt--;
- return *bufp++;
+ readchar_bufcnt--;
+ ch = *readchar_bufp++;
+ reschedule ();
+ return ch;
+}
+
+/* Reset the readchar state machine. */
+
+static void
+reset_readchar (void)
+{
+ readchar_bufcnt = 0;
+ if (readchar_callback != NOT_SCHEDULED)
+ {
+ delete_callback_event (readchar_callback);
+ readchar_callback = NOT_SCHEDULED;
+ }
+}
+
+/* Process remaining data in readchar_buf. */
+
+static int
+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;
+}
+
+/* If there is still data in the buffer, queue another event to process it,
+ we can't sleep in select yet. */
+
+static void
+reschedule (void)
+{
+ if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED)
+ readchar_callback = append_callback_event (process_remaining, NULL);
}
/* Read a packet from the remote machine, with error checking,
/* Functions from event-loop.c. */
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 (int fd);
extern void add_file_handler (int 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);