00001 #include "sim.h"
00002 #include "Main.h"
00003 #include "Motion.h"
00004 #include "SoundPlay.h"
00005 #include "Simulator.h"
00006 #include "SharedGlobals.h"
00007 #include "SimConfig.h"
00008 #include "local/DataSource.h"
00009 #include "IPC/SharedObject.h"
00010 #include "IPC/RegionRegistry.h"
00011 #include "IPC/FailsafeThread.h"
00012 #include "Shared/Config.h"
00013 #include "Shared/string_util.h"
00014 #include "Shared/StackTrace.h"
00015 #include "Shared/zignor.h"
00016 #include "Shared/RobotInfo.h"
00017 #include "IPC/SemaphoreManager.h"
00018 #include "Events/EventRouter.h"
00019 #include "Motion/Kinematics.h"
00020 #include <iostream>
00021 #include <sstream>
00022 #include <iomanip>
00023 #include <sys/ipc.h>
00024 #include <signal.h>
00025 #include <unistd.h>
00026 #include <sys/wait.h>
00027 #include <sys/stat.h>
00028 #include <errno.h>
00029 #include <pwd.h>
00030 #include <algorithm>
00031 #include <fcntl.h>
00032
00033 #ifndef DISABLE_READLINE
00034 # include <readline/readline.h>
00035 #endif
00036
00037 #ifdef __APPLE__
00038 # include <CoreFoundation/CoreFoundation.h>
00039 #endif
00040
00041 #ifndef TEKKOTSU_SHM_STYLE
00042 # error TEKKOTSU_SHM_STYLE unset!
00043 #endif
00044
00045 using namespace std;
00046
00047 INSTANTIATE_NAMEDENUMERATION_STATICS(SharedGlobals::runlevel_t);
00048
00049 const char * const sim::usage=
00050 "[-h|--help] [-c|--config config-file] [-s|--seed s1,s2,s3] [cmd1 cmd2 ...]\n"
00051 "\n"
00052 "Commands passed as arguments are commonly of the form var=val, but can\n"
00053 "also be any valid simulator command, such as 'freeze'. If you wish to\n"
00054 "pass a multi-word command, encase the command in quotes.\n"
00055 "\n"
00056 "The first --seed argument is passed to srand and srandom, the second\n"
00057 "and third are passed to the zignor library for normally distributed"
00058 "random numbers.";
00059
00060
00061 bool sim::original=true;
00062
00063 SimConfig sim::config;
00064 vector<string> sim::cmdlineArgs;
00065 pid_t sim::child=static_cast<pid_t>(-1);
00066 bool sim::showRunlevels=false;
00067 termios sim::ttyMode;
00068 vector<Thread*> sim::primaries;
00069 sim::ConfigErrorCheck sim::cfgCheck;
00070
00071 #ifndef __APPLE__
00072
00073 template<typename T>
00074 struct PrimaryThread : public Thread {
00075 virtual void* run() { sim::manage_process<T>(); return NULL; }
00076 };
00077 #else
00078 static Thread::Lock primaryThreadLock;
00079
00080
00081 template<typename T>
00082 struct PrimaryThread : public Thread {
00083 virtual void* run() {
00084 sim::manage_process<T>();
00085 {
00086 MarkScope lock(primaryThreadLock);
00087 vector<Thread*>::iterator it = find(sim::primaries.begin(),sim::primaries.end(),this);
00088 if(it==sim::primaries.end()) {
00089 std::cerr << "WARNING could not find thread for " << ProcessID::getIDStr() << " in sim::primaries" << std::endl;
00090 } else {
00091 sim::primaries.erase(it);
00092 if(sim::primaries.empty())
00093 CFRunLoopStop(CFRunLoopGetMain());
00094 }
00095 }
00096 return NULL;
00097 }
00098 virtual void dereference() {
00099 delete this;
00100 }
00101 };
00102 #endif
00103
00104
00105
00106 int main(int argc, const char* argv[]) {
00107
00108
00109
00110 ProcessID::setID(ProcessID::SimulatorProcess);
00111
00112
00113 Thread::initMainThread();
00114
00115 #if TEKKOTSU_SHM_STYLE==POSIX_SHM
00116 #ifndef USE_UNBACKED_SHM
00117
00118 struct passwd * pw=getpwuid(getuid());
00119 if(pw!=NULL) {
00120 if(RCRegion::shmRoot[RCRegion::shmRoot.size()-1]=='/') {
00121 RCRegion::shmRoot[RCRegion::shmRoot.size()-1]='-';
00122 RCRegion::shmRoot+=pw->pw_name;
00123 RCRegion::shmRoot+='/';
00124 } else {
00125 RCRegion::shmRoot+=pw->pw_name;
00126 }
00127 }
00128 #endif
00129 #elif TEKKOTSU_SHM_STYLE==NO_SHM
00130 sim::cfgCheck.holdMultiprocess();
00131 #endif
00132
00133 {
00134 sim s;
00135 if(!s.processCommandLine(argc,argv))
00136 return 2;
00137
00138 if(!s.run())
00139 return 1;
00140 return 0;
00141 }
00142 }
00143
00144 sim::sim()
00145 : mutexSemMgr(), glob(), subj(),
00146 srandSeed(1), zigSeed1(12345), zigSeed2(54321)
00147 {
00148 #ifndef DISABLE_READLINE
00149
00150 int fd = getTermFD();
00151 if(fd<0 || tcgetattr(fd, &ttyMode) == -1)
00152 cerr << "tcgetattr failed, could not store terminal state in case of error shutdown" << endl;
00153 close(fd);
00154 #endif
00155
00156
00157 MutexLockBase::usleep_granularity=measure_usleep_cost();
00158
00159 project_get_time::get_time_callback=&sim_get_time;
00160 project_get_time::get_timeScale_callback=&sim_getTimeScale;
00161
00162 ProjectInterface::sendCommand=Simulator::sendCommand;
00163
00164
00165 signal(SIGHUP, handle_signal);
00166 signal(SIGINT, handle_signal);
00167 signal(SIGQUIT, handle_signal);
00168 signal(SIGILL, handle_signal);
00169 signal(SIGABRT, handle_signal);
00170 signal(SIGFPE, handle_signal);
00171 signal(SIGBUS, handle_signal);
00172 signal(SIGSEGV, handle_signal);
00173 signal(SIGSYS, handle_signal);
00174 signal(SIGPIPE, SIG_IGN);
00175 #ifdef __linux__
00176
00177
00178 signal(SIGCHLD, SIG_IGN);
00179 #endif
00180 signal(SIGTERM, handle_signal);
00181 atexit(handle_exit);
00182
00183 #if TEKKOTSU_SHM_STYLE!=NO_SHM
00184
00185 MutexLockBase::setSemaphoreManager(&(*mutexSemMgr));
00186 #endif
00187
00188 MessageQueueBase::setSemaphoreManager(&(*mutexSemMgr));
00189
00190
00191 globals = &(*glob);
00192 sim::config.addEntry("WaitForSensors",globals->waitForSensors,"If true, wait for initial sensor readings before triggering the startup behavior or starting the motion polling thread. On some platforms (e.g. Dynamixel based actuators), sensed output values can be used to initialize output positions. On others, you may be unable to get any feedback, or can only expect feedback if the robot was left running and the executable is reconnecting (e.g. SSC-32).");
00193 sim::config.addEntry("Speed",globals->timeScale,"The speed at which to run the simulation, as a multiple of \"real-time\".\nFor example, '1' is normal, '0.5' is half-speed, '0' is paused.\nAny negative value requests full-speed mode, where the clock is moved as fast as processing (or manual control) allows.");
00194 globals->simulatorTime=sim::config.initSimTime;
00195 sim::config.addEntry("Motion",globals->motion,"Parameters for motion simulation");
00196 sim::config.addEntry("Sensors",globals->sensors,"Parameters for sensor updates");
00197 sim::config.addEntry("Vision",globals->vision,"Parameters for camera frames");
00198 DataSource::setSensorState(&globals->sensorState);
00199
00200
00201 ipc_setup = &(*subj);
00202
00203
00204 ::config = new Config();
00205 ::config->setFileSystemRoot("ms");
00206 if(::config->loadFile("config/tekkotsu.xml")==0) {
00207 if(::config->loadFile("config/tekkotsu.cfg")==0)
00208 std::cerr << std::endl << " *** ERROR: Could not load configuration file config/tekkotsu.xml *** " << std::endl << std::endl;
00209 else
00210 std::cerr << "Successfully imported settings from old-format tekkotsu.cfg" << std::endl;
00211 }
00212 if(::config->loadFile("config/sim_ovrd.xml")==0)
00213 if(::config->loadFile("config/sim_ovrd.cfg")!=0)
00214 std::cerr << "Successfully imported settings from old-format simulator.cfg" << std::endl;
00215 ::erouter = new EventRouter;
00216
00217
00218 if(::config->main.seed_rng) {
00219 struct timeval tp;
00220 gettimeofday(&tp,NULL);
00221 zigSeed1 = tp.tv_sec + tp.tv_usec;
00222 zigSeed2 = tp.tv_usec;
00223
00224 union {
00225 double t;
00226 unsigned int tm[2];
00227 };
00228 t=TimeET().Value();
00229 srandSeed=tm[0]+tm[1];
00230 }
00231 }
00232
00233 bool sim::processCommandLine(int argc, const char* argv[]) {
00234 int i=0;
00235
00236
00237 string halconfigfile;
00238 halconfigfile.append("hal-").append(RobotName).append(".plist");
00239 struct stat sb;
00240 if(stat(halconfigfile.c_str(),&sb)==0) {
00241 if(!sim::config.loadFile(halconfigfile.c_str())) {
00242 cerr << "Error loading default configuration file '" << halconfigfile << "', may be malformed." << endl;
00243 return false;
00244 }
00245 } else {
00246
00247 string defaultfile;
00248 defaultfile.assign("defaults/hal-common.plist");
00249 if(stat(defaultfile.c_str(),&sb)==0) {
00250 if(!sim::config.loadFile(defaultfile.c_str())) {
00251 cerr << "Error loading defaults file '" << defaultfile << "', may be malformed." << endl;
00252 return false;
00253 }
00254 }
00255 defaultfile.assign("defaults/hal-").append(RobotName).append(".plist");
00256 if(stat(defaultfile.c_str(),&sb)==0) {
00257 if(!sim::config.loadFile(defaultfile.c_str())) {
00258 cerr << "Error loading defaults file '" << defaultfile << "', may be malformed." << endl;
00259 return false;
00260 }
00261 }
00262 sim::config.setLastFile(halconfigfile);
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272 config.cmdPrompt="HAL:";
00273 config.cmdPrompt.append(RobotName).append("> ");
00274
00275
00276 for(i++; i<argc; i++) {
00277
00278 if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) {
00279 cerr << "Usage:\n" << argv[0] << " " << usage << endl;
00280 return false;
00281
00282 } else if(!strcmp(argv[i],"-c") || !strcmp(argv[i],"--config")) {
00283 if(i==argc-1) {
00284 std::cerr << "ERROR: Missing --config filename argument" << std::endl;
00285 return false;
00286 }
00287 if(!sim::config.loadFile(argv[++i]))
00288 return false;
00289
00290 } else if(!strcmp(argv[i],"-s") || !strcmp(argv[i],"--seed") || !strcmp(argv[i],"--seeds")) {
00291 if(i==argc-1) {
00292 std::cerr << "Missing --seed argument" << std::endl;
00293 return false;
00294 }
00295 std::string s = argv[++i];
00296 std::replace(s.begin(),s.end(),',',' ');
00297 std::stringstream ss(s);
00298 ss >> srandSeed >> zigSeed1 >> zigSeed2;
00299
00300 } else if(strchr(argv[i],'=')!=NULL) {
00301 string value=string_util::trim(strchr(argv[i],'=')+1);
00302 string key=string_util::trim(string(argv[i],strchr(argv[i],'=')-argv[i]));
00303 plist::ObjectBase* ob=sim::config.resolveEntry(key);
00304 if(ob==NULL)
00305 cmdlineArgs.push_back(argv[i]);
00306 else if(plist::PrimitiveBase* pbp=dynamic_cast<plist::PrimitiveBase*>(ob)) {
00307 try {
00308 pbp->set(value);
00309 } catch(const XMLLoadSave::bad_format& bf) {
00310 cout << "'" << value << "' is a bad value for '" << key << "'" << endl;
00311 cout << bf.what() << endl;
00312 return false;
00313 } catch(const std::exception& e) {
00314 cout << "An exception occured: " << e.what() << endl;
00315 return false;
00316 }
00317 } else {
00318 cout << "Cannot assign to a dictionary ("<<key<<")" << endl;
00319 return false;
00320 }
00321 } else {
00322 cmdlineArgs.push_back(argv[i]);
00323 }
00324 }
00325
00326 return true;
00327 }
00328
00329
00330 extern const char * TEKKOTSU_VERSION;
00331 extern const char * LIBTEKKOTSU_DATE;
00332 extern const char * LIBTEKKOTSU_TIME;
00333
00334 bool sim::run() {
00335 std::cout << "Tekkotsu Robotics Framework " << TEKKOTSU_VERSION;
00336 #ifndef NO_LIBTEKKOTSU
00337 std::cout << ", libtekkotsu compiled on " << LIBTEKKOTSU_DATE << " at " << LIBTEKKOTSU_TIME;
00338 #endif
00339 std::cout << std::endl;
00340
00341 srand(srandSeed);
00342 srandom(srandSeed);
00343 RanNormalSetSeedZig32(&zigSeed1,zigSeed2);
00344
00345
00346 cfgCheck.holdMultiprocess();
00347 RCRegion::setMultiprocess(config.multiprocess);
00348 if(!config.multiprocess) {
00349 ProcessID::setIDHooks(getProcessID,setProcessID);
00350
00351
00352 if(wireless==NULL) {
00353 wireless = new Wireless();
00354 sout=wireless->socket(Socket::SOCK_STREAM,Wireless::WIRELESS_DEF_RECV_SIZE,Wireless::WIRELESS_DEF_SEND_SIZE*12);
00355 serr=wireless->socket(Socket::SOCK_STREAM,Wireless::WIRELESS_DEF_RECV_SIZE,Wireless::WIRELESS_DEF_SEND_SIZE*4);
00356 wireless->setDaemon(sout);
00357 wireless->setDaemon(serr);
00358 serr->setFlushType(Socket::FLUSH_BLOCKING);
00359 sout->setTextForward();
00360 serr->setForward(sout);
00361 }
00362
00363
00364 if(kine==NULL)
00365 kine=new Kinematics();
00366 }
00367
00368 if(config.tgtRunlevel!=SharedGlobals::RUNNING)
00369 showRunlevels=true;
00370
00371
00372
00373 globals->level_count[SharedGlobals::CREATED]++;
00374
00375
00376
00377
00378
00379 if(fork_process<Main>()) ;
00380 else if(fork_process<Motion>()) ;
00381 else if(fork_process<SoundPlay>()) ;
00382 else if(config.multiprocess)
00383 manage_process<Simulator>();
00384 else {
00385 fork_process<Simulator>();
00386 globals->level_count[SharedGlobals::CREATED]--;
00387 #ifdef __APPLE__
00388
00389
00390 CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
00391 CFRunLoopAddSource(CFRunLoopGetCurrent(), CFRunLoopSourceCreate(NULL,0,&context), kCFRunLoopDefaultMode);
00392 CFRunLoopRun();
00393 #else
00394
00395 while(primaries.size()>0) {
00396 primaries.back()->join();
00397 delete primaries.back();
00398 primaries.pop_back();
00399 }
00400 #endif
00401 }
00402
00403
00404 globals->level_count[SharedGlobals::DESTRUCTED]++;
00405
00406 return true;
00407 }
00408
00409 sim::~sim() {
00410 #if TEKKOTSU_SHM_STYLE!=NO_SHM
00411 MutexLockBase::setSemaphoreManager(NULL);
00412 #endif
00413 MessageQueueBase::setSemaphoreManager(NULL);
00414 globals=NULL;
00415 ipc_setup=NULL;
00416
00417 if(child==static_cast<pid_t>(-1))
00418 return;
00419
00420 if(child!=0) {
00421 CallbackThread waitChild(&sim::wait_child,*this,true);
00422 FailsafeThread failsafe(waitChild,1.5,true);
00423 if(waitChild.join()==Thread::CANCELLED)
00424 cout << ProcessID::getIDStr() << ": Waiting for child (pid " << child << ") to exit..." << endl;
00425 wait_child();
00426 }
00427 }
00428
00429 void sim::wait_child() {
00430 int status;
00431 int res=waitpid(child,&status,0);
00432 Thread::testCurrentCancel();
00433 if(res<0 && errno!=ECHILD)
00434 perror("wait");
00435 }
00436
00437 void sim::wait_runlevel(SharedGlobals::runlevel_t level) {
00438 globals->lock.lock(ProcessID::getID());
00439 globals->level_count[level]++;
00440 if(globals->level_count[level]==1 && showRunlevels) {
00441 cout.setf(ios::left);
00442 cout << "Collecting for runlevel " << setw(12) << SharedGlobals::runlevel_names[level] << " |=" << flush;
00443 cout.unsetf(ios::left);
00444 }
00445 string nm=Process::getName();
00446 if(showRunlevels)
00447 cout << nm << '=' << flush;
00448 if(globals->level_count[level]==globals->level_count[SharedGlobals::CREATED] && showRunlevels)
00449 cout << "| done" << endl;
00450 globals->lock.unlock();
00451 while(globals->level_count[level]!=globals->level_count[SharedGlobals::CREATED])
00452 usleep(150*1000);
00453 globals->lock.lock(ProcessID::getID());
00454 globals->lock.unlock();
00455 }
00456
00457 template<class T>
00458 void sim::manage_process() {
00459
00460 globals->lock.lock(T::getID());
00461 globals->level_count[SharedGlobals::CONSTRUCTING]++;
00462
00463 T t;
00464 ASSERT(T::getID()==ProcessID::getID(),"Process ID set incorrectly!");
00465
00466 globals->lock.unlock();
00467 while(globals->level_count[SharedGlobals::CONSTRUCTING]!=globals->level_count[SharedGlobals::CREATED])
00468 usleep(150*1000);
00469 globals->lock.lock(ProcessID::getID());
00470 globals->lock.unlock();
00471
00472
00473 wait_runlevel(SharedGlobals::STARTING);
00474 t.start();
00475 wait_runlevel(SharedGlobals::RUNNING);
00476 t.run();
00477 wait_runlevel(SharedGlobals::STOPPING);
00478 t.stop();
00479 wait_runlevel(SharedGlobals::DESTRUCTING);
00480 }
00481
00482 template<class T>
00483 bool sim::fork_process() {
00484 if(config.multiprocess) {
00485 RCRegion::aboutToFork(T::getID());
00486 MutexLockBase::aboutToFork();
00487 }
00488
00489 globals->level_count[SharedGlobals::CREATED]++;
00490 if(config.multiprocess) {
00491 child=fork();
00492 if(child==static_cast<pid_t>(-1)) {
00493 cerr << "Unable to spawn simulator process!" << endl;
00494 exit(1);
00495 }
00496 if(child!=0) {
00497 manage_process<T>();
00498 return true;
00499 }
00500 original=false;
00501 } else {
00502 primaries.push_back(new PrimaryThread<T>());
00503 primaries.back()->start();
00504 }
00505 return false;
00506 }
00507
00508 ProcessID::ProcessID_t sim::getProcessID() {
00509 Thread* th=Thread::getCurrent();
00510 if(th==NULL)
00511 return ProcessID::SimulatorProcess;
00512 return static_cast<ProcessID::ProcessID_t>(reinterpret_cast<size_t>(th->getGroup()));
00513 }
00514 void sim::setProcessID(ProcessID::ProcessID_t id) {
00515 Thread* th=Thread::getCurrent();
00516 ASSERTRET(th!=NULL,"Unable to set process ID for main thread");
00517 th->setGroup(reinterpret_cast<void*>(id));
00518 }
00519
00520 int sim::getTermFD() {
00521 const char TERM[] = "/dev/tty";
00522 int fd = open(TERM, O_RDWR);
00523 if (fd < 0)
00524 cerr << "Unable to open terminal " << TERM << endl;
00525
00526 return fd;
00527 }
00528
00529 void sim::handle_signal(int sig) {
00530
00531
00532
00533 sigset_t mask_set;
00534 sigfillset(&mask_set);
00535 sigprocmask(SIG_SETMASK, &mask_set, NULL);
00536
00537 const char * name=NULL;
00538 char defBuf[30];
00539 switch(sig) {
00540 case SIGINT: name="SIGINT"; break;
00541 case SIGQUIT: name="SIGQUIT"; break;
00542 case SIGBUS: name="SIGBUS"; break;
00543 case SIGSEGV: name="SIGSEGV"; break;
00544 case SIGTERM: name="SIGTERM"; break;
00545 case SIGABRT: name="SIGABRT"; break;
00546 case SIGFPE: name="SIGFPE"; break;
00547 case SIGPIPE: name="SIGPIPE"; break;
00548 case SIGHUP: name="SIGHUP"; break;
00549 default:
00550 name=defBuf;
00551 snprintf(defBuf,30,"signal %d",sig);
00552 break;
00553 }
00554 cout << "*** ERROR " << Process::getName() << ": Received " << name << endl;
00555
00556 static bool firstCall=true;
00557 static bool inBackTrace=false;
00558 if(!firstCall && !inBackTrace) {
00559 cerr << "Signal handler was recursively called, may be leaked IPC resources :(" << endl;
00560 cerr << "The 'ipcs' tool can be used to manually free these, if it becomes a problem. " << endl;
00561 cerr << "However, simply re-running will generally reclaim the previous buffers for you." << endl;
00562 _exit(EXIT_FAILURE);
00563 return;
00564 }
00565 firstCall=false;
00566
00567 #ifndef DISABLE_READLINE
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 int fd = getTermFD();
00578 if(fd<0 || tcsetattr(fd, TCSADRAIN, &ttyMode) == -1)
00579 cerr << "tcsetattr failed, could not restore terminal state" << endl;
00580 close(fd);
00581 #endif
00582
00583 if(sig!=SIGINT && sig!=SIGTERM && !inBackTrace) {
00584 inBackTrace=true;
00585 stacktrace::displayCurrentStackTrace(25);
00586 inBackTrace=false;
00587 }
00588
00589 cout << "*** ERROR " << Process::getName() << ": Engaging fault shutdown..." << endl;
00590 badExitCleanup();
00591 _exit(EXIT_FAILURE);
00592 }
00593
00594 void sim::handle_exit() {
00595 static bool firstCall=true;
00596 if(!firstCall) {
00597 cerr << "handle_exit was recursively called" << endl;
00598 return;
00599 }
00600 firstCall=false;
00601 #ifndef DISABLE_READLINE
00602 rl_reset_terminal(NULL);
00603
00604
00605 int fd = getTermFD();
00606 if(fd<0 || tcsetattr(fd, TCSADRAIN, &ttyMode) == -1)
00607 cerr << "tcsetattr failed, could not restore terminal state" << endl;
00608 close(fd);
00609 #endif
00610
00611 if(RCRegion::NumberOfAttach()==0) {
00612
00613
00614 return;
00615 }
00616 cout << "*** ERROR " << Process::getName() << ": Exit with attached memory regions, engaging fault shutdown..." << endl;
00617 badExitCleanup();
00618 }
00619
00620 void sim::badExitCleanup() {
00621 if(globals!=NULL && !globals->hadFault()) {
00622 if(!MessageQueueBase::getSemaphoreManager()->hadFault())
00623 globals->lock.lock(ProcessID::getID());
00624 if(globals->level_count[SharedGlobals::CREATED]>0)
00625 globals->level_count[SharedGlobals::CREATED]--;
00626 else
00627 cout << "*** ERROR " << Process::getName() << ": level_count[CREATED] underflow" << endl;
00628 globals->signalShutdown();
00629 if(!MessageQueueBase::getSemaphoreManager()->hadFault())
00630 globals->lock.unlock();
00631 globals->faultShutdown();
00632 } else {
00633 cerr << "*** ERROR " << Process::getName() << ": exit with previous global fault" << endl;
00634 }
00635
00636 if(MessageQueueBase::getSemaphoreManager()!=NULL && !MessageQueueBase::getSemaphoreManager()->hadFault()) {
00637 cout << "*** ERROR " << Process::getName() << ": Dereferencing message queue SemaphoreManager" << endl;
00638 MessageQueueBase::getSemaphoreManager()->faultShutdown();
00639 MessageQueueBase::setSemaphoreManager(NULL);
00640 #if TEKKOTSU_SHM_STYLE!=NO_SHM
00641 MutexLockBase::setSemaphoreManager(NULL);
00642 #endif
00643 } else {
00644 cerr << "*** ERROR " << Process::getName() << ": exit with previous SemaphoreManager fault" << endl;
00645 }
00646
00647 #if TEKKOTSU_SHM_STYLE!=NO_SHM
00648 if(MutexLockBase::getSemaphoreManager()==NULL) {
00649 cerr << "*** ERROR " << Process::getName() << ": Mutex semaphore manager is NULL? (should have reset to internal manager)" << endl;
00650 } else if(!MutexLockBase::getSemaphoreManager()->hadFault()) {
00651 cout << "*** ERROR " << Process::getName() << ": Dereferencing mutex SemaphoreManager" << endl;
00652 MutexLockBase::getSemaphoreManager()->faultShutdown();
00653 MutexLockBase::setSemaphoreManager(NULL);
00654 MutexLockBase::getSemaphoreManager()->faultShutdown();
00655 } else {
00656 cerr << "*** ERROR " << Process::getName() << ": exit with previous SemaphoreManager fault" << endl;
00657 }
00658
00659 cout << "*** ERROR " << Process::getName() << ": Dereferencing shared memory regions" << endl;
00660 RCRegion::faultShutdown();
00661 #endif
00662
00663 cout << "*** ERROR " << Process::getName() << ": Exiting..." << endl;
00664 }
00665
00666 unsigned int sim::measure_usleep_cost() {
00667 usleep(50000);
00668 const unsigned int TRIALS=50;
00669 TimeET mintime(1.0);
00670 for(unsigned int i=0; i<TRIALS; i++) {
00671
00672 TimeET cur;
00673 usleep(1);
00674 TimeET elapsed(cur.Age());
00675 if(elapsed<mintime)
00676 mintime=elapsed;
00677 }
00678 usleep(50000);
00679 TimeET minover(1.0);
00680 for(unsigned int i=0; i<TRIALS; i++) {
00681
00682 TimeET cur;
00683 TimeET elapsed(cur.Age());
00684 if(elapsed<minover)
00685 minover=elapsed;
00686 }
00687 if(mintime<minover) {
00688 mintime=0L;
00689
00690 } else {
00691
00692 mintime-=minover;
00693
00694 if(mintime<2L) {
00695 mintime=2L;
00696
00697 }
00698
00699 }
00700 return static_cast<unsigned>(mintime.Value()*1.0e6);
00701 }
00702
00703 sim::ConfigErrorCheck::ConfigErrorCheck() : PrimitiveListener(), holdMPValue(config.multiprocess) {}
00704
00705 sim::ConfigErrorCheck::~ConfigErrorCheck() {
00706 sim::config.multiprocess.removePrimitiveListener(this);
00707 }
00708
00709 void sim::ConfigErrorCheck::plistValueChanged(const plist::PrimitiveBase& pl) {
00710 if(&pl==&sim::config.multiprocess) {
00711 #if TEKKOTSU_SHM_STYLE==NO_SHM
00712 if(sim::config.multiprocess) {
00713 cerr << "ERROR: TEKKOTSU_SHM_STYLE was set to NO_SHM during compile, Muliprocess cannot be set to 'true'" << endl;
00714 sim::config.multiprocess=false;
00715 }
00716 #else
00717 # ifdef DEBUG
00718 cerr << "sim::config.Multiprocess set to " << sim::config.multiprocess << endl;
00719 # endif
00720 if(holdMPValue!=sim::config.multiprocess) {
00721 cerr << "ERROR: Cannot change sim::config.Multiprocess during execution, must set from command line or load from settings file" << endl;
00722 sim::config.multiprocess=holdMPValue;
00723 }
00724 #endif
00725 }
00726 }
00727
00728 void sim::ConfigErrorCheck::holdMultiprocess() {
00729 holdMPValue=sim::config.multiprocess;
00730 sim::config.multiprocess.addPrimitiveListener(this);
00731 }