📄 visual.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. * *//* *********************************************************** * visual.c * TCP/IP connection to let SimOS talk to an outside * visualization process * ***********************************************************//* Statistics report and control module for simos. * Creates an independent process (the "control process") that * responds to requests over a socket asynchronously from the * simulation itself. * * The control process also communicates with the simos process. * Currently this is used to do real-time statisitics reporting. * This could be easily adapting to adding a control interface * to simos to, for example, change cpu simulators during a * simulation. */#include <sys/types.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <netdb.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/time.h>#include "visual.h"#include "sim_error.h"#include "eventcallback.h"#include "cpu_interface.h"#include "gdb_interface.h"#include "simutil.h"#include "tcl_init.h"#include "machine_params.h"extern int getdtablesize(void);#define VISUAL_MAXCONN 4#define VISUAL_MAXSTREAM 8#define MINBUFFER_SIZE (16 * 1024)typedef struct { char name[64]; int sd; /* socket */} VisualStream;static struct VisualState { int maxId; int listenSD; EventCallbackHdr eventCB; int context; struct Connection { char *host; int port; int sd; /* socket */ VisualStream stream[VISUAL_MAXSTREAM]; int id; int bufSize; char *buf; int pos; } conn[ VISUAL_MAXCONN];} visualState;static void VisualCallback( int cpuNum, EventCallbackHdr *hdr, void *arg);static bool VisualControl (void) ;static int PushString(int sd,char *string);int VisualPort = 0;int VisualSamplePeriod = 50000; /* PZ */int pauseSimulation = FALSE;static struct Connection *VisualGetConnection(void);static int VisualOpenStream(char *name, char *hostname, int portnumber);static int VisualCloseStream(char *name);int VisualOpenCmd(Tcl_Interp *interp, int argc, char *argv[]);int VisualPutsCmd(Tcl_Interp *interp, int argc, char *argv[]);int VisualCloseCmd(Tcl_Interp *interp, int argc, char *argv[]);static tclcmd visualCmds[] = { { "open", 5, VisualOpenCmd, " open name host port"}, { "close", 3, VisualCloseCmd, " close name"}, { "puts", 4, VisualPutsCmd, " puts name string"}};/* * VisualInitComm -- To initialize this module, three separate calls * must be made. This routine should be called before the control * process is forked. After the fork, the simos process should call * SimCntrl_InitSimComm, and the control process SimCntrl_InitCntrlComm. * * These calls setup a communication mechanism between the simos and * control processes, and create a socket to listen for incoming * control connections. The socket address is the first available * socket with number SIMOS_CNTRL_PORT or greater. * * Return value -- -1 on error, 0 otherwise. */void Visual_Init(void) { int isError = 0; struct sockaddr_in name; int portToTry; bool foundPort; visualState.maxId = 1; visualState.context = -1; if (!VisualPort) { /* CPUWarning("SIMOS: VisualPort not set: -- visual output not enabled \n"); */ return; } if( !isError ) { visualState.listenSD = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if (visualState.listenSD < 0 ) { perror( "opening request socket" ); } } if( !isError ) { bzero((char *)&name, sizeof(struct sockaddr_in)); name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; portToTry = VisualPort; foundPort = FALSE; ASSERT (portToTry); do { name.sin_port = htons( portToTry ); isError = bind(visualState.listenSD , (void*)&name, sizeof(name) ); if( !isError ) { foundPort = TRUE; CPUWarning( "SIMOS: visual port: %d\n", portToTry ); } else { switch( errno ) { case EADDRNOTAVAIL: case EADDRINUSE: portToTry++; break; default: foundPort = TRUE; perror( "bind request socket" ); break; } } } while( !foundPort ); } if( !isError ) { isError = listen( visualState.listenSD, 1 ); if( isError ) { perror( "listen" ); } } /* pauseSimulation -- if true, SimOS stays in VisualControl, suspending the simulation and accepting Tcl commands from the front end */ Tcl_LinkVar(TCLInterp, "PauseSimulation", (char *) &pauseSimulation, TCL_LINK_BOOLEAN); Tcl_CreateCommand(TCLInterp, "visual", DispatchCmd, (ClientData)visualCmds, (Tcl_CmdDeleteProc*)NULL); VisualCallback(0,&visualState.eventCB,0);}static void VisualCallback(int cpuNum, EventCallbackHdr *hdr, void *arg){ bool poll = TRUE; /* Keep calling VisualControl until it performs no actions -- this allows multiple requests on the same socket to be serviced */ while (poll || pauseSimulation) { poll = VisualControl(); } EventDoCallback(cpuNum,VisualCallback,hdr,arg,VisualSamplePeriod);}/* * accept the new connection */void VisualAccept(int listenPort){ int con; int in,fromAddrLen; struct sockaddr_in fromAddr; struct hostent *fromHost; for(con=0;con<VISUAL_MAXCONN && visualState.conn[con].sd ; con++) continue; fromAddrLen = sizeof( fromAddr ); if (con == VISUAL_MAXCONN ) { CPUWarning("\nSIMOS: ALREADY HAVE %d visualization connections. Drop this one \n", VISUAL_MAXCONN); return; } in = accept( listenPort, (struct sockaddr *)&fromAddr, &fromAddrLen ); if (in < 0 ) { perror("accepting connection"); } visualState.conn[con].sd = in; fromHost = gethostbyaddr( (void*)&fromAddr.sin_addr, sizeof(fromAddr.sin_addr), fromAddr.sin_family ); if( fromHost == NULL ) { perror( "resolving connecting hostname" ); visualState.conn[con].host = SaveString( "<unavailable>" ); } else { visualState.conn[con].host = SaveString(fromHost->h_name); } visualState.conn[con].port = fromAddr.sin_port; visualState.conn[con].id = visualState.maxId++; CPUWarning("Control: connect from %s:%d for connId=%d socket=%d\n", visualState.conn[con].host, visualState.conn[con].port, visualState.conn[con].id, visualState.conn[con].sd);} static void VisualConnect(struct Connection *conn, char *buf){ struct hostent *dest_host; struct sockaddr_in dest_socket; char hostname[32]; int portnumber; if (sscanf(buf,"VISUALstream %s %d",hostname,&portnumber) !=2 ) { CPUError("expecting <stream host port> got <%s>\n",buf); } if (VisualGetStream("log")) { VisualCloseStream("log"); } if (VisualOpenStream("log", hostname, portnumber) == 0) { CPUWarning("Error opening VISUALstream %s %d\n", hostname, portnumber); }}static char * VisualRPC(struct Connection *conn, char *buf){ int code; int ok = 0; int context = VisualSetContext(conn->id, &ok); SIM_DEBUG(('v', "VISUALrpc: (%2d)%s",conn->id,buf)); /* * Special case stream. I am too lazy to write the Tcl command for now */ if (!strncmp(buf,"VISUALstream",strlen("VISUALstream"))) { VisualConnect(conn,buf); return "OK"; } code = Tcl_Eval(TCLInterp, buf); VisualSetContext(context, &ok); if (code==TCL_OK || *TCLInterp->result) { return TCLInterp->result; } else { return "ERR"; } } /* ***************************************************************************** * VisualCmd(Connection *) * ****************************************************************************/static void VisualCmd(struct Connection *conn) { int i,j; char *result; char readBuffer = 'x'; /* *for now, screw the non-blocking stuff. * Block until script has been received */ if (!conn->buf) { conn->buf = malloc(MINBUFFER_SIZE); conn->bufSize = MINBUFFER_SIZE; } conn->pos = 0; for(;;) { if (conn->pos >= MINBUFFER_SIZE-2) { char *str; conn->bufSize *= 2; str = malloc(conn->bufSize); strcpy(str,conn->buf); free(conn->buf); conn->buf = str; } i = read(conn->sd,&readBuffer,1); if (i < 0 ) { perror("VisualCmd (read)"); return; /* notreached */ } if (i==0) { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -