FILE IPCaegis.c
MEMBER OF process XSPICE
Public Domain
Georgia Tech Research Corporation
Atlanta, Georgia 30332
PROJECT A-8503
AUTHORS
9/12/91 Steve Tynor
MODIFICATIONS
<date> <person name> <nature of modifications>
SUMMARY
Provides compatibility for the new XSPICE simulator to both the MSPICE user
interface and BCP via ATESSE v.1 style AEGIS mailboxes.
INTERFACES
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
============================================================================*/
#ifdef IPC_AEGIS_MAILBOXES
#include <assert.h>
#include <apollo/base.h>
#include <apollo/mbx.h>
#include <apollo/error.h>
#include "ngspice/memory.h"
#include "ngspice/ipc.h"
typedef unsigned char Buffer_char_t;
static status_$t status;
typedef enum {
IPC_MBX_UNINITIALIZED,
IPC_MBX_INITIALIZED,
IPC_MBX_CONNECTED_TO_CLIENT,
} Ipc_Mbx_State_t;
static void *mbx_handle;
static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED;
static mbx_$server_msg_t mbx_send_msg_buf;
static mbx_$server_msg_t mbx_recieve_msg_buf;
static mbx_$server_msg_t *mbx_ret_ptr;
static int mbx_ret_len;
static short mbx_chan;
#include "ngspice/ipcproto.h"
ipc_transport_initialize_server
This function creates an Aegis mailbox, and if successful,
calls ipc_get_line to wait for the first record sent which is
assumed to be the batch output filename.
*/
Ipc_Status_t ipc_transport_initialize_server (server_name, m, p,
batch_filename)
char *server_name;
Ipc_Mode_t m;
Ipc_Protocol_t p;
char *batch_filename;
{
int len;
assert (p == IPC_PROTOCOL_V1);
mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max,
1, &mbx_handle, &status);
if (status.all != status_$ok) {
fprintf (stderr,
"ERROR: IPC: Error creating mailbox server \"%s\"\n",
server_name);
error_$print (status);
mbx_state = IPC_MBX_UNINITIALIZED;
return IPC_STATUS_ERROR;
} else {
mbx_state = IPC_MBX_INITIALIZED;
* First record is the name of the batch filename - whether we're in
* batch mode or not:
*/
return ipc_get_line (batch_filename, &len, IPC_WAIT);
}
* shouldn't get here
*/
assert (0);
return IPC_STATUS_ERROR;
}
Ipc_Status_t extract_msg (str, len)
char *str;
int *len;
{
*len = mbx_ret_len - mbx_$serv_msg_hdr_len;
assert (*len >= 0);
* null terminate before copy:
*/
mbx_ret_ptr->data [*len] = '\0';
strcpy (str, mbx_ret_ptr->data);
return IPC_STATUS_OK;
}
ipc_transport_get_line
This function reads data sent by a client over the mailbox
channel. It also handles the initial opening of the
mailbox channel when requested by a client.
*/
Ipc_Status_t ipc_transport_get_line (str, len, wait)
char *str;
int *len;
Ipc_Wait_t wait;
{
if (mbx_state == IPC_MBX_UNINITIALIZED) {
fprintf (stderr,
"ERROR: IPC: Attempted to read from non-initialized mailbox\n");
return IPC_STATUS_ERROR;
}
assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) ||
(mbx_state == IPC_MBX_INITIALIZED));
for (;;) {
if (wait == IPC_WAIT) {
mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max,
&mbx_ret_ptr, &mbx_ret_len, &status);
} else {
mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf,
mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len,
&status);
if (status.all == mbx_$channel_empty) {
return IPC_STATUS_NO_DATA;
}
}
if (status.all != status_$ok) {
fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n");
error_$print (status);
return IPC_STATUS_ERROR;
}
switch (mbx_ret_ptr->mt) {
case mbx_$channel_open_mt:
if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) {
* we're already connected to a client... refuse the connection
*/
mbx_send_msg_buf.mt = mbx_$reject_open_mt;
} else {
mbx_send_msg_buf.mt = mbx_$accept_open_mt;
mbx_state = IPC_MBX_CONNECTED_TO_CLIENT;
}
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len;
mbx_chan = mbx_ret_ptr->chan;
mbx_send_msg_buf.chan = mbx_chan;
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len,
&status);
if (status.all != status_$ok) {
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
error_$print (status);
return IPC_STATUS_ERROR;
}
* check to see if there was a message buried in the open request:
*/
if (mbx_ret_len > mbx_$serv_msg_hdr_len) {
return extract_msg (str, len);
}
break;
case mbx_$eof_mt:
mbx_chan = mbx_ret_ptr->chan;
mbx_$deallocate(mbx_handle, mbx_chan, &status);
if (status.all != status_$ok) {
fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n");
error_$print (status);
return IPC_STATUS_ERROR;
}
mbx_state = IPC_MBX_INITIALIZED;
return IPC_STATUS_EOF;
break;
case mbx_$data_mt:
assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT);
return extract_msg (str, len);
break;
case mbx_$data_partial_mt:
fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n");
break;
default:
fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n",
mbx_ret_ptr->mt);
}
}
return IPC_STATUS_ERROR;
}
ipc_transport_terminate_server
This function calls ipc\_transport\_get\_line until it
receives an EOF from the client, which concludes the
communication.
*/
Ipc_Status_t ipc_transport_terminate_server ()
{
char buffer[300];
int len;
Ipc_Status_t status;
do {
status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
} while ((status != IPC_STATUS_ERROR) &&
(status != IPC_STATUS_EOF));
return status;
}
ipc_transport_send_line
This function sends a message to the current client through
the mailbox channel.
*/
Ipc_Status_t ipc_transport_send_line (str, len)
char *str;
int len;
{
long cnt;
if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) {
fprintf (stderr,
"ERROR: IPC: Attempted to write to non-open mailbox\n");
return IPC_STATUS_ERROR;
}
mbx_send_msg_buf.mt = mbx_$data_mt;
if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) {
fprintf (stderr,
"ERROR: IPC: send_line message too long - truncating\n");
len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len;
}
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len;
mbx_send_msg_buf.chan = mbx_chan;
memcpy (mbx_send_msg_buf.data, str, len);
cnt = mbx_send_msg_buf.cnt;
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status);
if (status.all != status_$ok) {
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
error_$print (status);
return IPC_STATUS_ERROR;
}
return IPC_STATUS_OK;
}
#else
int intDummy1;
#endif