[Common-cvs] netio/platform/posix sockimp.cpp,1.103,1.104

[Common-cvs] netio/platform/posix sockimp.cpp,1.103,1.104

atin at helixcommunity.org atin at helixcommunity.org
Fri Apr 3 11:19:17 PDT 2009


Update of /cvsroot/common/netio/platform/posix
In directory cvs01.internal.helixcommunity.org:/tmp/cvs-serv7233/platform/posix

Modified Files:
	sockimp.cpp 
Log Message:
Synopsis
========
if a player sent a TEARDOWN during the course of a session where the server is
stuck in a re-transmission (sendmsg() returns an EWOULDBLOCK/EAGAIN) loop due
to some reason, the streamer process with the connection would spin out and
consume close to 100% cpu.


Branches: SERVER_12_1, SERVER_CURRENT
Reviewer: ckarusala


Description
===========
when the client closes the socket it generally means that the server's socket
read/recvfrom method will return zero bytes. when this happens the socket
state is set to HX_SOCK_STATE_CLOSED inside CHXSocket::DoRead().

the problem is that there wasn't a check inside the CHXSocket::Close() method
to see if the socket is in the HX_SOCK_STATE_CLOSED state and if there is some
pending data to be written out to the socket the socket is set to linger until
the data can be written out.

so essentially, the select() returns that the socket is ready to be written
to, so the server writes to the socket, only to return back with a
EWOULDBLOCK. so it resets the flags in the select() to notify if the socket is
ready for writing again. the next select() it returns back stating once again
that the socket is ready for writing. this loop of write notification and
write failure keeps on indefinitely for every mainloop() iteration and because
the socket is forever ready to be written to, the select() returns immediately
thus causing high mainloop iterations and consequently high cpu usage.

fix:
====
add the check for socket state != HX_SOCK_STATE_CLOSED in Close() to make it
linger only if the socket is not closed.


Files Affected
==============
common/netio/platform/posix/sockimp.cpp


Testing Performed
=================
Unit Tests:
N/A

Integration Tests:
(1) solaris/linux/windows: as described in the repro steps in the pr using
    the NEGiES packet filter tool.
    (1) run unmodified server.
        request clip from client.
        start filter.
        wait for a few seconds.
        stop client.
        run a system tracing tool on the server.
        u will see the socket options being set to SO_LINGER
        all subsequent select() calls return with 1 socket being ready for
            writing and all sendmsg() calls return EAGAIN/EWOUDBLOCK.
            (i haven't figured out why the select() calls return that the
            socket is ready for writing even tho it is blocked.)
        observe the cpu usage for the responsible streams is close to 100%.
        stop the filter after 15 seconds.
        observe that the cpu usage drops back to zero.

    (2) repeat test (1) with the modified server.
        as expected after the client is stopped the server closes the socket
            and so there aren't any blocked sendmsg() calls.

    (3) run test (1) but don't stop the client.
        it can be observed that there is no spin out with the original or
        modified server, because the socket isn't closed and so even though
        the sendmsg() returns with a EWOULDBLOCK, the next select() returns
        with the socket not being ready for writing (which is how it is
        normally).

Leak Tests:
N/A

Performance Tests:
N/A

Platforms Tested: sunos-5.10-sparc-server, linux-rhel4-i686, win32-i386-vc7
Build verified: sunos-5.10-sparc-server, linux-rhel4-i686, win32-i386-vc7


QA Hints
========
None



Index: sockimp.cpp
===================================================================
RCS file: /cvsroot/common/netio/platform/posix/sockimp.cpp,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -d -r1.103 -r1.104
--- sockimp.cpp	28 Jul 2008 22:56:01 -0000	1.103
+++ sockimp.cpp	3 Apr 2009 18:19:15 -0000	1.104
@@ -1022,7 +1022,12 @@
         m_pSock4->Close();
     }
 #endif
-    if (HX_SOCK_VALID(m_sock) && !m_pWriteQueue->IsEmpty())
+    // if a socket is ready for reading and a read returns zero bytes
+    // then it generally means that the socket has been closed from
+    // the peer's side, so its ok to close the socket from our side too.
+    if (HX_SOCK_VALID(m_sock) && 
+	m_sock.state != HX_SOCK_STATE_CLOSED && 
+	!m_pWriteQueue->IsEmpty())
     {
         UINT32 uLinger = LINGER_OFF;
         if (hx_getsockopt(&m_sock, HX_SOCKOPT_LINGER, &uLinger) != 0)




More information about the Common-cvs mailing list
 

Site Map   |   Terms of Use   |   Privacy Policy   |   Contact Us

Copyright © 1995-2007 RealNetworks, Inc. All rights reserved. RealNetworks and Helix are trademarks of RealNetworks.
All other trademarks or registered trademarks are the property of their respective holders.