X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fglobals.cxx;h=796b18cd8f66d1ef35085ca9f8b738efd2534056;hb=6fc24034495c8a9932600e366615d500f1a5a66a;hp=fb3a35480c044c8d6e5cafa3d993526582a01126;hpb=47e802e6747cea6e6e9bc21f6b11c2885a29f694;p=flightgear.git diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index fb3a35480..796b18cd8 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -43,20 +43,17 @@ #include #include #include +#include #include #include -#include #include -#include #include -#include #include #include #include #include #include -#include #include "globals.hxx" #include "locale.hxx" @@ -71,29 +68,44 @@ public: simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH) { } - + virtual SGPath resolve(const std::string& aResource, SGPath&) const { string_list pieces(sgPathBranchSplit(aResource)); if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) { return SGPath(); // not an Aircraft path } - + // test against the aircraft-dir property const char* aircraftDir = fgGetString("/sim/aircraft-dir"); string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir)); if (!aircraftDirPieces.empty() && (aircraftDirPieces.back() == pieces[1])) { + // disable this warning for release builds +#if defined(ENABLE_DEV_WARNINGS) + SGPath betterPath; + for (unsigned int i=2; iget_aircraft_paths()); @@ -104,7 +116,7 @@ public: return p; } } // of aircraft path iteration - + return SGPath(); // not found } }; @@ -116,7 +128,7 @@ public: simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH) { } - + virtual SGPath resolve(const std::string& aResource, SGPath&) const { const char* aircraftDir = fgGetString("/sim/aircraft-dir"); @@ -136,7 +148,6 @@ FGGlobals *globals = NULL; // Constructor FGGlobals::FGGlobals() : - initial_state( NULL ), renderer( new FGRenderer ), subsystem_mgr( new SGSubsystemMgr ), event_mgr( new SGEventMgr ), @@ -144,24 +155,16 @@ FGGlobals::FGGlobals() : fg_root( "" ), fg_home( "" ), time_params( NULL ), - ephem( NULL ), - matlib( NULL ), - route_mgr( NULL ), - ATIS_mgr( NULL ), - controls( NULL ), - viewmgr( NULL ), commands( SGCommandMgr::instance() ), channel_options_list( NULL ), initial_waypoints( NULL ), - fontcache ( new FGFontCache ), channellist( NULL ), - haveUserSettings(false), - _chatter_queue(NULL) + haveUserSettings(false) { SGPropertyNode* root = new SGPropertyNode; props = SGPropertyNode_ptr(root); locale = new FGLocale(props); - + simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider); simgear::ResourceManager::instance()->addProvider(new CurrentAircraftDirProvider); initProperties(); @@ -170,15 +173,15 @@ FGGlobals::FGGlobals() : void FGGlobals::initProperties() { simgear::PropertyObjectBase::setDefaultRoot(props); - + positionLon = props->getNode("position/longitude-deg", true); positionLat = props->getNode("position/latitude-deg", true); positionAlt = props->getNode("position/altitude-ft", true); - + viewLon = props->getNode("sim/current-view/viewer-lon-deg", true); viewLat = props->getNode("sim/current-view/viewer-lat-deg", true); viewAlt = props->getNode("sim/current-view/viewer-elev-ft", true); - + orientPitch = props->getNode("orientation/pitch-deg", true); orientHeading = props->getNode("orientation/heading-deg", true); orientRoll = props->getNode("orientation/roll-deg", true); @@ -186,67 +189,61 @@ void FGGlobals::initProperties() } // Destructor -FGGlobals::~FGGlobals() +FGGlobals::~FGGlobals() { // save user settings (unless already saved) saveUserSettings(); - // The AIModels manager performs a number of actions upon - // Shutdown that implicitly assume that other subsystems - // are still operational (Due to the dynamic allocation and - // deallocation of AIModel objects. To ensure we can safely - // shut down all subsystems, make sure we take down the - // AIModels system first. - SGSubsystemRef ai = subsystem_mgr->get_subsystem("ai-model"); - if (ai) { - subsystem_mgr->remove("ai-model"); - ai->unbind(); - ai.clear(); // ensure AI is deleted now, not at end of this method + // stop OSG threading first, to avoid thread races while we tear down + // scene-graph pieces + + osg::ref_ptr vw(renderer->getViewer()); + if (vw) { + // https://code.google.com/p/flightgear-bugs/issues/detail?id=1291 + // explicitly stop trheading before we delete the renderer or + // viewMgr (which ultimately holds refs to the CameraGroup, and + // GraphicsContext) + vw->stopThreading(); } - - subsystem_mgr->shutdown(); - subsystem_mgr->unbind(); - subsystem_mgr->remove("aircraft-model"); - subsystem_mgr->remove("tile-manager"); - subsystem_mgr->remove("model-manager"); - _tile_mgr.clear(); + subsystem_mgr->shutdown(); + subsystem_mgr->unbind(); + subsystem_mgr->remove(FGTileMgr::subsystemName()); // don't cancel the pager until after shutdown, since AIModels (and // potentially others) can queue delete requests on the pager. - if (renderer->getViewer() && renderer->getViewer()->getDatabasePager()) { - renderer->getViewer()->getDatabasePager()->cancel(); - renderer->getViewer()->getDatabasePager()->clear(); + if (vw && vw->getDatabasePager()) { + vw->getDatabasePager()->cancel(); + vw->getDatabasePager()->clear(); } + osgDB::Registry::instance()->clearObjectCache(); - + subsystem_mgr->remove(FGScenery::subsystemName()); + // renderer touches subsystems during its destruction set_renderer(NULL); - _scenery.clear(); - _chatter_queue.clear(); - + delete subsystem_mgr; - subsystem_mgr = NULL; // important so ::get_subsystem returns NULL + subsystem_mgr = NULL; // important so ::get_subsystem returns NULL + vw = 0; // don't delete the viewer until now delete time_params; set_matlib(NULL); - delete route_mgr; - delete ATIS_mgr; + delete channel_options_list; delete initial_waypoints; - delete fontcache; delete channellist; simgear::PropertyObjectBase::setDefaultRoot(NULL); simgear::SGModelLib::resetPropertyRoot(); - + delete locale; locale = NULL; - + cleanupListeners(); - + props.clear(); - + delete commands; } @@ -266,14 +263,15 @@ void FGGlobals::set_fg_root (const std::string &root) { << fg_root << "'\n***\n***"); } - // remove /sim/fg-root before writing to prevent hijacking + // deliberately not a tied property, for fgValidatePath security + // write-protect to avoid accidents SGPropertyNode *n = fgGetNode("/sim", true); - n->removeChild("fg-root", 0, false); + n->removeChild("fg-root", 0); n = n->getChild("fg-root", 0, true); n->setStringValue(fg_root.c_str()); n->setAttribute(SGPropertyNode::WRITE, false); - - simgear::ResourceManager::instance()->addBasePath(fg_root, + + simgear::ResourceManager::instance()->addBasePath(fg_root, simgear::ResourceManager::PRIORITY_DEFAULT); } @@ -308,7 +306,7 @@ void FGGlobals::append_data_path(const SGPath& path) if (!path.exists()) { SG_LOG(SG_GENERAL, SG_WARN, "adding non-existant data path:" << path); } - + additional_data_paths.push_back(path); } @@ -320,28 +318,27 @@ SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const return p; } } - + SGPath rootPath(fg_root); rootPath.append(pathSuffix); if (rootPath.exists()) { return rootPath; } - + SG_LOG(SG_GENERAL, SG_WARN, "dir not found in any data path:" << pathSuffix); return SGPath(); } -void FGGlobals::append_fg_scenery (const std::string &paths) +void FGGlobals::append_fg_scenery (const std::string &paths, bool secure) { -// fg_scenery.clear(); SGPropertyNode* sim = fgGetNode("/sim", true); // find first unused fg-scenery property in /sim int propIndex = 0; while (sim->getChild("fg-scenery", propIndex) != NULL) { - ++propIndex; + ++propIndex; } - + BOOST_FOREACH(const SGPath& path, sgPathSplit( paths )) { SGPath abspath(path.realpath()); if (!abspath.exists()) { @@ -355,55 +352,94 @@ void FGGlobals::append_fg_scenery (const std::string &paths) SG_LOG(SG_GENERAL, SG_INFO, "skipping duplicate add of scenery path:" << abspath.str()); continue; } - + + // tell the ResouceManager about the scenery path + // needed to load Models from this scenery path + simgear::ResourceManager::instance()->addBasePath(abspath.str(), + simgear::ResourceManager::PRIORITY_DEFAULT); + simgear::Dir dir(abspath); SGPath terrainDir(dir.file("Terrain")); SGPath objectsDir(dir.file("Objects")); - - // this code used to add *either* the base dir, OR add the + + // this code used to add *either* the base dir, OR add the // Terrain and Objects subdirs, but the conditional logic was commented // out, such that all three dirs are added. Unfortunately there's // no information as to why the change was made. fg_scenery.push_back(abspath.str()); - + if (secure) { + secure_fg_scenery.push_back(abspath.str()); + } + if (terrainDir.exists()) { fg_scenery.push_back(terrainDir.str()); } - + if (objectsDir.exists()) { fg_scenery.push_back(objectsDir.str()); } - + // insert a marker for FGTileEntry::load(), so that // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "", // "B/Terrain", "B/Objects", ""] fg_scenery.push_back(""); - + // make scenery dirs available to Nasal SGPropertyNode* n = sim->getChild("fg-scenery", propIndex++, true); n->setStringValue(abspath.str()); n->setAttribute(SGPropertyNode::WRITE, false); + + // temporary fix so these values survive reset + n->setAttribute(SGPropertyNode::PRESERVE, true); } // of path list iteration } +void FGGlobals::clear_fg_scenery() +{ + fg_scenery.clear(); + secure_fg_scenery.clear(); + fgGetNode("/sim", true)->removeChildren("fg-scenery"); + +} + +void FGGlobals::set_catalog_aircraft_path(const SGPath& path) +{ + catalog_aircraft_dir = path; +} + +string_list FGGlobals::get_aircraft_paths() const +{ + string_list r; + if (!catalog_aircraft_dir.isNull()) { + r.push_back(catalog_aircraft_dir.str()); + } + + r.insert(r.end(), fg_aircraft_dirs.begin(), fg_aircraft_dirs.end()); + return r; +} + void FGGlobals::append_aircraft_path(const std::string& path) { SGPath dirPath(path); if (!dirPath.exists()) { - SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path); + SG_LOG(SG_GENERAL, SG_ALERT, "aircraft path not found:" << path); return; } + + SGPath acSubdir(dirPath); + acSubdir.append("Aircraft"); + if (acSubdir.exists()) { + SG_LOG( + SG_GENERAL, + SG_WARN, + "Specified an aircraft-dir with an 'Aircraft' subdirectory:" << dirPath + << ", will instead use child directory:" << acSubdir + ); + dirPath = acSubdir; + } + std::string abspath = dirPath.realpath(); - - unsigned int index = fg_aircraft_dirs.size(); fg_aircraft_dirs.push_back(abspath); - -// make aircraft dirs available to Nasal - SGPropertyNode* sim = fgGetNode("/sim", true); - sim->removeChild("fg-aircraft", index, false); - SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); - n->setStringValue(abspath); - n->setAttribute(SGPropertyNode::WRITE, false); } void FGGlobals::append_aircraft_paths(const std::string& path) @@ -441,7 +477,7 @@ void FGGlobals::set_renderer(FGRenderer *render) if (render == renderer) { return; } - + delete renderer; renderer = render; } @@ -453,12 +489,12 @@ FGGlobals::get_subsystem_mgr () const } SGSubsystem * -FGGlobals::get_subsystem (const char * name) +FGGlobals::get_subsystem (const char * name) const { if (!subsystem_mgr) { return NULL; } - + return subsystem_mgr->get_subsystem(name); } @@ -471,15 +507,6 @@ FGGlobals::add_subsystem (const char * name, subsystem_mgr->add(name, subsystem, type, min_time_sec); } -SGSoundMgr * -FGGlobals::get_soundmgr () const -{ - if (subsystem_mgr) - return (SGSoundMgr*) subsystem_mgr->get_subsystem("sound"); - - return NULL; -} - SGEventMgr * FGGlobals::get_event_mgr () const { @@ -528,18 +555,30 @@ static void treeDumpRefCounts(int depth, SGPropertyNode* nd) if (SGReferenced::count(cp) > 1) { SG_LOG(SG_GENERAL, SG_INFO, "\t" << cp->getPath() << " refcount:" << SGReferenced::count(cp)); } - + treeDumpRefCounts(depth + 1, cp); } } +static void treeClearAliases(SGPropertyNode* nd) +{ + if (nd->isAlias()) { + nd->unalias(); + } + + for (int i=0; inChildren(); ++i) { + SGPropertyNode* cp = nd->getChild(i); + treeClearAliases(cp); + } +} + void FGGlobals::resetPropertyRoot() { delete locale; - + cleanupListeners(); - + // we don't strictly need to clear these (they will be reset when we // initProperties again), but trying to reduce false-positives when dumping // ref-counts. @@ -552,49 +591,27 @@ FGGlobals::resetPropertyRoot() orientPitch.clear(); orientHeading.clear(); orientRoll.clear(); - + + // clear aliases so ref-counts are accurate when dumped + treeClearAliases(props); + SG_LOG(SG_GENERAL, SG_INFO, "root props refcount:" << props.getNumRefs()); treeDumpRefCounts(0, props); //BaseStackSnapshot::dumpAll(std::cout); - + props = new SGPropertyNode; initProperties(); locale = new FGLocale(props); - + // remove /sim/fg-root before writing to prevent hijacking SGPropertyNode *n = props->getNode("/sim", true); - n->removeChild("fg-root", 0, false); + n->removeChild("fg-root", 0); n = n->getChild("fg-root", 0, true); n->setStringValue(fg_root.c_str()); n->setAttribute(SGPropertyNode::WRITE, false); } -// Save the current state as the initial state. -void -FGGlobals::saveInitialState () -{ - initial_state = new SGPropertyNode(); - - // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd - int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ - SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; - int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; - if (!copyProperties(props, initial_state, expected, checked)) - SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state"); - - // delete various properties from the initial state, since we want to - // preserve their values even if doing a restore - // => Properties should now use the PRESERVE flag to protect their values - // on sim-reset. Remove some specific properties for backward compatibility. - SGPropertyNode* sim = initial_state->getChild("sim"); - SGPropertyNode* cameraGroupNode = sim->getNode("rendering/camera-group"); - if (cameraGroupNode) { - cameraGroupNode->removeChild("camera"); - cameraGroupNode->removeChild("gui"); - } -} - static std::string autosaveName() { std::ostringstream os; @@ -602,33 +619,11 @@ static std::string autosaveName() if (versionParts.size() < 2) { return "autosave.xml"; } - + os << "autosave_" << versionParts[0] << "_" << versionParts[1] << ".xml"; return os.str(); } -// Restore the saved initial state, if any -void -FGGlobals::restoreInitialState () -{ - if ( initial_state == 0 ) { - SG_LOG(SG_GENERAL, SG_ALERT, - "No initial state available to restore!!!"); - return; - } - // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd - int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ - SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; - int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; - if ( copyProperties(initial_state, props, expected, checked)) { - SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" ); - } else { - SG_LOG( SG_GENERAL, SG_INFO, - "Some errors restoring initial state (read-only props?)" ); - } - -} - // Load user settings from autosave.xml void FGGlobals::loadUserSettings(const SGPath& dataPath) @@ -676,12 +671,6 @@ FGGlobals::saveUserSettings() } } -FGViewer * -FGGlobals::get_current_view () const -{ - return viewmgr->get_current_view(); -} - long int FGGlobals::get_warp() const { return fgGetInt("/sim/time/warp"); @@ -704,39 +693,33 @@ void FGGlobals::set_warp_delta( long int d ) FGScenery* FGGlobals::get_scenery () const { - return _scenery.get(); + return get_subsystem(); } -void FGGlobals::set_scenery ( FGScenery *s ) +FGTileMgr* FGGlobals::get_tile_mgr () const { - _scenery = s; + return get_subsystem(); } -FGTileMgr* FGGlobals::get_tile_mgr () const +FGViewMgr *FGGlobals::get_viewmgr() const { - return _tile_mgr.get(); + return get_subsystem(); } -void FGGlobals::set_tile_mgr ( FGTileMgr *t ) +flightgear::View* FGGlobals::get_current_view () const { - _tile_mgr = t; + FGViewMgr* vm = get_viewmgr(); + return vm ? vm->get_current_view() : 0; } void FGGlobals::set_matlib( SGMaterialLib *m ) { - if (matlib) - delete matlib; matlib = m; } -FGSampleQueue* FGGlobals::get_chatter_queue() const -{ - return _chatter_queue; -} - -void FGGlobals::set_chatter_queue(FGSampleQueue* queue) +FGControls *FGGlobals::get_controls() const { - _chatter_queue = queue; + return get_subsystem(); } void FGGlobals::addListenerToCleanup(SGPropertyChangeListener* l) @@ -753,4 +736,14 @@ void FGGlobals::cleanupListeners() _listeners_to_cleanup.clear(); } +simgear::pkg::Root* FGGlobals::packageRoot() +{ + return _packageRoot.get(); +} + +void FGGlobals::setPackageRoot(const SGSharedPtr& p) +{ + _packageRoot = p; +} + // end of globals.cxx