⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipc.c

📁 支持数字元件仿真的SPICE插件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*============================================================================FILE    IPC.cMEMBER OF process XSPICECopyright 1991Georgia Tech Research CorporationAtlanta, Georgia 30332All Rights ReservedPROJECT A-8503AUTHORS    9/12/91  Steve TynorMODIFICATIONS    6/13/92  Bill Kuhn  Added some commentsSUMMARY    Provides compatibility for the new SPICE simulator to both the MSPICE user    interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE    v.2 Simulator Interface and BCP (via Bsd Sockets).    The Interprocess Communications package provides functions    called to receive XSPICE decks from the ATESSE Simulator Interface    or Batch Control processes, and to return results to those    processes.  Functions callable from the simulator packages include:            ipc_initialize_server        ipc_terminate_server        ipc_get_line        ipc_send_line        ipc_send_data_prefix        ipc_send_data_suffix        ipc_send_dcop_prefix        ipc_send_dcop_suffix        ipc_send_evtdict_prefix        ipc_send_evtdict_suffix        ipc_send_evtdata_prefix        ipc_send_evtdata_suffix        ipc_send_errchk        ipc_send_end        ipc_send_boolean        ipc_send_int        ipc_send_double        ipc_send_complex        ipc_send_event        ipc_flush        These functions communicate with a set of transport-level functions    that implement the interprocess communications under one of    the following protocol types determined by a compile-time option:            BSD UNIX Sockets        HP/Apollo Mailboxes        For each transport protocol, the following functions are written:            ipc_transport_initialize_server        ipc_transport_get_line        ipc_transport_terminate_server        ipc_transport_send_line============================================================================*/#ifndef NDEBUG#include <stdio.h>#endif#include <sys/file.h>   /* Specific to BSD - Use sys/fcntl.h for sys5 */#include <assert.h>#include <ctype.h>#include <string.h>#include <memory.h>     /* NOTE: I think this is a Sys5ism (there is not man                         * page for it under Bsd, but it's in /usr/include                         * and it has a BSD copyright header. Go figure.                         */#include "IPC.h"#include "IPCtiein.h"#include "IPCproto.h"/* * Conditional compilation sanity check: */#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\   && !defined (IPC_DEBUG_VIA_STDIO)"       compiler error - must specify a transport mechanism";#endif/* * static 'globals' *//*typedef unsigned char Buffer_Char_t;*/typedef char Buffer_Char_t;#define OUT_BUFFER_SIZE 1000#define MAX_NUM_RECORDS 200static int              end_of_record_index [MAX_NUM_RECORDS];static int              num_records;static Buffer_Char_t    out_buffer [OUT_BUFFER_SIZE];static int              fill_count;static Ipc_Mode_t       mode;static Ipc_Protocol_t   protocol;static Ipc_Boolean_t        end_of_deck_seen;static int              batch_fd;#define FMT_BUFFER_SIZE 80static char fmt_buffer [FMT_BUFFER_SIZE];/*---------------------------------------------------------------------------*/static Ipc_Boolean_t kw_match (keyword, str)     char *keyword;     char *str;     /*      * returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match      * the ones in `keyword' - case sensitive      */{   char *k = keyword;   char *s = str;   /*    * quit if we run off the end of either string:    */   while (*s && *k) {      if (*s != *k) {         return IPC_FALSE;      }      s++;      k++;   }   /*    * if we get this far, it sould be because we ran off the end of the     * keyword else we didn't match:    */   return (*k == '\0');}/*---------------------------------------------------------------------------*//*ipc_initialize_serverThis function creates the interprocess communication channelserver mailbox or socket.*/Ipc_Status_t ipc_initialize_server (server_name, m, p)     char               *server_name;  /* Mailbox path or host/portnumber pair */     Ipc_Mode_t         m;             /* Interactive or batch */     Ipc_Protocol_t     p;             /* Type of IPC protocol */     /*      * For mailboxes, `server_name' would be the mailbox pathname; for      * sockets, this needs to be a host/portnumber pair. Maybe this should be      * automatically generated by the routine...      */{   Ipc_Status_t status;   char batch_filename [1025];      mode = m;   protocol = p;   end_of_deck_seen = IPC_FALSE;   num_records = 0;   fill_count = 0;      status = ipc_transport_initialize_server (server_name, m, p,                                             batch_filename);   if (status != IPC_STATUS_OK) {      fprintf (stderr, "ERROR: IPC: error initializing server\n");      return IPC_STATUS_ERROR;   }   if (mode == IPC_MODE_BATCH) {#ifdef IPC_AEGIS_MAILBOXES      strcat (batch_filename, ".log");#endif      batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666);      if (batch_fd < 0) {         fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",                  batch_filename);         perror ("IPC");         return IPC_STATUS_ERROR;      }   }   return status;}/*---------------------------------------------------------------------------*//*ipc_terminate_serverThis function deallocates the interprocess communication channelmailbox or socket.*/Ipc_Status_t ipc_terminate_server (){   return ipc_transport_terminate_server ();}/*---------------------------------------------------------------------------*//*ipc_get_lineThis function gets a SPICE deck input line from the interprocesscommunication channel.  Any special control commands in the deckbeginning with a ``>'' or ``#'' character are processed internally bythis function and not returned to SPICE.*/Ipc_Status_t ipc_get_line (str, len, wait)     char               *str;   /* Text retrieved from IPC channel */     int                *len;   /* Length of text string */     Ipc_Wait_t         wait;   /* Select blocking or non-blocking */     /*      * Reads one SPICE line from the connection. Strips any control lines      * which cannot be interpretted by the simulator (e.g. >INQCON) and      * processes them.  If such a line is read, it is processed and the next      * line is read.  `ipc_get_line' does not return until a non-interceptable      * line is read or end of file.      *      * If `wait' is IPC_NO_WAIT and there is no data available on the      * connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is      * IPC_WAIT, `ipc_get_line' will not return until there is data available      * or and end of file condition is reached or an error occurs.      *      * Intercepts and processes the following commands:      *    #RETURNI, #MINTIME, #VTRANS,      *    >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET      * Other > records are silently ignored.      *      * Intercepts old-style .TEMP card generated by MSPICE      *      * Returns:      *    IPC_STATUS_OK                - for successful reads      *    IPC_STATUS_NO_DATA           - when NO_WAIT and no data available      *    IPC_STATUS_END_OF_DECK       - at end of deck (>ENDNET seen)      *    IPC_STATUS_ERROR             - otherwise      */{   Ipc_Status_t status;   Ipc_Boolean_t need_another = IPC_TRUE;      do {      status = ipc_transport_get_line (str, len, wait);            switch (status) {      case IPC_STATUS_NO_DATA:      case IPC_STATUS_ERROR:         need_another = IPC_FALSE;         break;      case IPC_STATUS_END_OF_DECK:         assert (0); /* should never get this from the low-level get-line */         status = IPC_STATUS_ERROR;         need_another = IPC_FALSE;         break;      case IPC_STATUS_OK:         /*          * Got a good line - check to see if it's one of the ones we need to          * intercept          */         if (str[0] == '>') {            if (kw_match (">STOP", str)) {               ipc_handle_stop();            } else if (kw_match (">PAUSE", str)) {               /* assert (need_another); */               /*                * once more around the loop to do a blocking wait for the >CONT                */               need_another = IPC_TRUE;               wait = IPC_WAIT;            } else if (kw_match (">INQCON", str)) {               ipc_send_line (">ABRTABL");               ipc_send_line (">PAUSABL");               ipc_send_line (">KEEPABL");               status = ipc_flush ();               if (IPC_STATUS_OK != status) {                  need_another = IPC_FALSE;               }            } else if (kw_match (">ENDNET", str)) {               end_of_deck_seen = IPC_TRUE;               need_another = IPC_FALSE;               status = IPC_STATUS_END_OF_DECK;            } else {               /* silently ignore */            }         } else if (str[0] == '#') {            if (kw_match ("#RETURNI", str)) {               ipc_handle_returni ();            } else if (kw_match ("#MINTIME", str)) {               double d1, d2;               if (1 != sscanf (&str[8], "%lg", &d1)) {                  status = IPC_STATUS_ERROR;                  need_another = IPC_FALSE;               } else {                  ipc_handle_mintime (d1);               }            } else if (kw_match ("#VTRANS", str)) {               char *tok1;               char *tok2;               char *tok3;                              tok1 = &str[8];               for (tok2 = tok1; *tok2; tok2++) {                  if (isspace(*tok2)) {                     *tok2 = '\0';                     tok2++;                     break;                  }               }               for(tok3 = tok2; *tok3; tok3++) {                   if(isspace(*tok3)) {                       *tok3 = '\0';                       break;                   }               }               ipc_handle_vtrans (tok1, tok2);            } else {               /* silently ignore */            }         } else if (str[0] == '.') {            if (kw_match (".TEMP", str)) {               /* don't pass .TEMP card to caller */               printf("Old-style .TEMP card found - ignored\n");            }            else {               /* pass all other . cards to the caller */               need_another = IPC_FALSE;            }         } else {            /*             * Not a '>' or '#' record - let the caller deal with it             */            need_another = IPC_FALSE;         }         break;      default:         /*          * some unknown status value!          */         assert (0);         status = IPC_STATUS_ERROR;         need_another = IPC_FALSE;         break;      }   } while (need_another);   return status;}/*---------------------------------------------------------------------------*//*ipc_flushThis function flushes the interprocess communication channelbuffer contents.*/Ipc_Status_t ipc_flush ()     /*      * Flush all buffered messages out the connection.      */{   Ipc_Status_t status;   int last = 0;   int bytes;   int i;   /* if batch mode */   if (mode == IPC_MODE_BATCH) {      assert (batch_fd >= 0);      /* for number of records in buffer */      for (i = 0; i < num_records; i++) {         /* write the records to the .log file */         if ((end_of_record_index [i] - last) !=               write (batch_fd, &out_buffer[last], end_of_record_index [i] - last)) {            fprintf (stderr,                     "ERROR: IPC: Error writing to batch output file\n");            perror ("IPC");            return IPC_STATUS_ERROR;         }         /* If the record is one of the batch simulation status messages, */         /* send it over the ipc channel too */         if( kw_match("#ERRCHK",  &out_buffer[last]) ||             kw_match(">ENDANAL", &out_buffer[last]) ||             kw_match(">ABORTED", &out_buffer[last]) ) {            status = ipc_transport_send_line (&out_buffer[last],                                              end_of_record_index [i] - last);            if (IPC_STATUS_OK != status) {               return status;            }         }         last = end_of_record_index [i];      }   /* else, must be interactive mode */   } else {      /* send the full buffer over the ipc channel */      status = ipc_transport_send_line (&out_buffer[0],                   end_of_record_index [num_records - 1]);      if (IPC_STATUS_OK != status) {         return status;      }   }   /* reset counts to zero and return */   num_records = 0;   fill_count = 0;   return IPC_STATUS_OK;}/*---------------------------------------------------------------------------*/static Ipc_Status_t ipc_send_line_binary (str, len)     char *str;     int  len;     /*      * Same as `ipc_send_line' except does not expect the str to be null      * terminated. Sends exactly `len' characters. Use this for binary data      * strings that may have embedded nulls.      *      * Modified by wbk to append newlines for compatibility with      * ATESSE 1.0      *      */{   int length = len + 1;   int diff;   Ipc_Status_t status;   /*    * If we can't add the whole str to the buffer, or if there are no more    * record indices free, flush the buffer:    */   if (((fill_count + length) >= OUT_BUFFER_SIZE) ||       (num_records >= MAX_NUM_RECORDS)) {      status = ipc_flush ();      if (IPC_STATUS_OK != status) {         return status;      }   }      /*    * make sure that the str will fit:    */   if (length + fill_count > OUT_BUFFER_SIZE) {      fprintf (stderr,               "ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",               OUT_BUFFER_SIZE);      length = OUT_BUFFER_SIZE - fill_count;   }   /*    * finally, concatenate the str to the end of the buffer and add the newline:    */   memcpy (&out_buffer[fill_count], str, len);   fill_count += len;   out_buffer[fill_count] = '\n';   fill_count++;   end_of_record_index [num_records++] = fill_count;      return IPC_STATUS_OK;}/*---------------------------------------------------------------------------*//*ipc_send_line

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -