From: Braden M. <br...@us...> - 2007-09-04 22:45:35
|
Update of /cvsroot/openvrml/openvrml/src/openvrml-xembed In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv24948/src/openvrml-xembed Modified Files: gtkvrmlbrowser.cpp main.cpp plugin_streambuf.cpp plugin_streambuf.h Log Message: If two requests for the same resource are made, it is possible that the one picked from the uninitialized_plugin_streambuf_map_ for the purpose of calling set_get_url_result will be one for which that has already been called. This change introduces the requested_plugin_streambuf_map_, which is a holding area for streambufs for which set_get_url_result has not yet been called. Index: plugin_streambuf.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/plugin_streambuf.cpp,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** plugin_streambuf.cpp 15 May 2007 04:06:11 -0000 1.6 --- plugin_streambuf.cpp 4 Sep 2007 22:45:36 -0000 1.7 *************** *** 46,49 **** --- 46,54 ---- g_assert(this->get_url_result_ == -1); this->get_url_result_ = result; + const boost::shared_ptr<plugin_streambuf> this_ = shared_from_this(); + requested_plugin_streambuf_map_.erase(*this); + if (result == 0) { + uninitialized_plugin_streambuf_map_.insert(this->url_, this_); + } this->received_get_url_result_.notify_all(); } *************** *** 66,70 **** g_assert(!type.empty()); boost::mutex::scoped_lock lock(this->mutex_); ! bool succeeded = uninitialized_plugin_streambuf_map_.erase(this->url_); g_assert(succeeded); this->url_ = received_url; --- 71,75 ---- g_assert(!type.empty()); boost::mutex::scoped_lock lock(this->mutex_); ! bool succeeded = uninitialized_plugin_streambuf_map_.erase(*this); g_assert(succeeded); this->url_ = received_url; *************** *** 81,85 **** boost::mutex::scoped_lock lock(this->mutex_); const bool succeeded = ! uninitialized_plugin_streambuf_map_.erase(this->url_); g_assert(succeeded); this->buf_.set_eof(); --- 86,90 ---- boost::mutex::scoped_lock lock(this->mutex_); const bool succeeded = ! uninitialized_plugin_streambuf_map_.erase(*this); g_assert(succeeded); this->buf_.set_eof(); *************** *** 139,142 **** --- 144,201 ---- const boost::shared_ptr<openvrml_xembed::plugin_streambuf> + openvrml_xembed::requested_plugin_streambuf_map:: + find(const std::string & url) const + { + openvrml::read_write_mutex::scoped_read_lock lock(this->mutex_); + const base_t::const_iterator pos = this->base_t::find(url); + return pos == this->end() + ? boost::shared_ptr<plugin_streambuf>() + : pos->second; + } + + void + openvrml_xembed::requested_plugin_streambuf_map:: + insert(const std::string & url, + const boost::shared_ptr<plugin_streambuf> & streambuf) + { + openvrml::read_write_mutex::scoped_write_lock lock(this->mutex_); + this->base_t::insert(make_pair(url, streambuf)); + } + + struct + openvrml_xembed::requested_plugin_streambuf_map::map_entry_matches_streambuf : + std::unary_function<bool, value_type> { + + explicit map_entry_matches_streambuf(const plugin_streambuf * streambuf): + streambuf_(streambuf) + {} + + bool operator()(const value_type & entry) const + { + return this->streambuf_ == entry.second.get(); + } + + private: + const plugin_streambuf * const streambuf_; + }; + + bool + openvrml_xembed::requested_plugin_streambuf_map:: + erase(const plugin_streambuf & streambuf) + { + openvrml::read_write_mutex::scoped_read_write_lock lock(this->mutex_); + const base_t::iterator pos = + std::find_if(this->begin(), this->end(), + map_entry_matches_streambuf(&streambuf)); + if (pos == this->end()) { return false; } + lock.promote(); + this->base_t::erase(pos); + return true; + } + + openvrml_xembed::requested_plugin_streambuf_map + openvrml_xembed::requested_plugin_streambuf_map_; + + const boost::shared_ptr<openvrml_xembed::plugin_streambuf> openvrml_xembed::uninitialized_plugin_streambuf_map:: find(const std::string & url) const *************** *** 158,177 **** } ! /** ! * @brief Erase the first entry corresponding to @p url. ! * ! * The map may have multiple entries corresponding to @p url if the same ! * resource has been requested multiple times. A single call to @c erase will ! * only remove one of them. ! * ! * @return @c true if an entry was removed; @c false otherwise. ! */ bool openvrml_xembed::uninitialized_plugin_streambuf_map:: ! erase(const std::string & url) { ! openvrml::read_write_mutex::scoped_write_lock lock(this->mutex_); ! const map_t::iterator pos = this->map_.find(url); if (pos == this->map_.end()) { return false; } this->map_.erase(pos); return true; --- 217,246 ---- } ! struct openvrml_xembed::uninitialized_plugin_streambuf_map::map_entry_matches_streambuf : ! std::unary_function<bool, map_t::value_type> { ! ! explicit map_entry_matches_streambuf(const plugin_streambuf * streambuf): ! streambuf_(streambuf) ! {} ! ! bool operator()(const map_t::value_type & entry) const ! { ! return this->streambuf_ == entry.second.get(); ! } ! ! private: ! const plugin_streambuf * const streambuf_; ! }; ! bool openvrml_xembed::uninitialized_plugin_streambuf_map:: ! erase(const plugin_streambuf & streambuf) { ! openvrml::read_write_mutex::scoped_read_write_lock lock(this->mutex_); ! const map_t::iterator pos = ! std::find_if(this->map_.begin(), this->map_.end(), ! map_entry_matches_streambuf(&streambuf)); if (pos == this->map_.end()) { return false; } + lock.promote(); this->map_.erase(pos); return true; Index: main.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/main.cpp,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** main.cpp 2 Sep 2007 18:27:55 -0000 1.8 --- main.cpp 4 Sep 2007 22:45:36 -0000 1.9 *************** *** 140,145 **** command_line_stream >> url >> result; ! shared_ptr<plugin_streambuf> streambuf = ! uninitialized_plugin_streambuf_map_.find(url); g_assert(streambuf); streambuf->set_get_url_result(result); --- 140,145 ---- command_line_stream >> url >> result; ! const shared_ptr<plugin_streambuf> streambuf = ! requested_plugin_streambuf_map_.find(url); g_assert(streambuf); streambuf->set_get_url_result(result); Index: gtkvrmlbrowser.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/gtkvrmlbrowser.cpp,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** gtkvrmlbrowser.cpp 2 Sep 2007 18:27:55 -0000 1.10 --- gtkvrmlbrowser.cpp 4 Sep 2007 22:45:36 -0000 1.11 *************** *** 691,699 **** using std::ostringstream; using boost::ref; ! using openvrml_xembed::uninitialized_plugin_streambuf_map_; this->rdbuf(this->streambuf_.get()); ! uninitialized_plugin_streambuf_map_.insert(uri, ! this->streambuf_); ostringstream request; --- 691,698 ---- using std::ostringstream; using boost::ref; ! using openvrml_xembed::requested_plugin_streambuf_map_; this->rdbuf(this->streambuf_.get()); ! requested_plugin_streambuf_map_.insert(uri, this->streambuf_); ostringstream request; Index: plugin_streambuf.h =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/plugin_streambuf.h,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** plugin_streambuf.h 15 May 2007 04:06:11 -0000 1.5 --- plugin_streambuf.h 4 Sep 2007 22:45:36 -0000 1.6 *************** *** 33,36 **** --- 33,82 ---- namespace openvrml_xembed { + // + // plugin_streambuf Life Cycle + // + // A plugin_streambuf is first created in GtkVrmlBrowser's + // resource_fetcher::do_get_resource implementation (which is + // called whenever libopenvrml needs to load a stream). + // + // Step 1: requested_plugin_streambuf_map_ + // + // Upon creation, the plugin_streambuf is inserted into the + // requested_plugin_streambuf_map_. do_get_resource does not + // complete until the result of asking the host application to + // resolve the URL is known; i.e., + // plugin_streambuf::get_url_result. get_url_result blocks until + // the response is received from the host application; i.e., until + // plugin_streambuf::set_get_url_result has been called. + // set_get_url_result removes the plugin_streambuf from the + // requested_plugin_streambuf_map_. + // + // Step 2: uninitialized_plugin_streambuf_map_ + // + // If plugin_streambuf::set_get_url_result is given a result code + // indicating success (i.e., 0), the plugin_streambuf is inserted + // in the uninitialized_plugin_streambuf_map_. When a new-stream + // command is received for a URL, a plugin_streambuf matching that + // URL is gotten from the uninitialized_plugin_streambuf_map_ and + // plugin_streambuf::init is called on it. init removes the + // plugin_streambuf from the uninitialized_plugin_streambuf_map_ + // and inserts it in the plugin_streambuf_map_. + // + // Step 3: plugin_streambuf_map_ + // + // The plugin_streambuf_map_ comprises plugin_streambufs that are + // being written to in response to write commands and read from by + // stream readers in libopenvrml. Once the host application is + // done sending write commands for a stream, it is expected that + // it will send a destroy-stream command. In response to + // destroy-stream, bounded_buffer<>::set_eof is called on the + // plugin_streambuf's underlying bounded_buffer<> and the + // plugin_streambuf is removed from the plugin_streambuf_map_. + // + // Once the last reference to the resource_istream corresponding + // to the plugin_streambuf is removed, the plugin_streambuf is + // deleted. + // + class command_istream_reader; *************** *** 68,72 **** --- 114,140 ---- }; + extern class requested_plugin_streambuf_map : + std::multimap<std::string, boost::shared_ptr<plugin_streambuf> >, + boost::noncopyable { + + struct map_entry_matches_streambuf; + + typedef std::multimap<std::string, + boost::shared_ptr<plugin_streambuf> > + base_t; + + mutable openvrml::read_write_mutex mutex_; + + public: + const boost::shared_ptr<plugin_streambuf> + find(const std::string & url) const; + void insert(const std::string & url, + const boost::shared_ptr<plugin_streambuf> & streambuf); + bool erase(const plugin_streambuf & streambuf); + } requested_plugin_streambuf_map_; + extern class uninitialized_plugin_streambuf_map : boost::noncopyable { + struct map_entry_matches_streambuf; + mutable openvrml::read_write_mutex mutex_; typedef std::multimap<std::string, boost::shared_ptr<plugin_streambuf> > *************** *** 79,83 **** void insert(const std::string & url, const boost::shared_ptr<plugin_streambuf> & streambuf); ! bool erase(const std::string & url); size_t size() const; bool empty() const; --- 147,151 ---- void insert(const std::string & url, const boost::shared_ptr<plugin_streambuf> & streambuf); ! bool erase(const plugin_streambuf & url); size_t size() const; bool empty() const; |