trick/trick_source/sim_services/MasterSlave/MSSharedMem.cpp
2021-08-27 19:38:56 -05:00

295 lines
9.2 KiB
C++

#include <iostream>
#include <sstream>
#include <cstring> // for memcpy
#include <unistd.h>
#include "trick/MSSharedMem.hh"
#include "trick/tsm_proto.h"
#include "trick/command_line_protos.h"
Trick::MSSharedMem::MSSharedMem() : tsm_dev() {
tsm_dev.default_val = -1;
// default is a non-zero sync wait limit; helpful when slave reading initial data from master
sync_wait_limit = 5.0 ;
}
Trick::MSSharedMem::~MSSharedMem() {
// detach shared memory
tsm_disconnect(&tsm_dev);
}
int Trick::MSSharedMem::set_sync_wait_limit(double in_limit) {
/** @par Detailed Design */
if ( in_limit > 0.0 ) {
/** @li if the incoming limit time is greater than zero, we will use it
as the timeout value during read and write */
sync_wait_limit = in_limit ;
} else {
/** @li if the incoming limit time is less than or equal to zero, wait forever */
sync_wait_limit = TSM_MAX_TIMEOUT_LIMIT;
}
return(0) ;
}
std::string Trick::MSSharedMem::add_sim_args(std::string slave_type __attribute__((unused))) {
/** @par Detailed Design */
/** @li nothing to do here for shared memory. */
return("");
}
int Trick::MSSharedMem::process_sim_args() {
//int ii ;
//int argc ;
//char ** argv ;
//argc = command_line_args_get_argc() ;
//argv = command_line_args_get_argv() ;
/** @par Detailed Design */
/** @li no shared memory arguments to search for, return 1 to enable slave */
//for (ii = 2; ii < argc; ii++) {
//}
return(1) ;
}
int Trick::MSSharedMem::accept() {
int ret ;
/** @par Detailed Design */
/** @li Call tsm_init to create shared memory for master. */
tsm_dev.size = sizeof(MSSharedMemData);
ret = tsm_init(&tsm_dev);
shm_addr = (MSSharedMemData*) tsm_dev.addr;
/** @li Save master process id so we can keep master and slave data seperate. */
// (the master calls accept)
if (ret==TSM_SUCCESS) {
shm_addr->master_pid = getpid();
//fprintf(stderr, "====accept master=%d\n", getpid());
MSQ_INIT(shm_addr->master_time);
MSQ_INIT(shm_addr->master_command);
MSQ_INIT(shm_addr->slave_command);
shm_addr->slave_port = MS_ERROR_PORT;
shm_addr->chkpnt_name[0] = MS_ERROR_NAME;
} else {
//fprintf(stderr, "====accept SHARED MEMORY ERROR\n");
}
return(ret) ;
}
int Trick::MSSharedMem::connect() {
int ret ;
/** @par Detailed Design */
/** @li Call tsm_init to create shared memory for slave. */
if (tsm_dev.size == 0) {
tsm_dev.size = sizeof(MSSharedMemData);
ret = tsm_init(&tsm_dev);
} else {
ret = tsm_reconnect(&tsm_dev);
}
shm_addr = (MSSharedMemData*) tsm_dev.addr;
return(ret) ;
}
int Trick::MSSharedMem::disconnect() {
return(0) ;
}
double Trick::MSSharedMem::read_wait(struct timespec *in_start) {
struct timespec ts_Current, ts_Difference;
RELEASE();
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Current);
if ((ts_Current.tv_nsec - in_start->tv_nsec) < 0) {
ts_Difference.tv_sec = ts_Current.tv_sec - in_start->tv_sec - 1;
ts_Difference.tv_nsec = 1000000000 + ts_Current.tv_nsec - in_start->tv_nsec;
} else {
ts_Difference.tv_sec = ts_Current.tv_sec - in_start->tv_sec;
ts_Difference.tv_nsec = ts_Current.tv_nsec - in_start->tv_nsec;
}
// return the total elapsed time we've waited since in_start
return ((double)ts_Difference.tv_nsec / 1000000000.0) + ts_Difference.tv_sec;
}
long long Trick::MSSharedMem::read_time() {
long long in_time;
double readtry_time = 0.0;
struct timespec ts_Start;
/** @par Detailed Design */
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
/** @li Get time from shared memory */
while (MSQ_ISEMPTY(shm_addr->master_time)) {
if (readtry_time >= sync_wait_limit) {
break;
}
readtry_time = read_wait(&ts_Start);
}
if (!MSQ_ISEMPTY(shm_addr->master_time)) {
in_time = MSQ_FRONT(shm_addr->master_time);
//fprintf(stderr, "+++++read_time pid=%d time=%lld readtry=%f\n", getpid(), in_time, readtry_time);
MSQ_POP(shm_addr->master_time);
return (in_time) ;
/** @li If no new data before timeout limit, return "error" time */
} else {
//fprintf(stderr, "+++++read_time pid=%d time=%lld ERROR readtry=%f\n", getpid(), in_time, readtry_time,); fflush(stderr);
return (MS_ERROR_TIME) ;
}
}
MS_SIM_COMMAND Trick::MSSharedMem::read_command() {
MS_SIM_COMMAND command;
double readtry_time = 0.0;
struct timespec ts_Start;
/** @par Detailed Design */
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
if (getpid() == shm_addr->master_pid) {
/** @li Get slave command from shared memory */
// I am master, so read slave command
while (MSQ_ISEMPTY(shm_addr->slave_command)) {
if (readtry_time >= sync_wait_limit) {
break;
}
readtry_time = read_wait(&ts_Start);
}
if (!MSQ_ISEMPTY(shm_addr->slave_command)) {
command = MSQ_FRONT(shm_addr->slave_command);
//fprintf(stderr, "+++++read_command pid=%d command=%d (from slave)\n", getpid(), command);
MSQ_POP(shm_addr->slave_command);
return (command) ;
/** @li If no new data before timeout limit, return "error" command */
} else {
//fprintf(stderr, "+++++read_command pid=%d command=%d (from slave) ERROR readtry=%f\n", getpid(), command, readtry_time);
return (MS_ErrorCmd) ;
}
} else {
/** @li Get master command from shared memory */
// I am slave, so read master command
while (MSQ_ISEMPTY(shm_addr->master_command)) {
if (readtry_time >= sync_wait_limit) {
break;
}
readtry_time = read_wait(&ts_Start);
}
if (!MSQ_ISEMPTY(shm_addr->master_command)) {
command = MSQ_FRONT(shm_addr->master_command);
//fprintf(stderr, "+++++read_command pid=%d command=%d (from master)\n", getpid(), command);
MSQ_POP(shm_addr->master_command);
return (command) ;
/** @li If no new data before timeout limit, return "error" command */
} else {
//fprintf(stderr, "+++++read_command pid=%d command=%d (from master) ERROR readtry=%f\n", getpid(), command, readtry_time);
return (MS_ErrorCmd) ;
}
}
}
int Trick::MSSharedMem::read_port() {
int in_port;
double readtry_time = 0.0;
struct timespec ts_Start;
/** @par Detailed Design */
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
/** @li Get port number from shared memory */
while (shm_addr->slave_port == MS_ERROR_PORT) {
if (readtry_time >= sync_wait_limit) {
break;
}
readtry_time = read_wait(&ts_Start);
}
if (shm_addr->slave_port != MS_ERROR_PORT) {
in_port = shm_addr->slave_port;
shm_addr->slave_port = MS_ERROR_PORT; // default value
return (in_port) ;
/** @li If no new data before timeout limit, return "error" port */
} else {
return (MS_ERROR_PORT) ;
}
}
char Trick::MSSharedMem::read_name(char * read_data, size_t size) {
double readtry_time = 0.0;
struct timespec ts_Start;
/** @par Detailed Design */
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start);
/** @li Get name (character array) from shared memory */
while (shm_addr->chkpnt_name[0] == MS_ERROR_NAME) {
if (readtry_time >= sync_wait_limit) {
break;
}
readtry_time = read_wait(&ts_Start);
}
if (shm_addr->chkpnt_name[0] != MS_ERROR_NAME) {
memcpy(read_data, shm_addr->chkpnt_name, size);
shm_addr->chkpnt_name[0] = MS_ERROR_NAME; // default value
return (0) ;
/** @li If no new data before timeout limit, return "error" name */
} else {
return (MS_ERROR_NAME) ;
}
}
int Trick::MSSharedMem::write_time(long long in_time) {
/** @par Detailed Design */
/** @li Write time to shared memory */
//fprintf(stderr, "====write_time pid=%d time=%lld\n", getpid(), in_time);
MSQ_PUSH(shm_addr->master_time, in_time);
/** @li Return the number of bytes written */
return(sizeof(long long)) ;
}
int Trick::MSSharedMem::write_command(MS_SIM_COMMAND command) {
/** @par Detailed Design */
/** @li Write command to shared memory */
if (getpid() == shm_addr->master_pid) {
//fprintf(stderr, "====write_command pid=%d command=%d (master)\n", getpid(), command);
MSQ_PUSH(shm_addr->master_command, command);
} else {
//fprintf(stderr, "====write_command pid=%d command=%d (slave)\n", getpid(), command);
MSQ_PUSH(shm_addr->slave_command, command);
}
/** @li Return the number of bytes written */
return(sizeof(MS_SIM_COMMAND)) ;
}
int Trick::MSSharedMem::write_port(int in_port) {
/** @par Detailed Design */
/** @li Write port number to shared memory */
shm_addr->slave_port = in_port;
/** @li Return the number of bytes written */
return(sizeof(int)) ;
}
int Trick::MSSharedMem::write_name(char * in_data, size_t size) {
/** @par Detailed Design */
/** @li Write name (character array) to shared memory */
memcpy(shm_addr->chkpnt_name, in_data, size);
/** @li Return the number of bytes written */
return(size);
}