ID:               46685
 Updated by:       [EMAIL PROTECTED]
 Reported By:      scott dot php at scottrix dot co dot uk
 Status:           Feedback
 Bug Type:         Performance problem
 Operating System: Linux
 PHP Version:      5.2.6
 New Comment:

You can do non blocking operations in php as well. 

Sorry to insist, but please provide a reproduce case (a script). I'm
not saying that your patch is wrong or not necessary, but it may be
possible already without changes.


Previous Comments:
------------------------------------------------------------------------

[2008-11-26 11:07:31] scott dot php at scottrix dot co dot uk

The script is running tests on our webpages over ssl.  So it is
spending time waiting to receive data from the webserver.  The php
source code for this waiting for data from the server (over SSL) employs
a busy loop on a nonblocking socket (hence the EAGAIN read errors in
strace output).

------------------------------------------------------------------------

[2008-11-26 10:56:10] [EMAIL PROTECTED]

What are you trying to do, in userland? Any sample scripts?

PHP can do multiplexing already and should work with ssl streams as
well.


------------------------------------------------------------------------

[2008-11-26 10:50:29] scott dot php at scottrix dot co dot uk

OK, so I couldn't find an add attachment button, so here is the patch.

-----------------------------------------
--- ext/openssl/xp_ssl.c.orig 2008-11-18 11:34:50.000000000 +0000
+++ ext/openssl/xp_ssl.c   2008-11-18 11:34:40.000000000 +0000
@@ -223,15 +223,31 @@
      int retry = 1;

      do {
-        nr_bytes = SSL_read(sslsock->ssl_handle, buf, count);
+        int ssl_read = 0;
+        if (! SSL_pending(sslsock->ssl_handle) ) {
+           int ssl_fd = SSL_get_fd(sslsock->ssl_handle);
+           struct timeval tv = { 1 , 0};
+           fd_set fds;
+           int ret;
+
+           FD_ZERO(&fds);
+           FD_SET(ssl_fd,&fds);
+           ret = select((ssl_fd+1),&fds,NULL,NULL,&tv);
+           if ((ret > 0) && FD_ISSET(ssl_fd,&fds)) ssl_read = 1;
+        }
+        else ssl_read = 1;
+
+        if (ssl_read) {
+           nr_bytes = SSL_read(sslsock->ssl_handle, buf, count);

-        if (nr_bytes <= 0) {
-           retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC);
-           stream->eof = (retry == 0 && errno != EAGAIN &&
!SSL_pending(sslsock->ssl_handle));
+           if (nr_bytes <= 0) {
+              retry = handle_ssl_error(stream, nr_bytes, 0
TSRMLS_CC);
+              stream->eof = (retry == 0 && errno != EAGAIN &&
!SSL_pending(sslsock->ssl_handle));

-        } else {
-           /* we got the data */
-           break;
+           } else {
+              /* we got the data */
+              break;
+           }
         }
      } while (retry);
   }
@@ -429,6 +445,16 @@

         if (n <= 0) {
            retry = handle_ssl_error(stream, n, 1 TSRMLS_CC);
+           if (retry) {
+              int ssl_fd = SSL_get_fd(sslsock->ssl_handle);
+              struct timeval tv = { 1 , 0};
+              fd_set fds;
+              int ret;
+
+              FD_ZERO(&fds);
+              FD_SET(ssl_fd,&fds);
+              ret = select((ssl_fd+1),&fds,NULL,NULL,&tv);
+           }
         } else {
            break;
         }
-----------------------------------------

------------------------------------------------------------------------

[2008-11-26 10:48:17] scott dot php at scottrix dot co dot uk

Description:
------------
We have had some problems with CPU usage using PHP test scripts on some
systems at work.  Looking into the strace logs it appeared to be in a
tight loop doing lots of reads mostly getting an EAGAIN error.  Looking
into the problem further it seems there are two locations in the file
ext/openssl/xp_ssl.c that were causing these "loops".

at line 223 (approx):

     int retry = 1;

     do {
        nr_bytes = SSL_read(sslsock->ssl_handle, buf, count);
        if (nr_bytes <= 0) {
           retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC);
           stream->eof = (retry == 0 && errno != EAGAIN &&     
SSL_pending(sslsock->ssl_handle));
        } else {
           /* we got the data */
           break;
        }
     } while (retry);


and the loop around the lines (429):

         if (n <= 0) {
            retry = handle_ssl_error(stream, n, 1 TSRMLS_CC);
         } else {
            break;
         }
 
They both involve SSL connections and I understand that one needs to be
very careful using select in this area since the socket is a layer away
from the SSL reading etc.  However, the openssl code does come with some
examples on how to do this and I have created a patch that seemed to
help a lot in our case that I thought someone who knows more about php
internals would like to look at and maybe incorporate to some extent
into future releases.  I will hopefully be able to attach the patch once
I have submitted the bug.



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=46685&edit=1

Reply via email to