* 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.
This commit is contained in:
Doug Evans
2010-05-03 20:53:21 +00:00
parent 1ac77ea163
commit 24b066ba2b
4 changed files with 217 additions and 17 deletions

View File

@ -1,3 +1,20 @@
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> 2010-05-03 Pedro Alves <pedro@codesourcery.com>
* proc-service.c (ps_pglobal_lookup): Use * proc-service.c (ps_pglobal_lookup): Use

View File

@ -141,6 +141,36 @@ static struct
} }
gdb_notifier; 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. /* Insert an event object into the gdb event queue.
EVENT_PTR points to the event to be inserted into the queue. The EVENT_PTR points to the event to be inserted into the queue. The
@ -220,6 +250,81 @@ process_event (void)
return 0; 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 /* 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 interested in. FD is the file descriptor for the file/stream to be
listened to. MASK is a combination of READABLE, WRITABLE, listened to. MASK is a combination of READABLE, WRITABLE,
@ -507,6 +612,16 @@ start_event_loop (void)
if (res) if (res)
continue; 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 /* Wait for a new event. If wait_for_event returns -1, we
should get out because this means that there are no event should get out because this means that there are no event
sources left. This will make the event loop stop, and the sources left. This will make the event loop stop, and the

View File

@ -80,7 +80,19 @@ typedef int socklen_t;
# define INVALID_DESCRIPTOR -1 # define INVALID_DESCRIPTOR -1
#endif #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 int readchar (void);
static void reset_readchar (void);
static void reschedule (void);
/* A cache entry for a successfully looked-up symbol. */ /* A cache entry for a successfully looked-up symbol. */
struct sym_cache struct sym_cache
@ -341,6 +353,8 @@ remote_close (void)
close (remote_desc); close (remote_desc);
#endif #endif
remote_desc = INVALID_DESCRIPTOR; remote_desc = INVALID_DESCRIPTOR;
reset_readchar ();
} }
/* Convert hex digit A to a number. */ /* Convert hex digit A to a number. */
@ -926,33 +940,83 @@ initialize_async_io (void)
unblock_async_io (); 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. */ /* Returns next char from remote GDB. -1 if error. */
static int static int
readchar (void) readchar (void)
{ {
static unsigned char buf[BUFSIZ]; int ch;
static int bufcnt = 0;
static unsigned char *bufp;
if (bufcnt-- > 0) if (readchar_bufcnt == 0)
return *bufp++;
bufcnt = read (remote_desc, buf, sizeof (buf));
if (bufcnt <= 0)
{ {
if (bufcnt == 0) readchar_bufcnt = read (remote_desc, readchar_buf, sizeof (readchar_buf));
fprintf (stderr, "readchar: Got EOF\n");
else
perror ("readchar");
return -1; if (readchar_bufcnt <= 0)
{
if (readchar_bufcnt == 0)
fprintf (stderr, "readchar: Got EOF\n");
else
perror ("readchar");
return -1;
}
readchar_bufp = readchar_buf;
} }
bufp = buf; readchar_bufcnt--;
bufcnt--; ch = *readchar_bufp++;
return *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, /* Read a packet from the remote machine, with error checking,

View File

@ -333,10 +333,14 @@ extern int non_stop;
/* Functions from event-loop.c. */ /* Functions from event-loop.c. */
typedef void *gdb_client_data; typedef void *gdb_client_data;
typedef int (handler_func) (int, 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 delete_file_handler (int fd);
extern void add_file_handler (int fd, handler_func *proc, extern void add_file_handler (int fd, handler_func *proc,
gdb_client_data client_data); 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 start_event_loop (void);