diff --git a/direct/src/plugin/p3dDownload.I b/direct/src/plugin/p3dDownload.I index 812b6e862f..5eff54903c 100755 --- a/direct/src/plugin/p3dDownload.I +++ b/direct/src/plugin/p3dDownload.I @@ -23,6 +23,28 @@ get_url() const { return _url; } +//////////////////////////////////////////////////////////////////// +// Function: P3DDownload::set_instance +// Access: Public +// Description: Specifies the particular P3DInstance that is +// responsible for downloading this object. +//////////////////////////////////////////////////////////////////// +inline void P3DDownload:: +set_instance(P3DInstance *instance) { + _instance = instance; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DDownload::get_instance +// Access: Public +// Description: Returns the particular P3DInstance that is +// responsible for downloading this object. +//////////////////////////////////////////////////////////////////// +inline P3DInstance *P3DDownload:: +get_instance() const { + return _instance; +} + //////////////////////////////////////////////////////////////////// // Function: P3DDownload::get_download_progress // Access: Public diff --git a/direct/src/plugin/p3dDownload.cxx b/direct/src/plugin/p3dDownload.cxx index 9dd20e6f93..f5aae868e9 100755 --- a/direct/src/plugin/p3dDownload.cxx +++ b/direct/src/plugin/p3dDownload.cxx @@ -30,6 +30,7 @@ P3DDownload() { _canceled = false; _download_id = 0; + _instance = NULL; } //////////////////////////////////////////////////////////////////// @@ -50,6 +51,7 @@ P3DDownload(const P3DDownload ©) : _canceled = false; _download_id = 0; + _instance = NULL; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dDownload.h b/direct/src/plugin/p3dDownload.h index 0dd2494a1f..b7adffe595 100755 --- a/direct/src/plugin/p3dDownload.h +++ b/direct/src/plugin/p3dDownload.h @@ -17,6 +17,7 @@ #include "p3d_plugin_common.h" #include "p3dReferenceCount.h" +class P3DInstance; #include @@ -37,6 +38,9 @@ public: void set_url(const string &url); inline const string &get_url() const; + inline void set_instance(P3DInstance *instance); + inline P3DInstance *get_instance() const; + inline double get_download_progress() const; inline bool is_download_progress_known() const; inline bool get_download_finished() const; @@ -78,6 +82,7 @@ private: bool _canceled; int _download_id; string _url; + P3DInstance *_instance; }; #include "p3dDownload.I" diff --git a/direct/src/plugin/p3dHost.cxx b/direct/src/plugin/p3dHost.cxx index a2813287a1..c14be5b177 100644 --- a/direct/src/plugin/p3dHost.cxx +++ b/direct/src/plugin/p3dHost.cxx @@ -63,6 +63,12 @@ P3DHost:: } } _packages.clear(); + + FailedPackages::iterator pi; + for (pi = _failed_packages.begin(); pi != _failed_packages.end(); ++pi) { + delete (*pi); + } + _failed_packages.clear(); } //////////////////////////////////////////////////////////////////// @@ -285,13 +291,21 @@ get_package(const string &package_name, const string &package_version, string key = package_name + "_" + package_version; PackageMap::iterator pi = package_map.find(key); if (pi != package_map.end()) { - return (*pi).second; + P3DPackage *package = (*pi).second; + if (!package->get_failed()) { + return package; + } + + // If the package has previously failed, move it aside and try + // again (maybe it just failed because the user interrupted it). + nout << "Package " << key << " has previously failed; trying again.\n"; + _failed_packages.push_back(package); + (*pi).second = NULL; } P3DPackage *package = new P3DPackage(this, package_name, package_version, alt_host); - bool inserted = package_map.insert(PackageMap::value_type(key, package)).second; - assert(inserted); + package_map[key] = package; return package; } diff --git a/direct/src/plugin/p3dHost.h b/direct/src/plugin/p3dHost.h index 4caffb48e5..29fc14439a 100644 --- a/direct/src/plugin/p3dHost.h +++ b/direct/src/plugin/p3dHost.h @@ -91,6 +91,8 @@ private: typedef map PackageMap; typedef map Packages; Packages _packages; + typedef vector FailedPackages; + FailedPackages _failed_packages; friend class P3DInstanceManager; }; diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 81e87c4d92..8f19b24b30 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -269,6 +269,9 @@ P3DInstance:: Downloads::iterator di; for (di = _downloads.begin(); di != _downloads.end(); ++di) { P3DDownload *download = (*di).second; + if (download->get_instance() == this) { + download->set_instance(NULL); + } p3d_unref_delete(download); } _downloads.clear(); @@ -880,12 +883,16 @@ feed_url_stream(int unique_id, } P3DDownload *download = (*di).second; + assert(download->get_instance() == this); bool download_ok = download->feed_url_stream (result_code, http_status_code, total_expected_data, this_data, this_data_size); if (!download_ok || download->get_download_finished()) { // All done. + if (download->get_instance() == this) { + download->set_instance(NULL); + } _downloads.erase(di); p3d_unref_delete(download); } @@ -1128,6 +1135,7 @@ start_download(P3DDownload *download, bool add_request) { int download_id = inst_mgr->get_unique_id(); download->set_download_id(download_id); + download->set_instance(this); download->ref(); bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index a42cf01662..8f5ab57def 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -129,8 +129,14 @@ P3DInstanceManager:: sigaction(SIGPIPE, &_old_sigpipe, NULL); #endif // _WIN32 - assert(_instances.empty()); + // force-finish any remaining instances. + while (!_instances.empty()) { + P3DInstance *inst = *(_instances.begin()); + finish_instance(inst); + } + assert(_sessions.empty()); + assert(_instances.empty()); if (_auth_session != NULL) { p3d_unref_delete(_auth_session); @@ -421,11 +427,12 @@ start_instance(P3DInstance *inst) { //////////////////////////////////////////////////////////////////// void P3DInstanceManager:: finish_instance(P3DInstance *inst) { - nout << "finish_instance\n"; + nout << "finish_instance: " << inst << "\n"; Instances::iterator ii; ii = _instances.find(inst); - assert(ii != _instances.end()); - _instances.erase(ii); + if (ii != _instances.end()) { + _instances.erase(ii); + } Sessions::iterator si = _sessions.find(inst->get_session_key()); if (si != _sessions.end()) { @@ -442,9 +449,7 @@ finish_instance(P3DInstance *inst) { } inst->cleanup(); - nout << "done cleanup, calling delete\n"; p3d_unref_delete(inst); - nout << "done finish_instance\n"; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 9b993e0672..6f4d69566c 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -1197,6 +1197,37 @@ is_extractable(FileSpec &file, const string &filename) const { return false; } + +//////////////////////////////////////////////////////////////////// +// Function: P3DPackage::instance_terminating +// Access: Private +// Description: Called when P3D_RC_shutdown is received by any +// Download object, which indicates that the instance +// owning this download object is terminating and we +// should either find a new instance or abort the +// download. +// +// The return value is true if a new instance is +// available, or false if not. +//////////////////////////////////////////////////////////////////// +bool P3DPackage:: +instance_terminating(P3DInstance *instance) { + if (_instances.empty() || + (_instances.size() == 1 && instance == _instances[0])) { + // No other instances. + return false; + } + + // There are more instances available to continue this download; + // pick one of them. Move this one to the end of the list. + Instances::iterator ii = find(_instances.begin(), _instances.end(), instance); + if (ii != _instances.end()) { + _instances.erase(ii); + _instances.push_back(instance); + } + return true; +} + //////////////////////////////////////////////////////////////////// // Function: P3DPackage::Download::Constructor // Access: Public @@ -1423,10 +1454,24 @@ do_step(bool download_finished) { if (_download->get_download_success()) { // The Download object has already validated the hash. return IT_step_complete; + } else if (_download->get_download_terminated()) { - // The download was interrupted because we're shutting down. - // Don't try any other plans. - return IT_terminate; + // The download was interrupted because its instance is shutting + // down. Don't try any other plans, unless we have some more + // instances. + P3DInstance *instance = _download->get_instance(); + if (!_package->instance_terminating(instance)) { + // That was the only instance referencing this package, so stop + // the download. + nout << "Terminating download of " << _urlbase << "\n"; + return IT_terminate; + } + nout << "Restarting download of " << _urlbase << " on new instance\n"; + + p3d_unref_delete(_download); + _download = NULL; + return IT_continue; + } else { // The Download object has already tried all of the mirrors, and // they all failed. diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h index 72f6b70f8f..ddf8a1e683 100755 --- a/direct/src/plugin/p3dPackage.h +++ b/direct/src/plugin/p3dPackage.h @@ -213,6 +213,7 @@ private: void set_saved_download(Download *download); bool is_extractable(FileSpec &file, const string &filename) const; + bool instance_terminating(P3DInstance *instance); public: class RequiredPackage { diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index 3de1c4d129..a578129f51 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/direct/src/plugin/p3d_plugin.cxx @@ -86,6 +86,7 @@ P3D_initialize(int api_version, const char *contents_filename, void P3D_finalize() { + nout << "P3D_finalize called\n"; P3DInstanceManager::delete_global_ptr(); } diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index fc695635f4..14d4d8d63c 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -336,6 +336,7 @@ stop_outstanding_streams() { NPStream *stream = (*si); nout << "Stopping stream " << (void *)stream << "\n"; browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); + destroy_stream(stream, NPRES_USER_BREAK); } assert(_streams.empty()); @@ -450,9 +451,7 @@ write_stream(NPStream *stream, int offset, int len, void *buffer) { NPError PPInstance:: destroy_stream(NPStream *stream, NPReason reason) { Streams::iterator si = find(_streams.begin(), _streams.end(), stream); - if (si == _streams.end()) { - nout << "Got destroy_stream for unknown stream\n"; - } else { + if (si != _streams.end()) { _streams.erase(si); } diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 7f759a6e28..79b54d8666 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -418,10 +418,11 @@ NPP_SetWindow(NPP instance, NPWindow *window) { NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16_t *stype) { - nout << "NewStream " << type << ", " << stream->url - << ", " << stream->end + nout << "NewStream " << type << ": " << (void *)stream + << ", " << stream->url << ", size = " << stream->end << ", notifyData = " << stream->notifyData - << "\n"; + << ", for " << instance + << ", " << (PPInstance *)(instance->pdata) << "\n"; PPInstance::generic_browser_call(); PPInstance *inst = (PPInstance *)(instance->pdata); assert(inst != NULL); @@ -436,8 +437,7 @@ NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, //////////////////////////////////////////////////////////////////// NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) { - nout << "DestroyStream " << stream->url - << ", " << stream->end + nout << "DestroyStream: " << (void *)stream << ", " << stream->url << ", notifyData = " << stream->notifyData << ", reason = " << reason << ", for " << instance