CVSROOT: /sources/gnash Module name: gnash Changes by: Sandro Santilli <strk> 07/12/20 22:37:13
Modified files: . : ChangeLog server/asobj : xml.cpp xml.h testsuite/actionscript.all: XML.as Log message: Load XML in background threads, fix abort on myXML.load() calls. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.5231&r2=1.5232 http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/xml.cpp?cvsroot=gnash&r1=1.57&r2=1.58 http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/xml.h?cvsroot=gnash&r1=1.22&r2=1.23 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/XML.as?cvsroot=gnash&r1=1.49&r2=1.50 Patches: Index: ChangeLog =================================================================== RCS file: /sources/gnash/gnash/ChangeLog,v retrieving revision 1.5231 retrieving revision 1.5232 diff -u -b -r1.5231 -r1.5232 --- ChangeLog 20 Dec 2007 22:31:31 -0000 1.5231 +++ ChangeLog 20 Dec 2007 22:37:12 -0000 1.5232 @@ -1,5 +1,9 @@ 2007-12-20 Sandro Santilli <[EMAIL PROTECTED]> + * server/asobj/xml.{cpp,h}: don't abort on XML.load() [ no args ]. + Engage a thread for each load request. + * testsuite/actionscript.all/XML.as: the test is now sane, and + have few more successes. * libbase/LoadThread.{cpp,h}: (setupCache) fix current position and _completed computation, (reset) join thread. Index: server/asobj/xml.cpp =================================================================== RCS file: /sources/gnash/gnash/server/asobj/xml.cpp,v retrieving revision 1.57 retrieving revision 1.58 diff -u -b -r1.57 -r1.58 --- server/asobj/xml.cpp 17 Dec 2007 22:57:18 -0000 1.57 +++ server/asobj/xml.cpp 20 Dec 2007 22:37:13 -0000 1.58 @@ -17,7 +17,7 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // -/* $Id: xml.cpp,v 1.57 2007/12/17 22:57:18 strk Exp $ */ +/* $Id: xml.cpp,v 1.58 2007/12/20 22:37:13 strk Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -65,10 +65,6 @@ static void attachXMLInterface(as_object& o); static void attachXMLProperties(as_object& o); -// Callback functions for xmlReadIO -static int closeTuFile (void * context); -static int readFromTuFile (void * context, char * buffer, int len); - DSOEXPORT as_value xml_new(const fn_call& fn); static as_value xml_load(const fn_call& fn); static as_value xml_addrequestheader(const fn_call& fn); @@ -81,7 +77,6 @@ static as_value xml_sendandload(const fn_call& fn); static as_value xml_ondata(const fn_call& fn); -static LogFile& dbglogfile = gnash::LogFile::getDefaultInstance(); #ifdef USE_DEBUGGER static Debugger& debugger = Debugger::getDefaultInstance(); #endif @@ -89,10 +84,12 @@ XML::XML() : XMLNode(getXMLInterface()), + _doc(0), + _firstChild(0), _loaded(-1), - _bytes_loaded(0), - _bytes_total(0), - _status(sOK) + _status(sOK), + _loadThreads(), + _loadCheckerTimer(0) { //GNASH_REPORT_FUNCTION; #ifdef DEBUG_MEMORY_ALLOCATION @@ -107,10 +104,12 @@ XML::XML(const std::string& xml_in) : XMLNode(getXMLInterface()), + _doc(0), + _firstChild(0), _loaded(-1), - _bytes_loaded(0), - _bytes_total(0), - _status(sOK) + _status(sOK), + _loadThreads(), + _loadCheckerTimer(0) { //GNASH_REPORT_FUNCTION; #ifdef DEBUG_MEMORY_ALLOCATION @@ -119,21 +118,6 @@ parseXML(xml_in); } -XML::XML(struct node * /* childNode */) - : - XMLNode(getXMLInterface()), - _loaded(-1), - _bytes_loaded(0), - _bytes_total(0), - _status(sOK) -{ - GNASH_REPORT_FUNCTION; -#ifdef DEBUG_MEMORY_ALLOCATION - log_msg(_("\tCreating XML data at %p"), this); -#endif - //log_msg("%s: %p", __FUNCTION__, this); -} - bool XML::get_member(string_table::key name, as_value *val, string_table::key nsname) { @@ -185,6 +169,11 @@ { //GNASH_REPORT_FUNCTION; + for (LoadThreadList::iterator it=_loadThreads.begin(); it != _loadThreads.end(); ++it) + { + delete *it; // supposedly joins the thread + } + #ifdef DEBUG_MEMORY_ALLOCATION log_msg(_("\tDeleting XML top level node at %p"), this); #endif @@ -407,35 +396,116 @@ GNASH_REPORT_FUNCTION; // Set the "loaded" parameter to false - VM& vm = _vm; + VM& vm = getVM(); string_table& st = vm.getStringTable(); string_table::key loadedKey = st.find("loaded"); - string_table::key onDataKey = st.find(PROPNAME("onData")); set_member(loadedKey, as_value(false)); - // TODO: - // 1. interrupt any pre-existing loading thread (send onLoad event in that case?) - // 2. start new loading thread - // - // Using LoadThread should do. Most likely we should do something - // similar for LoadVars or ::loadVariables, so might consider generalizing - // a load-in-a-separate-thread-calling-onLoad-when-done class - // - // The class would use a separate thread, provide cancelling and - // will call a specified function (or functor) when all data arrived, - // passing it the full data buffer. + bool startTimer = _loadThreads.empty(); + + std::auto_ptr<LoadThread> lt ( new LoadThread ); + lt->setStream(str); + + // we push on the front to avoid invalidating + // iterators when queueLoad is called as effect + // of onData invocation. + // Doing so also avoids processing queued load + // request immediately // - std::string src; - char buf[256]; - log_debug("Started loading of XML in main tread... "); - while ( 1 ) - { - size_t bytes = str->read_bytes(buf, 255); - src.append(buf, bytes); - if ( bytes < 255 ) break; // end of buffer + _loadThreads.push_front(lt.get()); + log_debug("Pushed thread %p to _loadThreads, number of XML load threads now: " SIZET_FMT, (void*)lt.get(), _loadThreads.size()); + lt.release(); + + + if ( startTimer ) + { + boost::intrusive_ptr<builtin_function> loadsChecker = \ + new builtin_function(&XML::checkLoads_wrapper); + std::auto_ptr<Timer> timer(new Timer); + timer->setInterval(*loadsChecker, 50, this); + _loadCheckerTimer = getVM().getRoot().add_interval_timer(timer, true); + log_debug("Registered XML loads interval %d", _loadCheckerTimer); + } + +} + +size_t +XML::getBytesLoaded() const +{ + if ( _loadThreads.empty() ) return 0; + LoadThread* lt = _loadThreads.front(); + return lt->getBytesLoaded(); +} + +size_t +XML::getBytesTotal() const +{ + if ( _loadThreads.empty() ) return 0; + LoadThread* lt = _loadThreads.front(); + return lt->getBytesTotal(); +} + +/* private */ +void +XML::checkLoads() +{ + static int call=0; + log_debug("XML %p checkLoads call %d, _loadThreads: %d", (void *)this, _loadThreads.size(), ++call); + + if ( _loadThreads.empty() ) return; // nothing to do + + VM& vm = getVM(); + string_table& st = vm.getStringTable(); + string_table::key onDataKey = st.find(PROPNAME("onData")); + + for (LoadThreadList::iterator it=_loadThreads.begin(); + it != _loadThreads.end(); ) + { + LoadThread* lt = *it; + + // TODO: notify progress + + log_debug("XML loads thread %p got %ld/%ld bytes", (void*)lt, lt->getBytesLoaded(), lt->getBytesTotal() ); + if ( lt->completed() ) + { + size_t xmlsize = lt->getBytesTotal(); + boost::scoped_array<char> buf(new char[xmlsize+1]); + size_t actuallyRead = lt->read(buf.get(), xmlsize); + assert(actuallyRead = xmlsize); + buf[xmlsize] = '\0'; + as_value dataVal(buf.get()); // memory copy here (optimize?) + + it = _loadThreads.erase(it); + delete lt; // supposedly joins the thread... + + // might push_front on the list.. + callMethod(onDataKey, dataVal); + + log_debug("Completed load, _loadThreads have now " SIZET_FMT " elements", _loadThreads.size()); + } + else + { + ++it; + } + } + + if ( _loadThreads.empty() ) + { + log_debug("Clearing XML load checker interval timer"); + vm.getRoot().clear_interval_timer(_loadCheckerTimer); + _loadCheckerTimer=0; } - log_debug("... finished loading of XML in main tread."); - callMethod(onDataKey, as_value(src)); +} + +/* private static */ +as_value +XML::checkLoads_wrapper(const fn_call& fn) +{ + log_debug("checkLoads_wrapper called"); + + boost::intrusive_ptr<XML> ptr = ensureType<XML>(fn.this_ptr); + ptr->checkLoads(); + return as_value(); } // This reads in an XML file from disk and parses into into a memory resident @@ -451,9 +521,10 @@ if ( ! str.get() ) { log_error(_("Can't load XML file: %s (security?)"), url.str().c_str()); - as_value nullValue; nullValue.set_null(); - callMethod(VM::get().getStringTable().find("onData"), nullValue); return false; + // TODO: this is still not correct.. we should still send onData later... + //as_value nullValue; nullValue.set_null(); + //callMethod(VM::get().getStringTable().find(PROPNAME("onData")), nullValue); } log_msg(_("Loading XML file from url: '%s'"), url.str().c_str()); @@ -535,6 +606,14 @@ boost::intrusive_ptr<XML> xml_obj = ensureType<XML>(fn.this_ptr); + if ( ! fn.nargs ) + { + IF_VERBOSE_ASCODING_ERRORS( + log_aserror(_("XML.load(): missing argument")); + ); + return rv; + } + const std::string& filespec = fn.arg(0).to_string(); URL url(filespec, get_base_url()); @@ -834,26 +913,6 @@ } -// Callback function for xmlReadIO -static int -readFromTuFile (void * context, char * buffer, int len) -{ - tu_file* str = static_cast<tu_file*>(context); - size_t read = str->read_bytes(buffer, len); - if ( str->get_error() ) return -1; - else return read; -} - -// Callback function for xmlReadIO -static int -closeTuFile (void * /*context*/) -{ - // nothing to do, the tu_file destructor will close - //tu_file* str = static_cast<tu_file*>(context); - //str->close(); - return 0; // no error -} - #if 0 // not time for this (yet) static void _xmlErrorHandler(void* ctx, const char* fmt, ...) Index: server/asobj/xml.h =================================================================== RCS file: /sources/gnash/gnash/server/asobj/xml.h,v retrieving revision 1.22 retrieving revision 1.23 diff -u -b -r1.22 -r1.23 --- server/asobj/xml.h 20 Nov 2007 12:04:56 -0000 1.22 +++ server/asobj/xml.h 20 Dec 2007 22:37:13 -0000 1.23 @@ -26,22 +26,19 @@ #include "event_id.h" #include "action.h" - -//#define DEBUG_MEMORY_ALLOCATION 1 -#include <vector> -#include <sstream> - +#include "LoadThread.h" #include "xmlattrs.h" #include "xmlnode.h" +#include "log.h" -#ifdef DEBUG_MEMORY_ALLOCATION - #include "log.h" -#endif - +#include <vector> +#include <sstream> #include <libxml/xmlmemory.h> #include <libxml/parser.h> #include <libxml/xmlreader.h> +//#define DEBUG_MEMORY_ALLOCATION 1 + using namespace std; namespace gnash { @@ -49,6 +46,7 @@ // Forward declarations class fn_call; class URL; +class LoaderThread; /// XML class and ActionScript object class DSOLOCAL XML : public XMLNode @@ -92,8 +90,7 @@ XML(); XML(const std::string& xml_in); - XML(struct node * childNode); - virtual ~XML(); + ~XML(); /// This is overridden to provide the 'status' and 'loaded' members, /// which are NOT proper properties ! @@ -138,13 +135,11 @@ // the XML object was successfully // loaded with XML.load() or // XML.sendAndLoad(). - bool loaded() { return _loaded; } XMLNode *processNode(xmlTextReaderPtr reader, XMLNode *node); void change_stack_frame(int frame, gnash::as_object *xml, gnash::as_environment *env); -// void setupStackFrames(gnash::as_object *xml, gnash::as_environment *env); void cleanupStackFrames( XMLNode *data); @@ -163,8 +158,8 @@ void sendAndLoad(); - int getBytesLoaded() { return _bytes_loaded; }; - int getBytesTotal() { return _bytes_total; }; + size_t getBytesLoaded() const; + size_t getBytesTotal() const; private: @@ -199,10 +194,6 @@ // 1 if successfully loaded int _loaded; - size_t _bytes_loaded; - - size_t _bytes_total; - Status _status; /// Trigger the onLoad event, if any @@ -230,6 +221,22 @@ void queueLoad(std::auto_ptr<tu_file> str); //static void _xmlErrorHandler(void *ctx, const char* fmt, ...); + + typedef std::list<LoadThread*> LoadThreadList; + + /// Queue of load requests + LoadThreadList _loadThreads; + + /// The load checker interval timer used to make loads async + unsigned int _loadCheckerTimer; + + /// Wrapper around checkLoads for use as a Timer + /// interval for checking loads + static as_value checkLoads_wrapper(const fn_call& fn); + + /// Scan the LoadThread queue (_loadThreads) to see if any of + /// them completed. If any did, invoke the onData event + void checkLoads(); }; Index: testsuite/actionscript.all/XML.as =================================================================== RCS file: /sources/gnash/gnash/testsuite/actionscript.all/XML.as,v retrieving revision 1.49 retrieving revision 1.50 diff -u -b -r1.49 -r1.50 --- testsuite/actionscript.all/XML.as 20 Dec 2007 17:49:57 -0000 1.49 +++ testsuite/actionscript.all/XML.as 20 Dec 2007 22:37:13 -0000 1.50 @@ -20,7 +20,7 @@ // compile this test case with Ming makeswf, and then // execute it like this gnash -1 -r 0 -v out.swf -rcsid="$Id: XML.as,v 1.49 2007/12/20 17:49:57 strk Exp $"; +rcsid="$Id: XML.as,v 1.50 2007/12/20 22:37:13 strk Exp $"; #include "check.as" //#include "dejagnu.as" @@ -712,7 +712,7 @@ if ( this.onLoadCalls == 2 ) { #if OUTPUT_VERSION < 6 - xcheck_totals(262); + check_totals(262); #else xcheck_totals(337); #endif @@ -741,9 +741,9 @@ #else // OUTPUT_VERSION >= 7 check_equals(typeof(myxml.LOADED), 'undefined'); #endif // OUTPUT_VERSION >= 7 -xcheck(! myxml.loaded ); // is really loaded in a background thread +check(! myxml.loaded ); // is really loaded in a background thread -xcheck_equals(myxml.loaded, false ); // is really loaded in a background thread +check_equals(myxml.loaded, false ); // is really loaded in a background thread note("myxml.loaded = "+myxml.loaded); note("myxml.load() returned "+ret); _______________________________________________ Gnash-commit mailing list Gnash-commit@gnu.org http://lists.gnu.org/mailman/listinfo/gnash-commit