From 9ecc675b72be5ff2ad53f0b50964bc67844d59cf Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 14 Oct 2009 13:33:05 +0000 Subject: [PATCH] better failed-case handling --- direct/src/p3d/coreapi.pdef | 5 +-- direct/src/p3d/panda3d.pdef | 1 + direct/src/plugin/p3dInstance.I | 11 +++++ direct/src/plugin/p3dInstance.cxx | 39 +++++++++++++++--- direct/src/plugin/p3dInstance.h | 4 ++ direct/src/plugin/p3dInstanceManager.cxx | 28 ++++++++----- direct/src/plugin/p3dOsxSplashWindow.cxx | 7 ++++ direct/src/plugin/p3dSession.cxx | 51 ++++++++++++++++++++++-- direct/src/plugin/p3dSession.h | 2 + direct/src/plugin_standalone/panda3d.cxx | 2 +- 10 files changed, 127 insertions(+), 23 deletions(-) diff --git a/direct/src/p3d/coreapi.pdef b/direct/src/p3d/coreapi.pdef index 00d3ce65e5..d9ced83ed8 100644 --- a/direct/src/p3d/coreapi.pdef +++ b/direct/src/p3d/coreapi.pdef @@ -26,7 +26,7 @@ class coreapi(solo): class images(package): # The default startup images are stored as their own package. - names = ['download', 'play_click', 'play_ready', 'play_rollover', + names = ['download', 'failed', 'play_click', 'play_ready', 'play_rollover', 'auth_click', 'auth_ready', 'auth_rollover'] configDict = {} for name in names: @@ -55,13 +55,12 @@ class images(package): print "Could not locate %s" % (filename) # Also make a few special cases. We use the same default image - # for download, ready, unauth, launch, and failed. + # for download, ready, unauth, and launch. download = configDict.get('download_img', None) if download: configDict['ready_img'] = download configDict['unauth_img'] = download configDict['launch_img'] = download - configDict['failed_img'] = download config(**configDict) diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef index 1a21169fd9..af23fa1a91 100755 --- a/direct/src/p3d/panda3d.pdef +++ b/direct/src/p3d/panda3d.pdef @@ -156,6 +156,7 @@ audio-library-name miles_audio class audio(package): # This package includes the best audio library for the given # platform, assuming a non-commercial application. + require('panda3d') if platform.startswith('osx'): require('fmod') diff --git a/direct/src/plugin/p3dInstance.I b/direct/src/plugin/p3dInstance.I index c42d516d09..1d2b979b18 100644 --- a/direct/src/plugin/p3dInstance.I +++ b/direct/src/plugin/p3dInstance.I @@ -107,6 +107,17 @@ is_started() const { return (_session != NULL); } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::is_failed +// Access: Public +// Description: Returns true if this instance has tried and failed to +// launch for some reason. +//////////////////////////////////////////////////////////////////// +inline bool P3DInstance:: +is_failed() const { + return _failed; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::ImageFile::Constructor // Access: Public diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index fedc53e4c6..b0031d7c68 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -93,11 +93,13 @@ P3DInstance(P3D_request_ready_func *func, P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); _instance_id = inst_mgr->get_unique_id(); + _has_log_basename = false; _hidden = (_fparams.lookup_token_int("hidden") != 0); _allow_python_dev = false; _keep_user_env = false; _auto_start = false; _auth_button_approved = false; + _failed = false; _session = NULL; _auth_session = NULL; _panda3d = NULL; @@ -320,6 +322,7 @@ set_p3d_filename(const string &p3d_filename) { if (!_mf_reader.open_read(_fparams.get_p3d_filename())) { nout << "Couldn't read " << _fparams.get_p3d_filename() << "\n"; + set_failed(); return; } @@ -1189,6 +1192,9 @@ void P3DInstance:: mark_p3d_untrusted() { // Failed test. nout << "p3d untrusted\n"; + if (is_failed()) { + return; + } if (_p3dcert_package == NULL) { // We have to go download this package. @@ -1238,7 +1244,7 @@ mark_p3d_trusted() { stringstream sstream; if (!_mf_reader.extract_one(sstream, "p3d_info.xml")) { nout << "No p3d_info.xml file found in " << _fparams.get_p3d_filename() << "\n"; - // TODO: fail. + set_failed(); } else { sstream.seekg(0); @@ -1296,8 +1302,10 @@ scan_app_desc_file(TiXmlDocument *doc) { _xpackage = (TiXmlElement *)xpackage->Clone(); const char *log_basename = _xpackage->Attribute("log_basename"); + _has_log_basename = false; if (log_basename != NULL) { _log_basename = log_basename; + _has_log_basename = false; } TiXmlElement *xconfig = _xpackage->FirstChildElement("config"); @@ -1675,6 +1683,21 @@ handle_script_request(const string &operation, P3D_object *object, } } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::set_failed +// Access: Private +// Description: Sets the "failed" indication to display sadness to +// the user--we're unable to launch the instance for +// some reason. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +set_failed() { + _failed = true; + set_button_image(IT_none); + set_background_image(IT_failed); + make_splash_window(); +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::make_splash_window // Access: Private @@ -1698,6 +1721,12 @@ make_splash_window() { make_visible = false; } + if (_failed) { + // But, if we've failed to launch somehow, we need to let the user + // know. + make_visible = true; + } + if (_splash_window != NULL) { // Already got one. _splash_window->set_visible(make_visible); @@ -1929,7 +1958,7 @@ start_next_download() { while (_download_package_index < (int)_downloading_packages.size()) { P3DPackage *package = _downloading_packages[_download_package_index]; if (package->get_failed()) { - // Too bad. TODO: fail. + set_failed(); return; } @@ -2001,8 +2030,8 @@ mark_download_complete() { //////////////////////////////////////////////////////////////////// void P3DInstance:: ready_to_start() { - if (is_started()) { - // Already started. + if (is_started() || is_failed()) { + // Already started--or never mind. return; } @@ -2160,7 +2189,7 @@ report_package_done(P3DPackage *package, bool success) { report_package_progress(package, 1.0); start_next_download(); } else { - // TODO: fail. + set_failed(); } } diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 5a75a855d6..db171f2a20 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -99,6 +99,7 @@ public: inline bool is_trusted() const; void start_download(P3DDownload *download); inline bool is_started() const; + inline bool is_failed() const; void request_stop_sub_thread(); void request_stop_main_thread(); void request_refresh(); @@ -164,6 +165,7 @@ private: const string &property_name, P3D_object *value, bool needs_response, int unique_id); + void set_failed(); void make_splash_window(); void set_background_image(ImageType image_type); void set_button_image(ImageType image_type); @@ -226,11 +228,13 @@ private: int _instance_id; string _session_key; string _log_basename; + bool _has_log_basename; bool _hidden; bool _allow_python_dev; bool _keep_user_env; bool _auto_start; bool _auth_button_approved; + bool _failed; P3DSession *_session; P3DAuthSession *_auth_session; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 1b6d82f4dc..31637d2742 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -222,17 +222,18 @@ initialize(const string &contents_filename, const string &host_url, _log_basename = P3D_PLUGIN_LOG_BASENAME2; } #endif - if (!_log_basename.empty()) { - _log_pathname = _log_directory; - _log_pathname += _log_basename; - _log_pathname += ".log"; - - logfile.clear(); - logfile.open(_log_pathname.c_str(), ios::out | ios::trunc); - if (logfile) { - logfile.setf(ios::unitbuf); - nout_stream = &logfile; - } + if (_log_basename.empty()) { + _log_basename = "p3dcore"; + } + _log_pathname = _log_directory; + _log_pathname += _log_basename; + _log_pathname += ".log"; + + logfile.clear(); + logfile.open(_log_pathname.c_str(), ios::out | ios::trunc); + if (logfile) { + logfile.setf(ios::unitbuf); + nout_stream = &logfile; } // Determine the temporary directory. @@ -434,6 +435,11 @@ set_p3d_filename(P3DInstance *inst, bool is_local, //////////////////////////////////////////////////////////////////// bool P3DInstanceManager:: start_instance(P3DInstance *inst) { + if (inst->is_failed()) { + // Don't bother trying again. + return false; + } + if (inst->is_started()) { // Already started. return true; diff --git a/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx index 6a400e23c1..ec4c597a8b 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.cxx +++ b/direct/src/plugin/p3dOsxSplashWindow.cxx @@ -90,6 +90,7 @@ set_wparams(const P3DWindowParams &wparams) { EventTypeSpec list1[] = { { kEventClassWindow, kEventWindowDrawContent }, { kEventClassWindow, kEventWindowBoundsChanged }, + { kEventClassWindow, kEventWindowClose }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseMoved }, @@ -605,6 +606,12 @@ event_callback(EventHandlerCallRef my_handler, EventRef event) { case kEventWindowDrawContent: paint_window(); + break; + + case kEventWindowClose: + // When the user closes the splash window, stop the instance. + _inst->request_stop_sub_thread(); + break; }; break; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 796739da46..cda5f6da11 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -56,6 +56,8 @@ P3DSession(P3DInstance *inst) { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); _session_id = inst_mgr->get_unique_id(); _session_key = inst->get_session_key(); + _keep_user_env = false; + _failed = false; _start_dir = inst_mgr->get_root_dir() + "/start"; _p3dpython_one_process = false; @@ -214,6 +216,10 @@ void P3DSession:: start_instance(P3DInstance *inst) { assert(inst->_session == NULL); assert(inst->get_session_key() == _session_key); + if (_failed) { + inst->set_failed(); + return; + } inst->ref(); ACQUIRE_LOCK(_instances_lock); @@ -342,6 +348,7 @@ command_and_response(TiXmlDocument *command) { // in recursively. _response_ready.release(); Instances::iterator ii; + // TODO: should we acquire _instances_lock? Deadlock concerns? for (ii = _instances.begin(); ii != _instances.end(); ++ii) { P3DInstance *inst = (*ii).second; inst->bake_requests(); @@ -678,6 +685,7 @@ start_p3dpython(P3DInstance *inst) { if (inst->_panda3d == NULL) { nout << "Couldn't start Python: no panda3d dependency.\n"; + set_failed(); return; } @@ -823,7 +831,7 @@ start_p3dpython(P3DInstance *inst) { const char *dont_keep[] = { "PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "PYTHONPATH", "PYTHONHOME", "PRC_PATH", "PANDA_PRC_PATH", - "TEMP", + "TEMP", "CTPROJS", NULL }; @@ -931,19 +939,24 @@ start_p3dpython(P3DInstance *inst) { // Get the log filename from the p3d_info.xml file. string log_basename = inst->_log_basename; + bool has_log_basename = inst->_has_log_basename; // But we also let it be overridden by the tokens. if (inst->get_fparams().has_token("log_basename")) { log_basename = inst->get_fparams().lookup_token("log_basename"); + has_log_basename = true; } + if (!has_log_basename) { #ifdef P3D_PLUGIN_LOG_BASENAME3 - if (log_basename.empty()) { // No log_basename specified for the app; use the compiled-in // default. log_basename = P3D_PLUGIN_LOG_BASENAME3; - } #endif + if (log_basename.empty()) { + log_basename = "p3dsession"; + } + } // However, it is always written into the log directory only; the // user may not override the log file to put it anywhere else. @@ -975,6 +988,7 @@ start_p3dpython(P3DInstance *inst) { // Create the pipe to the process. if (!CreatePipe(&r_to, &w_to, NULL, 0)) { nout << "failed to create pipe\n"; + set_failed(); } else { // Make sure the right end of the pipe is inheritable. SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); @@ -984,6 +998,7 @@ start_p3dpython(P3DInstance *inst) { // Create the pipe from the process. if (!CreatePipe(&r_from, &w_from, NULL, 0)) { nout << "failed to create pipe\n"; + set_failed(); } else { // Make sure the right end of the pipe is inheritable. SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); @@ -1000,10 +1015,12 @@ start_p3dpython(P3DInstance *inst) { int to_fd[2]; if (pipe(to_fd) < 0) { perror("failed to create pipe"); + set_failed(); } int from_fd[2]; if (pipe(from_fd) < 0) { perror("failed to create pipe"); + set_failed(); } _input_handle = to_fd[0]; @@ -1012,6 +1029,10 @@ start_p3dpython(P3DInstance *inst) { _pipe_write.open_write(to_fd[1]); #endif // _WIN32 + if (_failed) { + return; + } + // Get the filename of the Panda3D multifile. We need to pass this // to p3dpython. _mf_filename = inst->_panda3d->get_archive_file_pathname(); @@ -1074,6 +1095,30 @@ start_p3dpython(P3DInstance *inst) { _commands.clear(); } +//////////////////////////////////////////////////////////////////// +// Function: P3DSession::set_failed +// Access: Private +// Description: Sets the "failed" indication to display sadness to +// the user--we're unable to launch the instance for +// some reason. +// +// When this is called on the P3DSession instead of on a +// particular P3DInstance, it means that all instances +// attached to this session are marked failed. +//////////////////////////////////////////////////////////////////// +void P3DSession:: +set_failed() { + _failed = true; + + Instances::iterator ii; + ACQUIRE_LOCK(_instances_lock); + for (ii = _instances.begin(); ii != _instances.end(); ++ii) { + P3DInstance *inst = (*ii).second; + inst->set_failed(); + } + RELEASE_LOCK(_instances_lock); +} + //////////////////////////////////////////////////////////////////// // Function: P3DSession::spawn_read_thread // Access: Private diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index cf5417c29c..a53beda66d 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -64,6 +64,7 @@ public: private: void start_p3dpython(P3DInstance *inst); + void set_failed(); void spawn_read_thread(); void join_read_thread(); @@ -93,6 +94,7 @@ private: string _python_root_dir; string _start_dir; bool _keep_user_env; + bool _failed; // This information is passed to create_process(), or to // p3dpython_thread_run(). diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 4d6639b829..7661ce557b 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -152,7 +152,7 @@ run(int argc, char *argv[]) { case 'l': _log_dirname = Filename::from_os_specific(optarg).to_os_specific(); - _log_basename = "panda3d"; + _log_basename = "p3dcore"; break; case 'i':