2009-01-06 Sandra Loosemore <sandra@codesourcery.com>
gdb/ * ser-tcp.c: Adjust includes. (tcp_set_cmdlist, tcp_show_cmdlist): Declare. (tcp_auto_retry, tcp_retry_limit): Declare. (TIMEOUT): Remove, in favor of tcp_retry_limit. (POLL_INTERVAL): Increase to 5, in favor of backoff logic. (wait_for_connect): New function. (net_open): Use it. Add auto-retry logic. (set_tcp_cmd, show_tcp_cmd): New functions. (_initialize_ser_tcp): Initialize new "set/show tcp auto-retry" and "set/show tcp connect-timeout" commands. * NEWS: Document new commands. gdb/doc/ * gdb.texinfo (Remote Configuration): Document new "set/show tcp auto-retry" and "set/show tcp connect-timeout" commands.
This commit is contained in:
parent
1069ad51f4
commit
84603566b7
|
@ -1,3 +1,17 @@
|
|||
2009-01-06 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* ser-tcp.c: Adjust includes.
|
||||
(tcp_set_cmdlist, tcp_show_cmdlist): Declare.
|
||||
(tcp_auto_retry, tcp_retry_limit): Declare.
|
||||
(TIMEOUT): Remove, in favor of tcp_retry_limit.
|
||||
(POLL_INTERVAL): Increase to 5, in favor of backoff logic.
|
||||
(wait_for_connect): New function.
|
||||
(net_open): Use it. Add auto-retry logic.
|
||||
(set_tcp_cmd, show_tcp_cmd): New functions.
|
||||
(_initialize_ser_tcp): Initialize new "set/show tcp auto-retry"
|
||||
and "set/show tcp connect-timeout" commands.
|
||||
* NEWS: Document new commands.
|
||||
|
||||
2009-01-05 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* python/python-internal.h (Py_ssize_t): Define as int.
|
||||
|
|
8
gdb/NEWS
8
gdb/NEWS
|
@ -169,6 +169,14 @@ set target-async
|
|||
with GDB while the target is running. "show target-async" displays the
|
||||
current state of asynchronous execution of the target.
|
||||
|
||||
set tcp auto-retry (on|off)
|
||||
show tcp auto-retry
|
||||
set tcp connect-timeout
|
||||
show tcp connect-timeout
|
||||
These commands allow GDB to retry failed TCP connections to a remote stub
|
||||
with a specified timeout period; this is useful if the stub is launched
|
||||
in parallel with GDB but may not be ready to accept connections immediately.
|
||||
|
||||
macro define
|
||||
macro list
|
||||
macro undef
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2009-01-06 Sandra Loosemore <sandra@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Remote Configuration): Document new
|
||||
"set/show tcp auto-retry" and "set/show tcp connect-timeout"
|
||||
commands.
|
||||
|
||||
2008-12-28 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* gdbint.texinfo (gdbarch_cannot_fetch_register): Don't mention
|
||||
|
|
|
@ -14206,6 +14206,36 @@ Select the file used for @code{run} with @code{target
|
|||
extended-remote}. This should be set to a filename valid on the
|
||||
target system. If it is not set, the target will use a default
|
||||
filename (e.g.@: the last program run).
|
||||
|
||||
@kindex set tcp
|
||||
@kindex show tcp
|
||||
@item set tcp auto-retry on
|
||||
@cindex auto-retry, for remote TCP target
|
||||
Enable auto-retry for remote TCP connections. This is useful if the remote
|
||||
debugging agent is launched in parallel with @value{GDBN}; there is a race
|
||||
condition because the agent may not become ready to accept the connection
|
||||
before @value{GDBN} attempts to connect. When auto-retry is
|
||||
enabled, if the initial attempt to connect fails, @value{GDBN} reattempts
|
||||
to establish the connection using the timeout specified by
|
||||
@code{set tcp connect-timeout}.
|
||||
|
||||
@item set tcp auto-retry off
|
||||
Do not auto-retry failed TCP connections.
|
||||
|
||||
@item show tcp auto-retry
|
||||
Show the current auto-retry setting.
|
||||
|
||||
@item set tcp connect-timeout @var{seconds}
|
||||
@cindex connection timeout, for remote TCP target
|
||||
@cindex timeout, for remote target connection
|
||||
Set the timeout for establishing a TCP connection to the remote target to
|
||||
@var{seconds}. The timeout affects both polling to retry failed connections
|
||||
(enabled by @code{set tcp auto-retry on}) and waiting for connections
|
||||
that are merely slow to complete, and represents an approximate cumulative
|
||||
value.
|
||||
|
||||
@item show tcp connect-timeout
|
||||
Show the current connection timeout setting.
|
||||
@end table
|
||||
|
||||
@cindex remote packets, enabling and disabling
|
||||
|
|
234
gdb/ser-tcp.c
234
gdb/ser-tcp.c
|
@ -22,6 +22,9 @@
|
|||
#include "serial.h"
|
||||
#include "ser-base.h"
|
||||
#include "ser-tcp.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "cli/cli-decode.h"
|
||||
#include "cli/cli-setshow.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -49,6 +52,7 @@
|
|||
|
||||
#include <signal.h>
|
||||
#include "gdb_string.h"
|
||||
#include "gdb_select.h"
|
||||
|
||||
#ifndef HAVE_SOCKLEN_T
|
||||
typedef int socklen_t;
|
||||
|
@ -56,10 +60,93 @@ typedef int socklen_t;
|
|||
|
||||
void _initialize_ser_tcp (void);
|
||||
|
||||
/* seconds to wait for connect */
|
||||
#define TIMEOUT 15
|
||||
/* For "set tcp" and "show tcp". */
|
||||
|
||||
static struct cmd_list_element *tcp_set_cmdlist;
|
||||
static struct cmd_list_element *tcp_show_cmdlist;
|
||||
|
||||
/* Whether to auto-retry refused connections. */
|
||||
|
||||
static int tcp_auto_retry = 1;
|
||||
|
||||
/* Timeout period for connections, in seconds. */
|
||||
|
||||
static int tcp_retry_limit = 15;
|
||||
|
||||
/* how many times per second to poll deprecated_ui_loop_hook */
|
||||
#define POLL_INTERVAL 2
|
||||
|
||||
#define POLL_INTERVAL 5
|
||||
|
||||
/* Helper function to wait a while. If SCB is non-null, wait on its
|
||||
file descriptor. Otherwise just wait on a timeout, updating *POLLS.
|
||||
Returns -1 on timeout or interrupt, otherwise the value of select. */
|
||||
|
||||
static int
|
||||
wait_for_connect (struct serial *scb, int *polls)
|
||||
{
|
||||
struct timeval t;
|
||||
int n;
|
||||
|
||||
/* While we wait for the connect to complete,
|
||||
poll the UI so it can update or the user can
|
||||
interrupt. */
|
||||
if (deprecated_ui_loop_hook && deprecated_ui_loop_hook (0))
|
||||
{
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for timeout. */
|
||||
if (*polls > tcp_retry_limit * POLL_INTERVAL)
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Back off to polling once per second after the first POLL_INTERVAL
|
||||
polls. */
|
||||
if (*polls < POLL_INTERVAL)
|
||||
{
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 1000000 / POLL_INTERVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
t.tv_sec = 1;
|
||||
t.tv_usec = 0;
|
||||
}
|
||||
|
||||
if (scb)
|
||||
{
|
||||
fd_set rset, wset, eset;
|
||||
FD_ZERO (&rset);
|
||||
FD_SET (scb->fd, &rset);
|
||||
wset = rset;
|
||||
eset = rset;
|
||||
|
||||
/* POSIX systems return connection success or failure by signalling
|
||||
wset. Windows systems return success in wset and failure in
|
||||
eset.
|
||||
|
||||
We must call select here, rather than gdb_select, because
|
||||
the serial structure has not yet been initialized - the
|
||||
MinGW select wrapper will not know that this FD refers
|
||||
to a socket. */
|
||||
n = select (scb->fd + 1, &rset, &wset, &eset, &t);
|
||||
}
|
||||
else
|
||||
/* Use gdb_select here, since we have no file descriptors, and on
|
||||
Windows, plain select doesn't work in that case. */
|
||||
n = gdb_select (0, NULL, NULL, NULL, &t);
|
||||
|
||||
/* If we didn't time out, only count it as one poll. */
|
||||
if (n > 0 || *polls < POLL_INTERVAL)
|
||||
(*polls)++;
|
||||
else
|
||||
(*polls) += POLL_INTERVAL;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Open a tcp socket */
|
||||
|
||||
|
@ -76,6 +163,7 @@ net_open (struct serial *scb, const char *name)
|
|||
#else
|
||||
int ioarg;
|
||||
#endif
|
||||
int polls = 0;
|
||||
|
||||
use_udp = 0;
|
||||
if (strncmp (name, "udp:", 4) == 0)
|
||||
|
@ -108,6 +196,13 @@ net_open (struct serial *scb, const char *name)
|
|||
return -1;
|
||||
}
|
||||
|
||||
sockaddr.sin_family = PF_INET;
|
||||
sockaddr.sin_port = htons (port);
|
||||
memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
|
||||
sizeof (struct in_addr));
|
||||
|
||||
retry:
|
||||
|
||||
if (use_udp)
|
||||
scb->fd = socket (PF_INET, SOCK_DGRAM, 0);
|
||||
else
|
||||
|
@ -116,11 +211,6 @@ net_open (struct serial *scb, const char *name)
|
|||
if (scb->fd < 0)
|
||||
return -1;
|
||||
|
||||
sockaddr.sin_family = PF_INET;
|
||||
sockaddr.sin_port = htons (port);
|
||||
memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
|
||||
sizeof (struct in_addr));
|
||||
|
||||
/* set socket nonblocking */
|
||||
ioarg = 1;
|
||||
ioctl (scb->fd, FIONBIO, &ioarg);
|
||||
|
@ -128,68 +218,51 @@ net_open (struct serial *scb, const char *name)
|
|||
/* Use Non-blocking connect. connect() will return 0 if connected already. */
|
||||
n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
|
||||
|
||||
if (n < 0
|
||||
if (n < 0)
|
||||
{
|
||||
#ifdef USE_WIN32API
|
||||
int err = WSAGetLastError();
|
||||
#else
|
||||
int err = errno;
|
||||
#endif
|
||||
|
||||
/* Maybe we're waiting for the remote target to become ready to
|
||||
accept connections. */
|
||||
if (tcp_auto_retry
|
||||
#ifdef USE_WIN32API
|
||||
&& err == WSAECONNREFUSED
|
||||
#else
|
||||
&& err == ECONNREFUSED
|
||||
#endif
|
||||
&& wait_for_connect (NULL, &polls) >= 0)
|
||||
{
|
||||
close (scb->fd);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (
|
||||
#ifdef USE_WIN32API
|
||||
/* Under Windows, calling "connect" with a non-blocking socket
|
||||
results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */
|
||||
&& WSAGetLastError() != WSAEWOULDBLOCK
|
||||
err != WSAEWOULDBLOCK
|
||||
#else
|
||||
&& errno != EINPROGRESS
|
||||
err != EINPROGRESS
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef USE_WIN32API
|
||||
errno = WSAGetLastError();
|
||||
#endif
|
||||
errno = err;
|
||||
net_close (scb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
/* looks like we need to wait for the connect */
|
||||
struct timeval t;
|
||||
fd_set rset, wset, eset;
|
||||
int polls = 0;
|
||||
FD_ZERO (&rset);
|
||||
|
||||
do
|
||||
{
|
||||
/* While we wait for the connect to complete,
|
||||
poll the UI so it can update or the user can
|
||||
interrupt. */
|
||||
if (deprecated_ui_loop_hook)
|
||||
{
|
||||
if (deprecated_ui_loop_hook (0))
|
||||
{
|
||||
errno = EINTR;
|
||||
net_close (scb);
|
||||
return -1;
|
||||
n = wait_for_connect (scb, &polls);
|
||||
}
|
||||
}
|
||||
|
||||
FD_SET (scb->fd, &rset);
|
||||
wset = rset;
|
||||
eset = rset;
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 1000000 / POLL_INTERVAL;
|
||||
|
||||
/* POSIX systems return connection success or failure by signalling
|
||||
wset. Windows systems return success in wset and failure in
|
||||
eset.
|
||||
|
||||
We must call select here, rather than gdb_select, because
|
||||
the serial structure has not yet been initialized - the
|
||||
MinGW select wrapper will not know that this FD refers
|
||||
to a socket. */
|
||||
n = select (scb->fd + 1, &rset, &wset, &eset, &t);
|
||||
polls++;
|
||||
}
|
||||
while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
|
||||
if (n < 0 || polls > TIMEOUT * POLL_INTERVAL)
|
||||
while (n == 0);
|
||||
if (n < 0)
|
||||
{
|
||||
if (polls > TIMEOUT * POLL_INTERVAL)
|
||||
errno = ETIMEDOUT;
|
||||
net_close (scb);
|
||||
return -1;
|
||||
}
|
||||
|
@ -207,6 +280,18 @@ net_open (struct serial *scb, const char *name)
|
|||
res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len);
|
||||
if (res < 0 || err)
|
||||
{
|
||||
/* Maybe the target still isn't ready to accept the connection. */
|
||||
if (tcp_auto_retry
|
||||
#ifdef USE_WIN32API
|
||||
&& err == WSAECONNREFUSED
|
||||
#else
|
||||
&& err == ECONNREFUSED
|
||||
#endif
|
||||
&& wait_for_connect (NULL, &polls) >= 0)
|
||||
{
|
||||
close (scb->fd);
|
||||
goto retry;
|
||||
}
|
||||
if (err)
|
||||
errno = err;
|
||||
net_close (scb);
|
||||
|
@ -264,13 +349,27 @@ ser_tcp_send_break (struct serial *scb)
|
|||
return (serial_write (scb, "\377\363", 2));
|
||||
}
|
||||
|
||||
/* Support for "set tcp" and "show tcp" commands. */
|
||||
|
||||
static void
|
||||
set_tcp_cmd (char *args, int from_tty)
|
||||
{
|
||||
help_list (tcp_set_cmdlist, "set tcp ", -1, gdb_stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
show_tcp_cmd (char *args, int from_tty)
|
||||
{
|
||||
help_list (tcp_show_cmdlist, "show tcp ", -1, gdb_stdout);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_initialize_ser_tcp (void)
|
||||
{
|
||||
#ifdef USE_WIN32API
|
||||
/* Do nothing; the TCP serial operations will be initialized in
|
||||
ser-mingw.c. */
|
||||
return;
|
||||
#else
|
||||
struct serial_ops *ops;
|
||||
ops = XMALLOC (struct serial_ops);
|
||||
|
@ -297,4 +396,29 @@ _initialize_ser_tcp (void)
|
|||
ops->write_prim = net_write_prim;
|
||||
serial_add_interface (ops);
|
||||
#endif /* USE_WIN32API */
|
||||
|
||||
add_prefix_cmd ("tcp", class_maintenance, set_tcp_cmd, _("\
|
||||
TCP protocol specific variables\n\
|
||||
Configure variables specific to remote TCP connections"),
|
||||
&tcp_set_cmdlist, "set tcp ",
|
||||
0 /* allow-unknown */, &setlist);
|
||||
add_prefix_cmd ("tcp", class_maintenance, show_tcp_cmd, _("\
|
||||
TCP protocol specific variables\n\
|
||||
Configure variables specific to remote TCP connections"),
|
||||
&tcp_show_cmdlist, "show tcp ",
|
||||
0 /* allow-unknown */, &showlist);
|
||||
|
||||
add_setshow_boolean_cmd ("auto-retry", class_obscure,
|
||||
&tcp_auto_retry, _("\
|
||||
Set auto-retry on socket connect"), _("\
|
||||
Show auto-retry on socket connect"),
|
||||
NULL, NULL, NULL,
|
||||
&tcp_set_cmdlist, &tcp_show_cmdlist);
|
||||
|
||||
add_setshow_uinteger_cmd ("connect-timeout", class_obscure,
|
||||
&tcp_retry_limit, _("\
|
||||
Set timeout limit for socket connection"), _("\
|
||||
Show timeout limit for socket connection"),
|
||||
NULL, NULL, NULL,
|
||||
&tcp_set_cmdlist, &tcp_show_cmdlist);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue