#include #include #include // for memcpy #include #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); }