Browse Source

better failed-case handling

David Rose 16 years ago
parent
commit
9ecc675b72

+ 2 - 3
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)
 

+ 1 - 0
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')

+ 11 - 0
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

+ 34 - 5
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();
   }
 }
 

+ 4 - 0
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;

+ 17 - 11
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;

+ 7 - 0
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;
 

+ 48 - 3
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

+ 2 - 0
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().

+ 1 - 1
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':