mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-13 16:38:14 +00:00
Add new --timeout flag to emacsclient
* lib-src/emacsclient.c (DEFAULT_TIMEOUT): New constant. (timeout): New static variable. (longopts, shortopts, decode_options, print_help_and_exit): Add new flag --timeout. (set_socket_timeout, check_socket_timeout): New helper functions. (main): Display a status message or exit after Emacs has not responded for a while, depending on above new --timeout flag. (Bug#50849) * doc/emacs/misc.texi (emacsclient Options): * doc/man/emacsclient.1: Document the above new option. * etc/NEWS: Announce it.
This commit is contained in:
parent
b648634982
commit
6a19f2a024
@ -2089,6 +2089,13 @@ all server buffers are finished. You can take as long as you like to
|
||||
edit the server buffers within Emacs, and they are @emph{not} killed
|
||||
when you type @kbd{C-x #} in them.
|
||||
|
||||
@item -w
|
||||
@itemx --timeout=@var{N}
|
||||
Wait for a response from Emacs for @var{N} seconds before giving up.
|
||||
If there is no response within that time, @command{emacsclient} will
|
||||
display a warning and exit. The default is @samp{0}, which means to
|
||||
wait forever.
|
||||
|
||||
@item --parent-id @var{id}
|
||||
Open an @command{emacsclient} frame as a client frame in the parent X
|
||||
window with id @var{id}, via the XEmbed protocol. Currently, this
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" See section COPYING for conditions for redistribution.
|
||||
.TH EMACSCLIENT 1 "2021-11-05" "GNU Emacs" "GNU"
|
||||
.TH EMACSCLIENT 1 "2022-09-05" "GNU Emacs" "GNU"
|
||||
.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
|
||||
.\" other params are allowed: see man(7), man(1)
|
||||
.SH NAME
|
||||
@ -87,9 +87,12 @@ Use TCP configuration file FILENAME for communication.
|
||||
This can also be specified via the EMACS_SERVER_FILE environment variable.
|
||||
.TP
|
||||
.B \-n, \-\-no-wait
|
||||
Return
|
||||
immediately without waiting for you to "finish" the buffer in Emacs.
|
||||
If combined with --eval, this option is ignored.
|
||||
Return immediately without waiting for you to "finish" the buffer in
|
||||
Emacs. If combined with --eval, this option is ignored.
|
||||
.TP
|
||||
.B \-w, \-\-timeout=N
|
||||
How long to wait, in seconds, for Emacs to respond before giving up.
|
||||
The default is 0, which means to wait forever.
|
||||
.TP
|
||||
.B \-nw, \-t, \-\-tty
|
||||
Open a new Emacs frame on the current terminal.
|
||||
|
7
etc/NEWS
7
etc/NEWS
@ -1003,10 +1003,15 @@ suspicious and could be malicious.
|
||||
** Emacs server and client changes
|
||||
|
||||
+++
|
||||
*** New command-line option '-r' for emacsclient.
|
||||
*** New command-line option '-r'/'--reuse-frame' for emacsclient.
|
||||
With this command-line option, Emacs reuses an existing graphical client
|
||||
frame if one exists; otherwise it creates a new frame.
|
||||
|
||||
+++
|
||||
*** New command-line option '-w N'/'--timeout=N' for emacsclient.
|
||||
With this command-line option, emacsclient will exit if Emacs does not
|
||||
respond within N seconds. The default is to wait forever.
|
||||
|
||||
+++
|
||||
*** 'server-stop-automatically' can be used to automatically stop the server.
|
||||
The Emacs server will be automatically stopped when certain conditions
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Client process that communicates with GNU Emacs acting as server.
|
||||
|
||||
Copyright (C) 1986-1987, 1994, 1999-2022 Free Software Foundation, Inc.
|
||||
Copyright (C) 1986-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
@ -55,6 +55,8 @@ char *w32_getenv (const char *);
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
|
||||
# define DEFAULT_TIMEOUT (30)
|
||||
|
||||
# define SOCKETS_IN_FILE_SYSTEM
|
||||
|
||||
# define INVALID_SOCKET (-1)
|
||||
@ -144,6 +146,9 @@ static char const *socket_name;
|
||||
/* If non-NULL, the filename of the authentication file. */
|
||||
static char const *server_file;
|
||||
|
||||
/* Seconds to wait before timing out (0 means wait forever). */
|
||||
static uintmax_t timeout;
|
||||
|
||||
/* If non-NULL, the tramp prefix emacs must use to find the files. */
|
||||
static char const *tramp_prefix;
|
||||
|
||||
@ -178,6 +183,7 @@ static struct option const longopts[] =
|
||||
{ "server-file", required_argument, NULL, 'f' },
|
||||
{ "display", required_argument, NULL, 'd' },
|
||||
{ "parent-id", required_argument, NULL, 'p' },
|
||||
{ "timeout", required_argument, NULL, 'w' },
|
||||
{ "tramp", required_argument, NULL, 'T' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
@ -185,7 +191,7 @@ static struct option const longopts[] =
|
||||
/* Short options, in the same order as the corresponding long options.
|
||||
There is no '-p' short option. */
|
||||
static char const shortopts[] =
|
||||
"nqueHVtca:F:"
|
||||
"nqueHVtca:F:w:"
|
||||
#ifdef SOCKETS_IN_FILE_SYSTEM
|
||||
"s:"
|
||||
#endif
|
||||
@ -497,6 +503,7 @@ decode_options (int argc, char **argv)
|
||||
if (opt < 0)
|
||||
break;
|
||||
|
||||
char* endptr;
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
@ -530,6 +537,17 @@ decode_options (int argc, char **argv)
|
||||
nowait = true;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
timeout = strtoumax (optarg, &endptr, 10);
|
||||
if (timeout <= 0 ||
|
||||
((timeout == INTMAX_MAX || timeout == INTMAX_MIN)
|
||||
&& errno == ERANGE))
|
||||
{
|
||||
fprintf (stderr, "Invalid timeout: \"%s\"\n", optarg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
eval = true;
|
||||
break;
|
||||
@ -671,6 +689,7 @@ The following OPTIONS are accepted:\n\
|
||||
Set the parameters of a new frame\n\
|
||||
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
|
||||
-n, --no-wait Don't wait for the server to return\n\
|
||||
-w, --timeout Seconds to wait before timing out\n\
|
||||
-q, --quiet Don't display messages on success\n\
|
||||
-u, --suppress-output Don't display return values from the server\n\
|
||||
-d DISPLAY, --display=DISPLAY\n\
|
||||
@ -1870,6 +1889,33 @@ start_daemon_and_retry_set_socket (void)
|
||||
return emacs_socket;
|
||||
}
|
||||
|
||||
static void
|
||||
set_socket_timeout (HSOCKET socket, int seconds)
|
||||
{
|
||||
#ifndef WINDOWSNT
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = seconds;
|
||||
timeout.tv_usec = 0;
|
||||
setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);
|
||||
#else
|
||||
DWORD timeout = seconds * 1000;
|
||||
setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof timeout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
check_socket_timeout (int rl)
|
||||
{
|
||||
#ifndef WINDOWSNT
|
||||
return (rl == -1)
|
||||
&& (errno == EAGAIN)
|
||||
&& (errno == EWOULDBLOCK);
|
||||
#else
|
||||
return (rl == SOCKET_ERROR)
|
||||
&& (WSAGetLastError() == WSAETIMEDOUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -2086,19 +2132,42 @@ main (int argc, char **argv)
|
||||
}
|
||||
fflush (stdout);
|
||||
|
||||
set_socket_timeout (emacs_socket, timeout > 0 ? timeout : DEFAULT_TIMEOUT);
|
||||
bool saw_response = false;
|
||||
/* Now, wait for an answer and print any messages. */
|
||||
while (exit_status == EXIT_SUCCESS)
|
||||
{
|
||||
bool retry = true;
|
||||
bool msg_showed = quiet;
|
||||
do
|
||||
{
|
||||
act_on_signals (emacs_socket);
|
||||
rl = recv (emacs_socket, string, BUFSIZ, 0);
|
||||
retry = check_socket_timeout (rl);
|
||||
if (retry)
|
||||
{
|
||||
if (timeout > 0 && !saw_response)
|
||||
{
|
||||
/* Don't retry if we were given a --timeout flag. */
|
||||
fprintf (stderr, "\nServer not responding; timed out after %lu seconds",
|
||||
timeout);
|
||||
retry = false;
|
||||
}
|
||||
else if (!msg_showed)
|
||||
{
|
||||
msg_showed = true;
|
||||
fprintf (stderr, "\nServer not responding; use Ctrl+C to break");
|
||||
}
|
||||
}
|
||||
}
|
||||
while (rl < 0 && errno == EINTR);
|
||||
while ((rl < 0 && errno == EINTR) || retry);
|
||||
|
||||
if (rl <= 0)
|
||||
break;
|
||||
|
||||
if (msg_showed)
|
||||
fprintf (stderr, "\nGot response from server");
|
||||
saw_response = true;
|
||||
string[rl] = '\0';
|
||||
|
||||
/* Loop over all NL-terminated messages. */
|
||||
|
Loading…
Reference in New Issue
Block a user