📄 console.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * simconsole.c * * Very simple console device emulation. * Dan Teodosiu, 07/96 * *****************************************************************/#include <sys/types.h>#include <sys/termios.h>#include <sys/time.h>#include <sys/signal.h>#ifndef linux#include <sys/sysinfo.h>#include <poll.h>#endif#include <sys/times.h>#include <sys/file.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <sys/mman.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <stdio.h>#include <setjmp.h>#include <string.h>#include <memory.h>#include <ctype.h>#include <math.h>#include <stdlib.h>#include <sys/wait.h>#include <sys/socket.h>#include <netdb.h>#include "syslimits.h"#include "simtypes.h"#include "sim_error.h"#include "sim.h"#include "expect.h"#include "checkpoint.h"#include "console.h"#include "machine_params.h"/* * General remarks: * For every console, we have two (logical) interrupt sources: tx and rx * interrupts. These two are OR'ed together inside the device. */typedef struct Sim_Console { int inited; /* keeps track of whether this console was inited */ /* interrupt status/enable */ int intr_status; int intr_enable; void (*int_f)(int n, int on); /* interrupt function */ /* sconsole connection management */ int in_fd; /* note: iface 0 uses stdin/stdout */ int out_fd; int accepter_fd; /* socket on which we do the accept call */ int accepter_port; int has_connected; int warned; /* failed connection has been reported to error log */ } Sim_Console;/* check whether an int is pending */#define INT_PENDING(sts, enb) (((sts) & (enb)) != 0)/* check whether the intr line has transitioned */#define INT_TRANSITION(old_sts, old_enb, new_sts, new_enb) \ (INT_PENDING(old_sts, old_enb) != INT_PENDING(new_sts, new_enb))static Sim_Console cs[MAX_CONSOLES]; /* console data */static int ncs; /* number of consoles */int ConsolePort = 3456; /* some old port */int SlaveConsoleTimeOut = 600; /* 10 minutes */extern CptVersion cptVersion;/***************************************************************** * initialization and sconsole session management *****************************************************************//* Make a socket for a slave console (so someone can use 'sconsole' to * connect to it). */static voidCreateConsoleSocket(int n){ struct sockaddr_in sockaddr; int tmp; int sfd; sfd = socket (PF_INET, SOCK_STREAM, 0); if (sfd < 0) { perror("Can't open console socket\n"); cs[n].accepter_fd = -1; cs[n].accepter_port = -1; return; } /* Allow rapid reuse of this port. */ tmp = 1; if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp)) < 0) { perror("CreateConsoleSocket setsockopt SO_REUSEADDR"); /* Not fatal */ } sockaddr.sin_family = PF_INET; sockaddr.sin_port = htons(ConsolePort + n); sockaddr.sin_addr.s_addr = INADDR_ANY; while (bind (sfd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)) || listen (sfd, 1)) { perror("CreateConsoleSocket - Can't bind address"); Sim_Warning("Console port %d inuse ID %d PID %d\n", ConsolePort+n, n, getpid()); ConsolePort++; sockaddr.sin_port = htons(ConsolePort + n); } CPUWarning("Console num %d tcp port=%d\n", n, sockaddr.sin_port); cs[n].accepter_fd = sfd; cs[n].accepter_port = sockaddr.sin_port;}/* Open a connection. This is synchronous and blocks until the sconsole * connection arrives. */static void ConnectSlaveConsole(int n){ struct sockaddr_in sockaddr; int tmp; int sock_fd; int retval; char buf[256]; tmp = sizeof (sockaddr); sock_fd = accept (cs[n].accepter_fd, (struct sockaddr *)&sockaddr, &tmp); if (sock_fd == -1) { perror( "ConnectSlaveConsole - Accept failed"); return; } /* Tell TCP not to delay small packets. This greatly speeds up interactive response. */ tmp = 1; setsockopt (sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&tmp, sizeof(tmp)); cs[n].in_fd = sock_fd; cs[n].out_fd = sock_fd; cs[n].has_connected = 1; sprintf(buf, "\n==== SimOS slave console: Console %d ====\r\n", n); retval = write(cs[n].out_fd, buf, strlen(buf)); if (retval < 0) { perror( "ConnectSlaveConsole - Initial output write failed\n"); } else { Sim_Warning("ConnectSlaveConsole: console %d connected\n", n); }}/***************************************************************** * ConfigureTerm turns off all character processing by the host OS * so the launched OS can control it. * * We ignore anything except stdin; the sconsole program runs this * same code on the ttys for the slave consoles before connecting. *****************************************************************/static voidConfigureTerm(int fd){#ifdef RESET_TTY /* I really don't want this for Topsy (PZ) */ struct termios ios; if ((fd == 0) && isatty(0)) { if (tcgetattr(fd, &ios) < 0) { perror( "tcgetattr\n"); } ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON); ios.c_oflag &= ~OPOST; ios.c_lflag &= ~(ISIG|ICANON|ECHO); ios.c_cc[VMIN] = 1; ios.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &ios) < 0) { perror( "tcsetattr\n"); } }#endif}/***************************************************************** * Initialize console. *****************************************************************/static voidInitConsole(int n, void (*int_f)(int n, int on)){ SIMASSERT(!cs[n].inited); cs[n].inited = 1; /* note: intr_status and intr_enable will normally be 0, since * cs is statically allocated. When restoring from a checkpoint, * these fields will be set, so don't touch them here. */ cs[n].int_f = int_f; /* interrupt function */ if (n == 0) { /* console 0 gets special treatment since it uses stdin/stdout */ cs[n].in_fd = 0; cs[n].out_fd = 1; cs[n].has_connected = 1; cs[n].accepter_fd = -1; cs[n].accepter_port = 0; } else { CreateConsoleSocket(n); cs[n].has_connected = 0; cs[n].in_fd = cs[n].accepter_fd; cs[n].out_fd = -1; } cs[n].warned = 0;}/***************************************************************** * Wait for all slave consoles to connect or to time out. *****************************************************************/static voidConsoleWaitLoop(int n){#ifdef linux /* Only have one console for linux runs for now */ return;#else int delay = SlaveConsoleTimeOut; int connected = 0; int needed = n-1; int i; struct pollfd fds[MAX_CONSOLES]; Sim_Warning("This configuration calls for %d slave consoles.\n", needed); Sim_Warning("Use 'sconsole' to connect. All sessions must start before simulation begins.\n"); Sim_Warning("Any slave consoles not connected within %d seconds will not be usable during this run.\n", delay); Sim_Warning("Waiting for connections...\n"); fds[0].fd = -1; for (i=1; i<n; i++) { fds[i].fd = cs[i].accepter_fd; fds[i].events = POLLIN; fds[i].revents = 0; } for (; connected < needed && delay > 0; delay--) { sleep(1); if (poll(fds, n, 0) > 0) { for (i=1; i<n; i++) { if (fds[i].revents & POLLIN) { ConnectSlaveConsole(i); fds[i].fd = -1; /* ignore on future polls */ fds[i].revents = 0; connected++; } } } } if (connected < needed) { Sim_Warning("\nConsole wait timed out! %d consoles bitbucketed.\n", needed - connected); } else { Sim_Warning("\nAll slave consoles established.\n"); }#endif} /***************************************************************** * Initialize all consoles *****************************************************************/voidsim_console_init(int n, void (*int_f)(int n, int on)){ int i; SIMASSERT(n > 0 && n <= MAX_CONSOLES); ncs = n; for (i = 0; i < n; i++) { InitConsole(i, int_f); } if (n > 1) { ConsoleWaitLoop(n); } ConfigureTerm(0); /* need to set line discipline for console 0 */}/***************************************************************** * Poll all console inputs. Should be called periodically. *****************************************************************/static struct { int hasChar; char c;} simconsoleSavedChar[MAX_CONSOLES];#ifdef linux/* Linux version of console polling */voidsim_console_poll(void){ fd_set readfds; int i; int n; int old_status; int max_fd; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&readfds); max_fd = 0; for (i = 0; i < ncs; i++) { if (cs[i].has_connected != 0) { FD_SET(cs[i].in_fd, &readfds); if (cs[i].in_fd >= max_fd) max_fd = cs[i].in_fd; } } n = select(max_fd+1, &readfds, NULL, NULL, &tv); if (n) { for(i = 0; i < ncs; i++) { if (FD_ISSET(cs[i].in_fd, &readfds)) { /* post interrupt */ old_status = cs[i].intr_status; cs[i].intr_status |= CONS_INT_RX; if (INT_TRANSITION(old_status, cs[i].intr_enable, cs[i].intr_status, cs[i].intr_enable) && cs[i].int_f) cs[i].int_f(i, 1); /* 0->1 */ } } }}#elsevoidsim_console_poll(void){ static struct pollfd fds[MAX_CONSOLES]; /* must be 0-inited */ int i; int old_status; for (i = 0; i < ncs; i++) { if (cs[i].has_connected != 0) { fds[i].fd = cs[i].in_fd; fds[i].events = POLLRDNORM; fds[i].revents = 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -