mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-07 13:33:06 +00:00
1026 lines
24 KiB
C++
1026 lines
24 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <queue>
|
|
#include "vec.h"
|
|
#include "util.h"
|
|
#include "ipcio.h"
|
|
#include "DbeThread.h"
|
|
#include "Experiment.h"
|
|
|
|
#define ipc_trace if (ipc_flags) ipc_default_log
|
|
#define ipc_request_trace if (ipc_flags) ipc_request_log
|
|
#define ipc_response_trace if (ipc_flags) ipc_response_log
|
|
|
|
using namespace std;
|
|
|
|
// IPC implementation
|
|
static const int L_PROGRESS = 0;
|
|
static const int L_INTEGER = 1;
|
|
static const int L_BOOLEAN = 2;
|
|
static const int L_LONG = 3;
|
|
static const int L_STRING = 4;
|
|
static const int L_DOUBLE = 5;
|
|
static const int L_ARRAY = 6;
|
|
static const int L_OBJECT = 7;
|
|
static const int L_CHAR = 8;
|
|
|
|
int currentRequestID;
|
|
int currentChannelID;
|
|
static long maxSize;
|
|
|
|
extern int cancellableChannelID;
|
|
extern int error_flag;
|
|
extern int ipc_delay_microsec;
|
|
extern FILE *responseLogFileP;
|
|
|
|
IPCresponse *IPCresponseGlobal;
|
|
|
|
BufferPool *responseBufferPool;
|
|
|
|
IPCrequest::IPCrequest (int sz, int reqID, int chID)
|
|
{
|
|
size = sz;
|
|
requestID = reqID;
|
|
channelID = chID;
|
|
status = INITIALIZED;
|
|
idx = 0;
|
|
buf = (char *) malloc (size);
|
|
cancelImmediate = false;
|
|
}
|
|
|
|
IPCrequest::~IPCrequest ()
|
|
{
|
|
free (buf);
|
|
}
|
|
|
|
void
|
|
IPCrequest::read (void)
|
|
{
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
int c = getc (stdin);
|
|
ipc_request_trace (TRACE_LVL_4, " IPCrequest:getc(stdin): %02x\n", c);
|
|
buf[i] = c;
|
|
}
|
|
}
|
|
|
|
IPCrequestStatus
|
|
IPCrequest::getStatus (void)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
void
|
|
IPCrequest::setStatus (IPCrequestStatus newStatus)
|
|
{
|
|
status = newStatus;
|
|
}
|
|
|
|
static int
|
|
readByte (IPCrequest* req)
|
|
{
|
|
int c;
|
|
int val = 0;
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
if (req == NULL)
|
|
{
|
|
c = getc (stdin);
|
|
ipc_request_trace (TRACE_LVL_4, " readByte:getc(stdin): %02x\n", c);
|
|
}
|
|
else
|
|
c = req->rgetc ();
|
|
switch (c)
|
|
{
|
|
case '0': case '1': case '2': case '3':
|
|
case '4': case '5': case '6': case '7':
|
|
case '8': case '9':
|
|
val = val * 16 + c - '0';
|
|
break;
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
|
val = val * 16 + c - 'a' + 10;
|
|
break;
|
|
case EOF:
|
|
val = EOF;
|
|
break;
|
|
default:
|
|
fprintf (stderr, "readByte: Unknown byte: %d\n", c);
|
|
break;
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
|
|
static int
|
|
readIVal (IPCrequest *req)
|
|
{
|
|
int val = readByte (req);
|
|
for (int i = 0; i < 3; i++)
|
|
val = val * 256 + readByte (req);
|
|
ipc_trace (" readIVal: %d\n", val);
|
|
return val;
|
|
}
|
|
|
|
static String
|
|
readSVal (IPCrequest *req)
|
|
{
|
|
int len = readIVal (req);
|
|
if (len == -1)
|
|
{
|
|
ipc_trace (" readSVal: <NULL>\n");
|
|
return NULL;
|
|
}
|
|
char *str = (char *) malloc (len + 1);
|
|
char *s = str;
|
|
*s = (char) 0;
|
|
while (len--)
|
|
*s++ = req->rgetc ();
|
|
*s = (char) 0;
|
|
ipc_trace (" readSVal: '%s'\n", str);
|
|
return str;
|
|
}
|
|
|
|
static long long
|
|
readLVal (IPCrequest *req)
|
|
{
|
|
long long val = readByte (req);
|
|
for (int i = 0; i < 7; i++)
|
|
val = val * 256 + readByte (req);
|
|
ipc_trace (" readLVal: %lld\n", val);
|
|
return val;
|
|
}
|
|
|
|
static bool
|
|
readBVal (IPCrequest *req)
|
|
{
|
|
int val = readByte (req);
|
|
ipc_trace (" readBVal: %s\n", val == 0 ? "true" : "false");
|
|
return val != 0;
|
|
}
|
|
|
|
static char
|
|
readCVal (IPCrequest *req)
|
|
{
|
|
int val = readByte (req);
|
|
ipc_trace (" readCVal: %d\n", val);
|
|
return (char) val;
|
|
}
|
|
|
|
static double
|
|
readDVal (IPCrequest *req)
|
|
{
|
|
String s = readSVal (req);
|
|
double d = atof (s);
|
|
free (s);
|
|
return d;
|
|
}
|
|
|
|
static Object
|
|
readAVal (IPCrequest *req)
|
|
{
|
|
bool twoD = false;
|
|
int type = readByte (req);
|
|
if (type == L_ARRAY)
|
|
{
|
|
twoD = true;
|
|
type = readByte (req);
|
|
}
|
|
ipc_trace ("readAVal: twoD=%s type=%d\n", twoD ? "true" : "false", type);
|
|
|
|
int len = readIVal (req);
|
|
if (len == -1)
|
|
return NULL;
|
|
switch (type)
|
|
{
|
|
case L_INTEGER:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<int>*> *array = new Vector<Vector<int>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<int>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<int> *array = new Vector<int>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readIVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_LONG:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<long long>*> *array = new Vector<Vector<long long>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<long long>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<long long> *array = new Vector<long long>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readLVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_DOUBLE:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<double>*> *array = new Vector<Vector<double>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<double>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<double> *array = new Vector<double>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readDVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_BOOLEAN:
|
|
if (twoD)
|
|
{
|
|
Vector < Vector<bool>*> *array = new Vector < Vector<bool>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<bool>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<bool> *array = new Vector<bool>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readBVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_CHAR:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<char>*> *array = new Vector<Vector<char>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<char>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<char> *array = new Vector<char>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readCVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_STRING:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<String>*> *array = new Vector<Vector<String>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<String>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<String> *array = new Vector<String>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readSVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
case L_OBJECT:
|
|
if (twoD)
|
|
{
|
|
Vector<Vector<Object>*> *array = new Vector<Vector<Object>*>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, (Vector<Object>*)readAVal (req));
|
|
return array;
|
|
}
|
|
else
|
|
{
|
|
Vector<Object> *array = new Vector<Object>(len);
|
|
for (int i = 0; i < len; i++)
|
|
array->store (i, readAVal (req));
|
|
return array;
|
|
}
|
|
//break;
|
|
default:
|
|
fprintf (stderr, "readAVal: Unknown code: %d\n", type);
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int iVal;
|
|
static bool bVal;
|
|
static long long lVal;
|
|
static String sVal;
|
|
static double dVal;
|
|
static Object aVal;
|
|
|
|
static void
|
|
readResult (int type, IPCrequest *req)
|
|
{
|
|
int tVal = readByte (req);
|
|
switch (tVal)
|
|
{
|
|
case L_INTEGER:
|
|
iVal = readIVal (req);
|
|
break;
|
|
case L_LONG:
|
|
lVal = readLVal (req);
|
|
break;
|
|
case L_BOOLEAN:
|
|
bVal = readBVal (req);
|
|
break;
|
|
case L_DOUBLE:
|
|
dVal = readDVal (req);
|
|
break;
|
|
case L_STRING:
|
|
sVal = readSVal (req);
|
|
break;
|
|
case L_ARRAY:
|
|
aVal = readAVal (req);
|
|
break;
|
|
case EOF:
|
|
fprintf (stderr, "EOF read in readResult\n");
|
|
sVal = NULL;
|
|
return;
|
|
default:
|
|
fprintf (stderr, "Unknown code: %d\n", tVal);
|
|
abort ();
|
|
}
|
|
if (type != tVal)
|
|
{
|
|
fprintf (stderr, "Internal error: readResult: parameter mismatch: type=%d should be %d\n", tVal, type);
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
int
|
|
readInt (IPCrequest *req)
|
|
{
|
|
readResult (L_INTEGER, req);
|
|
return iVal;
|
|
}
|
|
|
|
String
|
|
readString (IPCrequest *req)
|
|
{
|
|
readResult (L_STRING, req);
|
|
return sVal;
|
|
}
|
|
|
|
long long
|
|
readLong (IPCrequest *req)
|
|
{
|
|
readResult (L_LONG, req);
|
|
return lVal;
|
|
}
|
|
|
|
double
|
|
readDouble (IPCrequest *req)
|
|
{
|
|
readResult (L_DOUBLE, req);
|
|
return dVal;
|
|
}
|
|
|
|
bool
|
|
readBoolean (IPCrequest *req)
|
|
{
|
|
readResult (L_BOOLEAN, req);
|
|
return bVal;
|
|
}
|
|
|
|
DbeObj
|
|
readObject (IPCrequest *req)
|
|
{
|
|
readResult (L_LONG, req);
|
|
return (DbeObj) lVal;
|
|
}
|
|
|
|
Object
|
|
readArray (IPCrequest *req)
|
|
{
|
|
readResult (L_ARRAY, req);
|
|
return aVal;
|
|
}
|
|
|
|
// Write
|
|
IPCresponse::IPCresponse (int sz)
|
|
{
|
|
requestID = -1;
|
|
channelID = -1;
|
|
responseType = -1;
|
|
responseStatus = RESPONSE_STATUS_SUCCESS;
|
|
sb = new StringBuilder (sz);
|
|
next = NULL;
|
|
}
|
|
|
|
IPCresponse::~IPCresponse ()
|
|
{
|
|
delete sb;
|
|
}
|
|
|
|
void
|
|
IPCresponse::reset ()
|
|
{
|
|
requestID = -1;
|
|
channelID = -1;
|
|
responseType = -1;
|
|
responseStatus = RESPONSE_STATUS_SUCCESS;
|
|
sb->setLength (0);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendByte (int b)
|
|
{
|
|
ipc_trace ("sendByte: %02x %d\n", b, b);
|
|
sb->appendf ("%02x", b);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendIVal (int i)
|
|
{
|
|
ipc_trace ("sendIVal: %08x %d\n", i, i);
|
|
sb->appendf ("%08x", i);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendLVal (long long l)
|
|
{
|
|
ipc_trace ("sendLVal: %016llx %lld\n", l, l);
|
|
sb->appendf ("%016llx", l);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendSVal (const char *s)
|
|
{
|
|
if (s == NULL)
|
|
{
|
|
sendIVal (-1);
|
|
return;
|
|
}
|
|
sendIVal ((int) strlen (s));
|
|
ipc_trace ("sendSVal: %s\n", s);
|
|
sb->appendf ("%s", s);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendBVal (bool b)
|
|
{
|
|
sendByte (b ? 1 : 0);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendCVal (char c)
|
|
{
|
|
sendByte (c);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendDVal (double d)
|
|
{
|
|
char str[32];
|
|
snprintf (str, sizeof (str), "%.12f", d);
|
|
sendSVal (str);
|
|
}
|
|
|
|
void
|
|
IPCresponse::sendAVal (void *ptr)
|
|
{
|
|
if (ptr == NULL)
|
|
{
|
|
sendByte (L_INTEGER);
|
|
sendIVal (-1);
|
|
return;
|
|
}
|
|
|
|
VecType type = ((Vector<void*>*)ptr)->type ();
|
|
switch (type)
|
|
{
|
|
case VEC_INTEGER:
|
|
{
|
|
sendByte (L_INTEGER);
|
|
Vector<int> *array = (Vector<int>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendIVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_BOOL:
|
|
{
|
|
sendByte (L_BOOLEAN);
|
|
Vector<bool> *array = (Vector<bool>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendBVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_CHAR:
|
|
{
|
|
sendByte (L_CHAR);
|
|
Vector<char> *array = (Vector<char>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendCVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_LLONG:
|
|
{
|
|
sendByte (L_LONG);
|
|
Vector<long long> *array = (Vector<long long>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendLVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_DOUBLE:
|
|
{
|
|
sendByte (L_DOUBLE);
|
|
Vector<double> *array = (Vector<double>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendDVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_STRING:
|
|
{
|
|
sendByte (L_STRING);
|
|
Vector<String> *array = (Vector<String>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendSVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_STRINGARR:
|
|
{
|
|
sendByte (L_ARRAY);
|
|
sendByte (L_STRING);
|
|
Vector<void*> *array = (Vector<void*>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendAVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_INTARR:
|
|
{
|
|
sendByte (L_ARRAY);
|
|
sendByte (L_INTEGER);
|
|
Vector<void*> *array = (Vector<void*>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendAVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_LLONGARR:
|
|
{
|
|
sendByte (L_ARRAY);
|
|
sendByte (L_LONG);
|
|
Vector<void*> *array = (Vector<void*>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendAVal (array->fetch (i));
|
|
break;
|
|
}
|
|
case VEC_VOIDARR:
|
|
{
|
|
sendByte (L_OBJECT);
|
|
Vector<void*> *array = (Vector<void*>*)ptr;
|
|
sendIVal (array->size ());
|
|
for (int i = 0; i < array->size (); i++)
|
|
sendAVal (array->fetch (i));
|
|
break;
|
|
}
|
|
default:
|
|
fprintf (stderr, "sendAVal: Unknown type: %d\n", type);
|
|
abort ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
writeResponseHeader (int requestID, int responseType, int responseStatus, int nBytes)
|
|
{
|
|
if (responseType == RESPONSE_TYPE_HANDSHAKE)
|
|
nBytes = IPC_VERSION_NUMBER;
|
|
int use_write = 2;
|
|
ipc_response_trace (TRACE_LVL_1, "ResponseHeaderBegin----- %x ---- %x ----- %x -----%x -------\n", requestID, responseType, responseStatus, nBytes);
|
|
if (use_write)
|
|
{
|
|
char buf[23];
|
|
if (use_write == 1)
|
|
{
|
|
int i = 0;
|
|
snprintf (buf + i, 3, "%2x", HEADER_MARKER);
|
|
i += 2;
|
|
snprintf (buf + i, 9, "%8x", requestID);
|
|
i += 8;
|
|
snprintf (buf + i, 3, "%2x", responseType);
|
|
i += 2;
|
|
snprintf (buf + i, 3, "%2x", responseStatus);
|
|
i += 2;
|
|
snprintf (buf + i, 9, "%8x", nBytes);
|
|
}
|
|
else
|
|
snprintf (buf, 23, "%02x%08x%02x%02x%08x", HEADER_MARKER, requestID,
|
|
responseType, responseStatus, nBytes);
|
|
buf[22] = 0;
|
|
write (1, buf, 22);
|
|
}
|
|
else
|
|
{
|
|
cout << setfill ('0') << setw (2) << hex << HEADER_MARKER;
|
|
cout << setfill ('0') << setw (8) << hex << requestID;
|
|
cout << setfill ('0') << setw (2) << hex << responseType;
|
|
cout << setfill ('0') << setw (2) << hex << responseStatus;
|
|
cout << setfill ('0') << setw (8) << hex << nBytes;
|
|
cout.flush ();
|
|
}
|
|
ipc_response_trace (TRACE_LVL_1, "----------------------------ResponseHeaderEnd\n");
|
|
if (nBytes > maxSize)
|
|
{
|
|
maxSize = nBytes;
|
|
ipc_trace ("New maxsize %ld\n", maxSize);
|
|
}
|
|
}
|
|
|
|
bool
|
|
cancelNeeded (int chID)
|
|
{
|
|
if (chID == cancellableChannelID && chID == cancelRequestedChannelID)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static void
|
|
writeResponseWithHeader (int requestID, int channelID, int responseType,
|
|
int responseStatus, IPCresponse* os)
|
|
{
|
|
if (cancelNeeded (channelID))
|
|
{
|
|
responseStatus = RESPONSE_STATUS_CANCELLED;
|
|
ipc_trace ("CANCELLING %d %d\n", requestID, channelID);
|
|
// This is for gracefully cancelling regular ops like openExperiment - getFiles should never reach here
|
|
}
|
|
os->setRequestID (requestID);
|
|
os->setChannelID (channelID);
|
|
os->setResponseType (responseType);
|
|
os->setResponseStatus (responseStatus);
|
|
os->print ();
|
|
os->reset ();
|
|
responseBufferPool->recycle (os);
|
|
}
|
|
|
|
void
|
|
writeAckFast (int requestID)
|
|
{
|
|
writeResponseHeader (requestID, RESPONSE_TYPE_ACK, RESPONSE_STATUS_SUCCESS, 0);
|
|
}
|
|
|
|
void
|
|
writeAck (int requestID, int channelID)
|
|
{
|
|
#if DEBUG
|
|
char *s = getenv (NTXT ("SP_NO_IPC_ACK"));
|
|
#else /* ^DEBUG */
|
|
char *s = NULL;
|
|
#endif /* ^DEBUG */
|
|
if (s)
|
|
{
|
|
int i = requestID;
|
|
int j = channelID;
|
|
ipc_request_trace (TRACE_LVL_4, "ACK skipped: requestID=%d channelID=%d\n", i, j);
|
|
}
|
|
else
|
|
{
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
|
|
writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_ACK,
|
|
RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
}
|
|
|
|
void
|
|
writeHandshake (int requestID, int channelID)
|
|
{
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
|
|
writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
// writeResponseHeader(requestID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, IPC_VERSION_NUMBER);
|
|
}
|
|
|
|
void
|
|
writeResponseGeneric (int responseStatus, int requestID, int channelID)
|
|
{
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
|
|
writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_COMPLETE, responseStatus, OUTS);
|
|
}
|
|
|
|
BufferPool::BufferPool ()
|
|
{
|
|
pthread_mutex_init (&p_mutex, NULL);
|
|
smallBuf = NULL;
|
|
largeBuf = NULL;
|
|
}
|
|
|
|
BufferPool::~BufferPool ()
|
|
{
|
|
for (IPCresponse *p = smallBuf; p;)
|
|
{
|
|
IPCresponse *tmp = p;
|
|
p = tmp->next;
|
|
delete tmp;
|
|
}
|
|
for (IPCresponse *p = largeBuf; p;)
|
|
{
|
|
IPCresponse *tmp = p;
|
|
p = tmp->next;
|
|
delete tmp;
|
|
}
|
|
}
|
|
|
|
IPCresponse*
|
|
BufferPool::getNewResponse (int size)
|
|
{
|
|
pthread_mutex_lock (&p_mutex);
|
|
if (ipc_single_threaded_mode && size < BUFFER_SIZE_LARGE)
|
|
size = BUFFER_SIZE_LARGE;
|
|
IPCresponse *newResponse = NULL;
|
|
if (size >= BUFFER_SIZE_LARGE)
|
|
{
|
|
if (largeBuf)
|
|
{
|
|
newResponse = largeBuf;
|
|
largeBuf = largeBuf->next;
|
|
}
|
|
}
|
|
else if (smallBuf)
|
|
{
|
|
newResponse = smallBuf;
|
|
smallBuf = smallBuf->next;
|
|
}
|
|
if (newResponse)
|
|
newResponse->reset ();
|
|
else
|
|
{
|
|
newResponse = new IPCresponse (size);
|
|
ipc_trace ("GETNEWBUFFER %d\n", size);
|
|
}
|
|
pthread_mutex_unlock (&p_mutex);
|
|
return newResponse;
|
|
}
|
|
|
|
void
|
|
BufferPool::recycle (IPCresponse *respB)
|
|
{
|
|
pthread_mutex_lock (&p_mutex);
|
|
if (respB->getCurBufSize () >= BUFFER_SIZE_LARGE)
|
|
{
|
|
respB->next = largeBuf;
|
|
largeBuf = respB;
|
|
}
|
|
else
|
|
{
|
|
respB->next = smallBuf;
|
|
smallBuf = respB;
|
|
}
|
|
pthread_mutex_unlock (&p_mutex);
|
|
}
|
|
|
|
void
|
|
writeArray (void *ptr, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
|
|
OUTS->sendByte (L_ARRAY);
|
|
OUTS->sendAVal (ptr);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
|
|
RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeString (const char *s, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
|
|
OUTS->sendByte (L_STRING);
|
|
OUTS->sendSVal (s);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
|
|
RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeObject (DbeObj obj, IPCrequest* req)
|
|
{
|
|
writeLong ((long long) obj, req);
|
|
}
|
|
|
|
void
|
|
writeBoolean (bool b, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
|
|
OUTS->sendByte (L_BOOLEAN);
|
|
OUTS->sendBVal (b);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
|
|
RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeInt (int i, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
|
|
OUTS->sendByte (L_INTEGER);
|
|
OUTS->sendIVal (i);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeChar (char c, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
|
|
OUTS->sendByte (L_CHAR);
|
|
OUTS->sendCVal (c);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeLong (long long l, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE)
|
|
return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
|
|
OUTS->sendByte (L_LONG);
|
|
OUTS->sendLVal (l);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
void
|
|
writeDouble (double d, IPCrequest* req)
|
|
{
|
|
if (req->getStatus () == CANCELLED_IMMEDIATE) return;
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
|
|
OUTS->sendByte (L_DOUBLE);
|
|
OUTS->sendDVal (d);
|
|
writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
}
|
|
|
|
int
|
|
setProgress (int percentage, const char *proc_str)
|
|
{
|
|
if (cancelNeeded (currentChannelID))
|
|
{
|
|
// ExperimentLoadCancelException *e1 = new ExperimentLoadCancelException();
|
|
// throw (e1);
|
|
return 1;
|
|
}
|
|
if (NULL == proc_str)
|
|
return 1;
|
|
int size = strlen (proc_str) + 100; // 100 bytes for additional data
|
|
int bs = BUFFER_SIZE_MEDIUM;
|
|
if (size > BUFFER_SIZE_MEDIUM)
|
|
{
|
|
if (size > BUFFER_SIZE_LARGE) return 1; // This should never happen
|
|
bs = BUFFER_SIZE_LARGE;
|
|
}
|
|
IPCresponse *OUTS = responseBufferPool->getNewResponse (bs);
|
|
OUTS->sendByte (L_PROGRESS);
|
|
OUTS->sendIVal (percentage);
|
|
OUTS->sendSVal (proc_str);
|
|
writeResponseWithHeader (currentRequestID, currentChannelID, RESPONSE_TYPE_PROGRESS, RESPONSE_STATUS_SUCCESS, OUTS);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
IPCresponse::print (void)
|
|
{
|
|
if (ipc_delay_microsec)
|
|
usleep (ipc_delay_microsec);
|
|
int stringSize = sb->length ();
|
|
writeResponseHeader (requestID, responseType, responseStatus, stringSize);
|
|
if (stringSize > 0)
|
|
{
|
|
char *s = sb->toString ();
|
|
hrtime_t start_time = gethrtime ();
|
|
int use_write = 1;
|
|
if (use_write)
|
|
write (1, s, stringSize); // write(1, sb->toString(), stringSize);
|
|
else
|
|
{
|
|
cout << s;
|
|
cout.flush ();
|
|
}
|
|
hrtime_t end_time = gethrtime ();
|
|
unsigned long long time_stamp = end_time - start_time;
|
|
ipc_response_log (TRACE_LVL_3, "ReqID %x flush time %llu nanosec \n", requestID, time_stamp);
|
|
free (s);
|
|
}
|
|
}
|
|
|
|
void
|
|
setCancelRequestedCh (int chID)
|
|
{
|
|
cancelRequestedChannelID = chID;
|
|
}
|
|
|
|
void
|
|
readRequestHeader ()
|
|
{
|
|
int marker = readByte (NULL);
|
|
if (marker != HEADER_MARKER)
|
|
{
|
|
fprintf (stderr, "Internal error: received request (%d) without header marker\n", marker);
|
|
error_flag = 1;
|
|
return;
|
|
}
|
|
else
|
|
ipc_request_trace (TRACE_LVL_1, "RequestHeaderBegin------------------------\n");
|
|
int requestID = readIVal (NULL);
|
|
int requestType = readByte (NULL);
|
|
int channelID = readIVal (NULL);
|
|
int nBytes = readIVal (NULL);
|
|
if (requestType == REQUEST_TYPE_HANDSHAKE)
|
|
{
|
|
// write the ack directly to the wire, not through the response queue
|
|
// writeAckFast(requestID);
|
|
writeAck (requestID, channelID);
|
|
maxSize = 0;
|
|
writeHandshake (requestID, channelID);
|
|
ipc_request_trace (TRACE_LVL_1, "RQ: HANDSHAKE --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
|
|
}
|
|
else if (requestType == REQUEST_TYPE_CANCEL)
|
|
{
|
|
writeAck (requestID, channelID);
|
|
ipc_request_trace (TRACE_LVL_1, "RQ: CANCEL --- RQ: %x ----- %x --- CH: %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
|
|
if (channelID == cancellableChannelID)
|
|
{
|
|
// we have worked on at least one request belonging to this channel
|
|
writeResponseGeneric (RESPONSE_STATUS_SUCCESS, requestID, channelID);
|
|
setCancelRequestedCh (channelID);
|
|
ipc_trace ("CANCELLABLE %x %x\n", channelID, currentChannelID);
|
|
if (channelID == currentChannelID)
|
|
// request for this channel is currently in progress
|
|
ipc_request_trace (TRACE_LVL_1, "IN PROGRESS REQUEST NEEDS CANCELLATION");
|
|
// ssp_post_cond(waitingToFinish);
|
|
}
|
|
else
|
|
{
|
|
// FIXME:
|
|
// it is possible that a request for this channel is on the requestQ
|
|
// or has been submitted to the work group queue but is waiting for a thread to pick it up
|
|
writeResponseGeneric (RESPONSE_STATUS_FAILURE, requestID, channelID);
|
|
setCancelRequestedCh (channelID);
|
|
ipc_request_trace (TRACE_LVL_1, "RETURNING FAILURE TO CANCEL REQUEST channel %d\n", channelID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
writeAck (requestID, channelID);
|
|
ipc_request_trace (TRACE_LVL_1, "RQ: --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
|
|
IPCrequest *nreq = new IPCrequest (nBytes, requestID, channelID);
|
|
nreq->read ();
|
|
ipc_request_trace (TRACE_LVL_1, "RQ: --- %x Read from stream \n", requestID);
|
|
if (cancelNeeded (channelID))
|
|
{
|
|
ipc_request_trace (TRACE_LVL_1, "CANCELLABLE REQ RECVD %x %x\n", channelID, requestID);
|
|
writeResponseGeneric (RESPONSE_STATUS_CANCELLED, requestID, channelID);
|
|
delete nreq;
|
|
return;
|
|
}
|
|
DbeQueue *q = new DbeQueue (ipc_doWork, nreq);
|
|
ipcThreadPool->put_queue (q);
|
|
}
|
|
}
|