On Fri, Jun 24, 2011 at 2:44 PM, Stefan Sperling <s...@elego.de> wrote: > Trying to update my working copy I observed svn spinning on the CPU > forever. Attaching with gdb showed that it was stuck in an endless > loop inside svn_ra_serf__handle_xml_parser(). > > Below is the code. The problem was that serf_bucket_read() returned > zero bytes but also indicated success. If that happens the loop never > terminates. > > I suppose this code was written with the assumption that reading > from the socket would always block until data is available?
No, serf is non-blocking! It's ok that serf returns 0 bytes read but still APR_SUCCESS, but that should happen only once. The second time svn reads something it should either return more data, or 0 with status APR_EOF. > This does not seem to happen in my case. Maybe serf is doing something > wrong when it opens the socket? > > I'm using serf-0.7.x from the branch as of June 21. > Assuming you have a working copy checkout out from https://s.a.o, en you haven't disabled gzip compression, my guess is that you're encountering the same issue I have documented here: http://groups.google.com/group/serf-dev/browse_thread/thread/56fcd4f25b290e29 In my scenario it loops in handle_fetch instead of the xml parser, but it's basically the same case. Serf trunk r1481 ensures the loop ends with an error in this situation. Lieven > while (1) > { > const char *data; > apr_size_t len; > > status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len); > > if (SERF_BUCKET_READ_ERROR(status)) > { > return svn_error_wrap_apr(status, NULL); > } > > /* Note: once the callbacks invoked by inject_to_parser() sets the > PAUSED flag, then it will not be cleared. write_to_pending() will > only save the content. Logic outside of serf_context_run() will > clear that flag, as appropriate, along with processing the > content that we have placed into the PENDING buffer. > > We want to save arriving content into the PENDING structures if > the parser has been paused, or we already have data in there (so > the arriving data is appended, rather than injected out of order) */ > #ifdef DISABLE_THIS_FOR_NOW > if (ctx->paused || HAS_PENDING_DATA(ctx->pending)) > { > err = write_to_pending(ctx, data, len, pool); > } > else > #endif > { > err = inject_to_parser(ctx, data, len, &sl); > if (err) > { > /* Should have no errors if IGNORE_ERRORS is set. */ > SVN_ERR_ASSERT(!ctx->ignore_errors); > } > } > if (err) > { > XML_ParserFree(ctx->xmlp); > add_done_item(ctx); > return svn_error_return(err); > } > > if (APR_STATUS_IS_EAGAIN(status)) > { > return svn_error_wrap_apr(status, NULL); > } > > if (APR_STATUS_IS_EOF(status)) > { > if (ctx->pending != NULL) > ctx->pending->network_eof = TRUE; > > /* We just hit the end of the network content. If we have nothing > in the PENDING structures, then we're completely done. */ > if (!HAS_PENDING_DATA(ctx->pending)) > { > /* Ignore the return status. We just don't care. */ > (void) XML_Parse(ctx->xmlp, NULL, 0, 1); > > XML_ParserFree(ctx->xmlp); > add_done_item(ctx); > } > > return svn_error_wrap_apr(status, NULL); > } > > /* feed me! */ > } > >