You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Eric van der Maarel <er...@nedap.com> on 2011/06/24 10:12:17 UTC

Re: 100% cpu with APR on Windows

On 05/29/2011 10:53 PM, Jeff Trawick wrote:
> On Fri, May 27, 2011 at 3:59 PM, Justin Erenkrantz
> <ju...@erenkrantz.com>  wrote:
>> On Fri, May 27, 2011 at 9:48 AM,<tr...@gmail.com>  wrote:
>>> Can you outline the idioms you refer to that prefer a select()
>>> implementation?
>>>
>>> iow, how different are they from
>>>
>>> apr_socket_create
>>> set socket nonblocking with no timeout
>>> apr_socket_connect()
>>> apr_pollset_poll()
>>
>> That's all serf is doing.  With WSAPoll(), if you connect to a port
>> via a non-blocking socket that there is no listener on, WSAPoll()
>> never sends any indication.  However, select() lets you know that the
>> earlier connect() failed.  Given the pretty isolated test case in the
>> forum earlier, I do think this is an underlying issue with WSAPoll() -
>> but enough of an issue, it shouldn't be the default unless someone can
>> find a way to get WSAPoll() to report failure...  -- justin
>
> no-can-do AFAICT; there's literally NOTHING you can put in .events
> which results in anything reported in .revents after ECONNREFUSED
>
> your two cases are the only reports of WSAPoll() problems I know of in
> the last year (since 1.4.x was released, making WSAPoll() the
> default); still, it seems probable that more code works with a
> select()-based implementation
>
> a new WSAEVENT-based implementation may be the long term solution
> (FD_CONNECT events would have to be mapped to something the app would
> ask for; presumably FD_CLOSE events would map to POLLHUP, which was
> the select() issue which started this thread)


I propose a patch for impl_pollset_poll() in select.c (the poller impl 
based on select(), used on Windows XP).

The idea is to test all sockets that are kept by select() in the read 
set, for data with a peeking recv() call. When the call to recv() for a 
socket returns 0, no data read, we set the APR_POLLHUP flag in the 
return event of the pollset result_set. And we set the APR_POLLERR flag 
when result < 0.
This works since the socket was kept in the read set by select(), either 
since there's data or since the socket was disconnected.
I'm not sure about the conditions under which recv() can return 0 
though... (e.g. socket has not yet accept()ed an incoming connection 
request? or data is available but for some reason recv() still reads no 
data and returns 0?).

Test results so far are positive.

Here's the proposed code, with changes/additions in lines 6-12:

   1       if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
   2           FD_ISSET(fd, &exceptset)) {
   3           pollset->p->result_set[j] = pollset->p->query_set[i];
   4           pollset->p->result_set[j].rtnevents = 0;
   5           if (FD_ISSET(fd, &readset)) {
   6              r = recv(fd, buf, 8, MSG_PEEK); // 8 byte buffer
   7              if (r == 0) {
   8                  pollset->p->result_set[j].rtnevents |= APR_POLLHUP;
   9              }
  10              else if (r < 0) {
  11                  pollset->p->result_set[j].rtnevents |= APR_POLLERR;
  12              }
  13              pollset->p->result_set[j].rtnevents |= APR_POLLIN;
  14          }
  15          if (FD_ISSET(fd, &writeset)) {
  16              pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
  17          }
  18          if (FD_ISSET(fd, &exceptset)) {
  19              pollset->p->result_set[j].rtnevents |= APR_POLLERR;
  20          }
  21          j++;

Regards,
Eric

-- 
-------------------------------------------
| Eric van der Maarel                     |
| NEDAP IDEAS                             |
| eric.vandermaarel@nedap.com             |
-------------------------------------------^[ZZ