1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-06-30 19:12:48 -05:00

New timing infrastructure. There's a new function schedule_timer()

which pretty much any module can call to request a call-back in the
future. So terminal.c can do its own handling of blinking, visual
bells and deferred screen updates, without having to rely on
term_update() being called 50 times a second (fixes: pterm-timer);
and ssh.c and telnet.c both invoke a new module pinger.c which takes
care of sending keepalives, so they get sent uniformly in all front
ends (fixes: plink-keepalives, unix-keepalives).

[originally from svn r4906]
[this svn revision also touched putty-wishlist]
This commit is contained in:
Simon Tatham
2004-11-27 13:20:21 +00:00
parent d609e1f7f8
commit 7ecf13564a
30 changed files with 1109 additions and 369 deletions

View File

@ -40,6 +40,13 @@ GdkAtom compound_text_atom, utf8_string_atom;
extern char **pty_argv; /* declared in pty.c */
extern int use_pty_argv;
/*
* Timers are global across all sessions (even if we were handling
* multiple sessions, which we aren't), so the current timer ID is
* a global variable.
*/
static guint timer_id = 0;
struct gui_data {
GtkWidget *window, *area, *sbar;
GtkBox *hbox;
@ -1022,7 +1029,6 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
show_mouseptr(inst, 0);
term_seen_key_event(inst->term);
term_out(inst->term);
}
return TRUE;
@ -1130,9 +1136,9 @@ void frontend_keypress(void *handle)
exit(0);
}
gint timer_func(gpointer data)
void notify_remote_exit(void *frontend)
{
struct gui_data *inst = (struct gui_data *)data;
struct gui_data *inst = (struct gui_data *)frontend;
int exitcode;
if (!inst->exited &&
@ -1153,10 +1159,40 @@ gint timer_func(gpointer data)
}
gtk_widget_show(inst->restartitem);
}
}
term_update(inst->term);
term_blink(inst->term, 0);
return TRUE;
static gint timer_trigger(gpointer data)
{
long now = GPOINTER_TO_INT(data);
long next;
long ticks;
if (run_timers(now, &next)) {
ticks = next - GETTICKCOUNT();
timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
GINT_TO_POINTER(next));
}
/*
* Never let a timer resume. If we need another one, we've
* asked for it explicitly above.
*/
return FALSE;
}
void timer_change_notify(long next)
{
long ticks;
if (timer_id)
gtk_timeout_remove(timer_id);
ticks = next - GETTICKCOUNT();
if (ticks <= 0)
ticks = 1; /* just in case */
timer_id = gtk_timeout_add(ticks, timer_trigger,
GINT_TO_POINTER(next));
}
void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
@ -1183,7 +1219,6 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
inst->term->has_focus = event->in;
term_out(inst->term);
term_update(inst->term);
show_mouseptr(inst, 1);
return FALSE;
@ -3392,7 +3427,6 @@ int pt_main(int argc, char **argv)
if (inst->cfg.scrollbar)
gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
GTK_SIGNAL_FUNC(scrollbar_moved), inst);
gtk_timeout_add(20, timer_func, inst);
gtk_widget_add_events(GTK_WIDGET(inst->area),
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |

View File

@ -474,6 +474,8 @@ int pty_select_result(int fd, int event)
#endif
from_backend(pty_frontend, 0, message, strlen(message));
}
notify_remote_exit(pty_frontend);
}
return !finished;
}

View File

@ -45,8 +45,8 @@ extern Backend pty_backend;
/* Simple wraparound timer function */
unsigned long getticks(void); /* based on gettimeofday(2) */
#define GETTICKCOUNT getticks
#define TICKSPERSEC 1000000 /* gettimeofday returns microseconds */
#define CURSORBLINK 450000 /* no standard way to set this */
#define TICKSPERSEC 1000 /* we choose to use milliseconds */
#define CURSORBLINK 450 /* no standard way to set this */
#define WCHAR wchar_t
#define BYTE unsigned char

View File

@ -35,6 +35,14 @@ void update_specials_menu(void *frontend)
{
}
void notify_remote_exit(void *frontend)
{
}
void timer_change_notify(long next)
{
}
void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
char *keystr, char *fingerprint)
{

View File

@ -15,14 +15,13 @@ unsigned long getticks(void)
struct timeval tv;
gettimeofday(&tv, NULL);
/*
* This will wrap around approximately every 4000 seconds, i.e.
* just over an hour, which is more than enough.
* We want to use milliseconds rather than microseconds,
* because we need a decent number of them to fit into a 32-bit
* word so it can be used for keepalives.
*/
return tv.tv_sec * 1000000 + tv.tv_usec;
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
Filename filename_from_str(const char *str)
{
Filename ret;

View File

@ -252,6 +252,7 @@ int main(int argc, char **argv)
int errors;
int use_subsystem = 0;
void *ldisc, *logctx;
long now;
ssh_get_line = console_get_line;
@ -584,6 +585,7 @@ int main(int argc, char **argv)
atexit(cleanup_termios);
ldisc_update(NULL, 1, 1);
sending = FALSE;
now = GETTICKCOUNT();
while (1) {
fd_set rset, wset, xset;
@ -644,7 +646,23 @@ int main(int argc, char **argv)
}
do {
ret = select(maxfd, &rset, &wset, &xset, NULL);
long next, ticks;
struct timeval tv, *ptv;
if (run_timers(now, &next)) {
ticks = next - GETTICKCOUNT();
if (ticks < 0) ticks = 0; /* just in case */
tv.tv_sec = ticks / 1000;
tv.tv_usec = ticks % 1000 * 1000;
ptv = &tv;
} else {
ptv = NULL;
}
ret = select(maxfd, &rset, &wset, &xset, ptv);
if (ret == 0)
now = next;
else
now = GETTICKCOUNT();
} while (ret < 0 && errno == EINTR);
if (ret < 0) {

View File

@ -321,55 +321,80 @@ char *dir_file_cat(char *dir, char *file)
}
/*
* Wait for some network data and process it.
* Do a select() between all currently active network fds and
* optionally stdin.
*/
int ssh_sftp_loop_iteration(void)
static int ssh_sftp_do_select(int include_stdin)
{
fd_set rset, wset, xset;
int i, fdcount, fdsize, *fdlist;
int fd, fdstate, rwx, ret, maxfd;
long now = GETTICKCOUNT();
fdlist = NULL;
fdcount = fdsize = 0;
/* Count the currently active fds. */
i = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) i++;
if (i < 1)
return -1; /* doom */
/* Expand the fdlist buffer if necessary. */
if (i > fdsize) {
fdsize = i + 16;
fdlist = sresize(fdlist, fdsize, int);
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&xset);
maxfd = 0;
/*
* Add all currently open fds to the select sets, and store
* them in fdlist as well.
*/
fdcount = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) {
fdlist[fdcount++] = fd;
if (rwx & 1)
FD_SET_MAX(fd, maxfd, rset);
if (rwx & 2)
FD_SET_MAX(fd, maxfd, wset);
if (rwx & 4)
FD_SET_MAX(fd, maxfd, xset);
}
do {
ret = select(maxfd, &rset, &wset, &xset, NULL);
} while (ret < 0 && errno == EINTR);
/* Count the currently active fds. */
i = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) i++;
if (i < 1)
return -1; /* doom */
/* Expand the fdlist buffer if necessary. */
if (i > fdsize) {
fdsize = i + 16;
fdlist = sresize(fdlist, fdsize, int);
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&xset);
maxfd = 0;
/*
* Add all currently open fds to the select sets, and store
* them in fdlist as well.
*/
fdcount = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) {
fdlist[fdcount++] = fd;
if (rwx & 1)
FD_SET_MAX(fd, maxfd, rset);
if (rwx & 2)
FD_SET_MAX(fd, maxfd, wset);
if (rwx & 4)
FD_SET_MAX(fd, maxfd, xset);
}
if (include_stdin)
FD_SET_MAX(0, maxfd, rset);
do {
long next, ticks;
struct timeval tv, *ptv;
if (run_timers(now, &next)) {
ticks = next - GETTICKCOUNT();
if (ticks <= 0)
ticks = 1; /* just in case */
tv.tv_sec = ticks / 1000;
tv.tv_usec = ticks % 1000 * 1000;
ptv = &tv;
} else {
ptv = NULL;
}
ret = select(maxfd, &rset, &wset, &xset, ptv);
if (ret == 0)
now = next;
else
now = GETTICKCOUNT();
} while (ret < 0 && errno != EINTR);
} while (ret == 0);
if (ret < 0) {
perror("select");
@ -393,7 +418,58 @@ int ssh_sftp_loop_iteration(void)
sfree(fdlist);
return 0;
return FD_ISSET(0, &rset) ? 1 : 0;
}
/*
* Wait for some network data and process it.
*/
int ssh_sftp_loop_iteration(void)
{
return ssh_sftp_do_select(FALSE);
}
/*
* Read a PSFTP command line from stdin.
*/
char *ssh_sftp_get_cmdline(char *prompt)
{
char *buf;
int buflen, bufsize, ret;
fputs(prompt, stdout);
fflush(stdout);
buf = NULL;
buflen = bufsize = 0;
while (1) {
ret = ssh_sftp_do_select(TRUE);
if (ret < 0) {
printf("connection died\n");
return NULL; /* woop woop */
}
if (ret > 0) {
if (buflen >= bufsize) {
bufsize = buflen + 512;
buf = sresize(buf, bufsize, char);
}
ret = read(0, buf+buflen, 1);
if (ret < 0) {
perror("read");
return NULL;
}
if (ret == 0) {
/* eof on stdin; no error, but no answer either */
return NULL;
}
if (buf[buflen++] == '\n') {
/* we have a full line */
return buf;
}
}
}
}
/*

View File

@ -105,29 +105,6 @@ static void make_filename(char *filename, int index, const char *subname)
filename[FILENAME_MAX-1] = '\0';
}
/*
* Read an entire line of text from a file. Return a buffer
* malloced to be as big as necessary (caller must free).
*/
static char *fgetline(FILE *fp)
{
char *ret = snewn(512, char);
int size = 512, len = 0;
while (fgets(ret + len, size - len, fp)) {
len += strlen(ret + len);
if (ret[len-1] == '\n')
break; /* got a newline, we're done */
size = len + 512;
ret = sresize(ret, size, char);
}
if (len == 0) { /* first fgets returned NULL */
sfree(ret);
return NULL;
}
ret[len] = '\0';
return ret;
}
void *open_settings_w(const char *sessionname, char **errmsg)
{
char filename[FILENAME_MAX];