You are viewing a plain text version of this content. The canonical link for it is here.
Posted to general@xerces.apache.org by RHS Linux User <hn...@ns1.netarx.com> on 2000/02/08 19:52:25 UTC

Inexplicable blocking when Xerces is called from Perl5

	I am actively integrating XERCES into Perl5 on UNIX, using SWIG.
In order to get needed functionality (and experiment with the code), I
have created some InputSources based on the standard C++ stream classes,
specifically fstream and strstream.  The resulting classes are called
"StrStreamInputSource" and "FStreamInputSource".

	-- These classes work quite well from C++. --  However, when I
SWIG them into Perl5, they start acting up.  Specifically, the InputSource
based on the istrstream class, "StrStreamInputSource".  I can create an
StrStreamInputSource object just fine in Perl.  However when I attempt to
pass it to a DOMParser object, the script goes into an everlasting sleep.
Specifically, it is blocking on a "read" operation call for an istrstream
object.  This call occurs in the BinStreamInputStream class -- an
object of this class is returned by a call to "makeStream" on a
StrStreamInputSource object.

	Here's the output from the "ps -aefl" command:

  F S UID        PID  C PRI  NI ADDR  WCHAN         CMD
000 S root     29698  7 78    0 -     rt_sigsuspend perl ./DOMPrint3.pl

Re: Inexplicable blocking when Xerces is called from Perl5

Posted by Tom Watson <rt...@apache.org>.
Harmon,

I'm not sure that I want to degug your code ... at least not until we
have reason to believe their is a bug on our end ... but I can give you
some pointers.  First, I have used SWIG extensively to wrap the Xerces
C++ DOM in order to create the Xerces Perl DOM project.  It works.  You
might want to take a look at this project if you have any questions
about how to use SWIG to wrap something like Xerces C.  

I never encountered a hang problem like you describe, but I did
encounter other problems that I eventually figured out. These were
usually related to values being passed differently by Perl, or handled
differently by SWIG than I expected ... boolean is one I remember
working through.  Here are some techniques to try.

1.  Put printfs in the SWIG generated wrapper before and after calls to
the C++ functions.
2.  Write a C++ or C method of your own to call the C++ parser method
and then wrap your method in SWIG instead.  This may give you more
opportunity to put debug code around the call.
3.  In particular, look at the values you are passing into the methods. 
They may be Perl references and may not be what you think they are. 
Invalid values could be causing the C++ methods to act up.
4.  Use mapsym (on Windows ... not sure what you are using) to examine
the sybol table and see if wrapper signatures are what you expect. 
There may be some unexpected coersion of values going on.

Tom

RHS Linux User wrote:
> 
>         I am actively integrating XERCES into Perl5 on UNIX, using SWIG.
> In order to get needed functionality (and experiment with the code), I
> have created some InputSources based on the standard C++ stream classes,
> specifically fstream and strstream.  The resulting classes are called
> "StrStreamInputSource" and "FStreamInputSource".
> 
>         -- These classes work quite well from C++. --  However, when I
> SWIG them into Perl5, they start acting up.  Specifically, the InputSource
> based on the istrstream class, "StrStreamInputSource".  I can create an
> StrStreamInputSource object just fine in Perl.  However when I attempt to
> pass it to a DOMParser object, the script goes into an everlasting sleep.
> Specifically, it is blocking on a "read" operation call for an istrstream
> object.  This call occurs in the BinStreamInputStream class -- an
> object of this class is returned by a call to "makeStream" on a
> StrStreamInputSource object.
> 
>         Here's the output from the "ps -aefl" command:
> 
>   F S UID        PID  C PRI  NI ADDR  WCHAN         CMD
> 000 S root     29698  7 78    0 -     rt_sigsuspend perl ./DOMPrint3.pl
> 
> >From this output, it appears that the script is suspended, waiting for
> a signal of some kind.  Why, I have no idea.  As mentioned above, an
> analogous piece of code in C++ works fine.  As well, the "read" is from
> a string, not a file descriptor, so the blocking can't be due to I/O.
> 
> The PERL script is listed below, along with the code for the InputSource
> classes based on the standard C++ streams.  As well there is the code for
> the BinStreamInputStream class, which is derived from BinInputStream.
> 
> THANKS FOR ANY HELP YOU CAN GIVE.
> 
> -- Harmon S. Nine
> 
> ---------------  START OF SCRIPT  ----------------
> #!/usr/bin/perl
> 
> use XERCES;
> 
> $| = 1;
> sub print_node {
>         my $node_type = $_[0]->getNodeType;
>         die "unknown node type $node_type" unless defined $print_array[$node_type];
> 
>         &{$print_array[$node_type]}(@_);
> }
> 
> sub output_content {
>         my $node_value = $_[0]->transcode;
> 
>         $node_value =~ s/&/&amp;/g;
>         $node_value =~ s/</&lt;/g;
>         $node_value =~ s/>/&gt;/g;
>         $node_value =~ s/"/&quote;/g;
> 
>         print $node_value;
> }
> 
> $print_array[$DOM_Node::TEXT_NODE] = sub {
>         output_content $_[0]->getNodeValue;
> };
> 
> $print_array[$DOM_Node::PROCESSING_INSTRUCTION_NODE] = sub {
>         print '<?', $_[0]->getNodeName->transcode, ' ', $_[0]->getNodeValue->transcode, '?>';
> };
> 
> $print_array[$DOM_Node::DOCUMENT_NODE] = sub {
>         print "<?xml version='1.0' encoding='ISO-8859-1' ?>\n";
> 
>         for(my $child = $_[0]->getFirstChild ; !$child->isNull ; $child = $child->getNextSibling) { print_node $child; }
> };
> 
> $print_array[$DOM_Node::ELEMENT_NODE] = sub {
>         my $node_name = $_[0]->getNodeName->transcode;
>         print "<$node_name";
> 
>         my $attributes = $_[0]->getAttributes;
>         my $attribute_count = $attributes->getLength;
> 
>         my $ix;
>         for($ix = 0 ; $ix < $attribute_count ; ++$ix) {
>                 $attribute = $attributes->item($ix);
>                 print ' ', $attribute->getNodeName->transcode, '="';
>                 output_content $attribute->getNodeValue;
>                 print '"';
>         }
> 
>         my $child = $_[0]->getFirstChild;
>         print('/>'), return if $child->isNull;
> 
>         print '>';
>         until($child->isNull) {
>                 print_node $child;
>                 $child = $child->getNextSibling;
>         }
>         print "</$node_name>";
> };
> 
> $print_array[$DOM_Node::ENTITY_REFERENCE_NODE] = sub {
>         for(my $child = $_[0]->getFirstChild ; !$child->isNull ; $child = $child->getNextSibling) { print_node $child; }
> };
> 
> $print_array[$DOM_Node::CDATA_SECTION_NODE] = sub {
>         print '<![CDATA[', $_[0]->getNodeValue->transcode, ']]>';
> };
> 
> $print_array[$DOM_Node::COMMENT_NODE] = sub {
>         print '<!--', $_[0]->getNodeValue->transcode, '-->';
> };
> 
> # WHERE THE ACTION ACTUALLY STARTS DOING SOMETHING
> 
> XMLPlatformUtils::Initialize;
> 
> $doc = <<'END';                                 # THE XML DOCUMENT -- IN A VARIABLE ($doc)
> <?xml version="1.0" encoding="ASCII"?>
> <!DOCTYPE personnel SYSTEM "personal.dtd">
> 
> <!-- @version: -->
> 
> <personnel>
> 
>   <person id="Big.Boss" >
>     <name><family>Boss</family> <given>Big</given></name>
>     <email>chief@foo.com</email>
>     <link subordinates="one.worker two.worker three.worker four.worker five.worker"/>
>   </person>
> 
>   <person id="one.worker">
>     <name><family>Worker</family> <given>One</given></name>
>     <email>one@foo.com</email>
> <link manager="Big.Boss"/>
>   </person>
> 
>   <person id="two.worker"                                     >
>     <name><family>Worker</family> <given>Two</given></name>
>     <email>two@foo.com</email>
>     <link manager="Big.Boss"/>
>   </person>
> 
>   <person id="three.worker">
>     <name><family>Worker</family> <given>Three</given></name>
>     <email>three@foo.com</email>
>     <link manager="Big.Boss"/>
>   </person>
> 
>   <person id="four.worker">
>     <name><family>Worker</family> <given>Four</given></name>
>     <email>four@foo.com</email>
>     <link manager="Big.Boss"/>
>   </person>
> 
>   <person id="five.worker">
>     <name><family>Worker</family> <given>Five</given></name>
>     <email>five@foo.com</email>
>     <link manager="Big.Boss"/>
>   </person>
> 
> </personnel>
> END
> 
> # GET A NEW DOM PARSER
> $parser = new DOMParser;
> $parser->setDoValidation(0);                    # TURN VALIDATION OFF FOR TESTING
> 
> $input_source = new StrStreamInputSource($doc); # GET A NEW INPUT SOURCE, BASED ON XML DOCUMENT ABOVE (variable = $doc)
> 
> $parser->parse($input_source);                  # ***** GOES TO SLEEP FOREVER HERE ****
> 
> print_node($parser->getDocument);               # NEVER GETS HERE
> 
> ----------------  END OF SCRIPT  -----------------
> 
> ---------------  StreamInputSource base class  --------------------
> 
> //HEADER FILE StreamInputSource.hpp
> 
> #if !defined(STREAMINPUTSOURCE_HPP)
> #define STREAMINPUTSOURCE_HPP
> 
> #include <stdio.h>
> #include <iostream.h>
> #include <sax/InputSource.hpp>
> #include <util/BinStreamInputStream.hpp>
> 
> class XMLPARSER_EXPORT StreamInputSource : public InputSource {
> 
> private:
> 
>         istream *is;
> 
>         static char *StreamInputSourceToSystemId(const StreamInputSource *ptr);
> 
> public:
> 
>     // -----------------------------------------------------------------------
>     //  Constructors and Destructor
>     // -----------------------------------------------------------------------
>     StreamInputSource(istream *is_parm);
>     StreamInputSource(istream *is_parm, const char *const systemId);
>     StreamInputSource(istream *is_parm, const char *const systemId, const char *const publicId);
>     StreamInputSource(istream *is_parm, const XMLCh *const systemId);
>     StreamInputSource(istream *is_parm, const XMLCh *const systemId, const XMLCh *const publicId);
> 
>     ~StreamInputSource();
> 
>     // -----------------------------------------------------------------------
>     //  Virtual input source interface
>     // -----------------------------------------------------------------------
>     BinInputStream* makeStream() const;
> 
> protected:
> 
>     StreamInputSource();
>     StreamInputSource(const char *const systemId);
>     StreamInputSource(const char *const systemId, const char *const publicId);
>     StreamInputSource(const XMLCh *const systemId);
>     StreamInputSource(const XMLCh *const systemId, const XMLCh *const publicId);
> 
>     void setStream(istream *is_parm);
> };
> 
> #endif
> 
> // C++ SOURCE FILE StreamInputSource.cpp
> #include <internal/StreamInputSource.hpp>
> 
> char *StreamInputSource::StreamInputSourceToSystemId(const StreamInputSource *ptr) {
>         static char string[128];
>         sprintf(string, "StreamInputSource(%#0*x)", 2*sizeof(int) + 2, ptr);
>         return string;
> }
> 
> StreamInputSource::StreamInputSource(istream *is_parm) :
>          InputSource( StreamInputSourceToSystemId(this) ), is(is_parm) { }
> 
> StreamInputSource::StreamInputSource(istream *is_parm, const char *const systemId) :
>         InputSource(systemId), is(is_parm) { }
> 
> StreamInputSource::StreamInputSource(istream *is_parm, const char *const systemId, const char *const publicId) :
>  InputSource(systemId, publicId), is(is_parm) { }
> 
> StreamInputSource::StreamInputSource(istream *is_parm, const XMLCh *const systemId) :
>         InputSource(systemId), is(is_parm) { }
> 
> StreamInputSource::StreamInputSource(istream *is_parm, const XMLCh *const systemId, const XMLCh *const publicId) :
>         InputSource(systemId, publicId), is(is_parm) { }
> 
> StreamInputSource::~StreamInputSource() { delete is; }
> 
> BinInputStream* StreamInputSource::makeStream() const {
>         return is->good() ? new BinStreamInputStream(is) : 0;
> }
> 
> StreamInputSource::StreamInputSource() :
>         InputSource( StreamInputSourceToSystemId(this) ) { }
> 
> StreamInputSource::StreamInputSource(const char *const systemId) :
>         InputSource(systemId) { }
> 
> StreamInputSource::StreamInputSource(const char *const systemId, const char *const publicId) :
>         InputSource(systemId, publicId) { }
> 
> StreamInputSource::StreamInputSource(const XMLCh *const systemId) :
>         InputSource(systemId) { }
> 
> StreamInputSource::StreamInputSource(const XMLCh *const systemId, const XMLCh *const publicId) :
>          InputSource(systemId, publicId) { }
> 
> void StreamInputSource::setStream(istream *is_parm) { is = is_parm; }
> 
> -------------------- StrStreamInputSource Derived Class -----------------
> 
> //HEADER FILE StrStreamInputSource.hpp
> 
> #if !defined(STRSTREAMINPUTSOURCE_HPP)
> #define STRSTREAMINPUTSOURCE_HPP
> 
> #include <internal/StreamInputSource.hpp>
> #include <strstream.h>
> #include <string.h>
> 
> class XMLPARSER_EXPORT StrStreamInputSource : public StreamInputSource {
> 
> private:
> 
>         char *string;
> 
>         void initialize(const char *string_parm, int strlen_parm);
> 
> public:
> 
>     //
> -----------------------------------------------------------------------
>     //  Constructors and Destructor
>     //
> -----------------------------------------------------------------------
>     StrStreamInputSource(const char *string_parm);
>     StrStreamInputSource(const char *string_parm, const char *const systemId);
>     StrStreamInputSource(const char *string_parm, const char *const systemId, const char *const publicId);
>     StrStreamInputSource(const char *string_parm, const XMLCh *const systemId);
>     StrStreamInputSource(const char *string_parm, const XMLCh *const systemId, const XMLCh *const publicId);
> 
>     StrStreamInputSource(const char *string_parm, int strlen_parm);
>     StrStreamInputSource(const char *string_parm, int strlen_parm, const char *const systemId);
>     StrStreamInputSource(const char *string_parm, int strlen_parm, const char *const systemId, const char *const publicId);
>     StrStreamInputSource(const char *string_parm, int strlen_parm, const XMLCh *const systemId);
>     StrStreamInputSource(const char *string_parm, int strlen_parm, const XMLCh *const systemId, const XMLCh *const publicId);
> 
>     virtual ~StrStreamInputSource();
> 
> };
> 
> #endif
> 
> // C++ SOURCE FILE StrStreamInputSource.cpp
> 
> #include <internal/StrStreamInputSource.hpp>
> 
> void StrStreamInputSource::initialize(const char *string_parm, int
> strlen_parm) {
>         string = new char[strlen_parm];
>         memcpy(string, string_parm, strlen_parm);
>         setStream( new istrstream(string, strlen_parm) );
> }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm) :
>         StreamInputSource() { initialize( string_parm, strlen(string_parm) ); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, const char *const systemId) :
>         StreamInputSource(systemId) { initialize( string_parm, strlen(string_parm) ); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, const char *const systemId, const char *const publicId) :
>         StreamInputSource(systemId, publicId) { initialize( string_parm, strlen(string_parm) ); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, const XMLCh *const systemId) :
>         StreamInputSource(systemId) { initialize( string_parm, strlen(string_parm) ); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, const XMLCh *const systemId, const XMLCh *const publicId) :
>         StreamInputSource(systemId, publicId) { initialize( string_parm, strlen(string_parm) ); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, int strlen_parm) :
>         StreamInputSource() { initialize(string_parm, strlen_parm); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, int strlen_parm, const char *const systemId) :
>         StreamInputSource(systemId) { initialize(string_parm, strlen_parm); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, int strlen_parm, const char *const systemId, const char *const publicId) :
>         StreamInputSource(systemId, publicId) { initialize(string_parm, strlen_parm); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, int strlen_parm, const XMLCh *const systemId) :
>         StreamInputSource(systemId) { initialize(string_parm, strlen_parm); }
> 
> StrStreamInputSource::StrStreamInputSource(const char *string_parm, int strlen_parm, const XMLCh *const systemId, const XMLCh *const publicId) :
>         StreamInputSource(systemId, publicId) { initialize(string_parm, strlen_parm); }
> 
> StrStreamInputSource::~StrStreamInputSource() { delete[] string; }
> 
> ------------  DERIVED CLASS BinStreamInputStream ---------------------
> 
> // HEADER FILE BinStreamInputStream.hpp
> 
> #if !defined(BINSTREAMINPUTSTREAM_HPP)
> #define BINSTREAMINPUTSTREAM_HPP
> 
> #include <iostream.h>
> #include <util/BinInputStream.hpp>
> 
> class XMLUTIL_EXPORT BinStreamInputStream : public BinInputStream {
> public :
>     // -----------------------------------------------------------------------
>     //  Constructors and Destructor
>     // -----------------------------------------------------------------------
>     BinStreamInputStream(istream *istr);
> 
>     virtual ~BinStreamInputStream();
> 
>     // -----------------------------------------------------------------------
>     //  Implementation of the input stream interface
>     // -----------------------------------------------------------------------
>     virtual unsigned int curPos() const;
> 
>     virtual unsigned int readBytes (XMLByte *const toFill, const unsigned int maxToRead);
> 
> private:
>         istream *is;
> };
> 
> #endif
> 
> // C++ SOURCE FILE BinStreamInputStream.cpp
> 
> #include <util/BinStreamInputStream.hpp>
> 
> BinStreamInputStream::BinStreamInputStream(istream *istr) : is(istr) { }
> 
> BinStreamInputStream::~BinStreamInputStream() { }
> 
>     // -----------------------------------------------------------------------
>     //  Implementation of the input stream interface
>     // -----------------------------------------------------------------------
> unsigned int BinStreamInputStream::curPos() const {
>         return is->tellg();
> }
> 
> unsigned int BinStreamInputStream::readBytes (XMLByte *const toFill, const unsigned int maxToRead) {
> 
>         is->read( (void *)toFill, maxToRead );  // *** GOES TO SLEEP FOREVER HERE ***
> 
>         return is->gcount();
> }