diff options
author | Wez Furlong <wez@php.net> | 2002-10-21 22:54:37 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2002-10-21 22:54:37 +0000 |
commit | dabf1053cdbd1bf8cd9020d16b41eb6b7ca2013f (patch) | |
tree | 84cb33061e3e0e32ddec7c432b5d4b64c5c85233 | |
parent | 102c94550126b9e004d22620300033f0fe9a2006 (diff) | |
download | php-git-dabf1053cdbd1bf8cd9020d16b41eb6b7ca2013f.tar.gz |
Refine stream_select() to work with streams that have data in their read
buffers.
When selecting for read, the streams are examined; if any of them have
pending read data, no actual select(2) call is performed; instead the
streams with buffered data are returned; just like a regular select
call.
Prevent erroneous warning in stream_select when obtaining the fd.
-rw-r--r-- | ext/standard/file.c | 84 | ||||
-rwxr-xr-x | main/php_streams.h | 3 | ||||
-rwxr-xr-x | main/streams.c | 4 |
3 files changed, 83 insertions, 8 deletions
diff --git a/ext/standard/file.c b/ext/standard/file.c index bcc11c7365..0ef7215478 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -650,8 +650,12 @@ static int stream_array_to_fd_set(zval *stream_array, fd_set *fds, int *max_fd T if (stream == NULL) continue; - /* get the fd */ - if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&this_fd, 1)) { + /* get the fd. + * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag + * when casting. It is only used here so that the buffered data warning + * is not displayed. + * */ + if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1)) { FD_SET(this_fd, fds); if (this_fd > *max_fd) { *max_fd = this_fd; @@ -666,7 +670,7 @@ static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC) zval **elem, **dest_elem; php_stream *stream; HashTable *new_hash; - int this_fd; + int this_fd, ret = 0; if (Z_TYPE_P(stream_array) != IS_ARRAY) return 0; @@ -682,12 +686,18 @@ static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC) if (stream == NULL) continue; - /* get the fd */ - if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&this_fd, 1)) { + /* get the fd + * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag + * when casting. It is only used here so that the buffered data warning + * is not displayed. + */ + if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1)) { if (FD_ISSET(this_fd, fds)) { zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem); if (dest_elem) zval_add_ref(dest_elem); + ret++; + continue; } } } @@ -699,7 +709,58 @@ static int stream_array_from_fd_set(zval *stream_array, fd_set *fds TSRMLS_DC) zend_hash_internal_pointer_reset(new_hash); Z_ARRVAL_P(stream_array) = new_hash; - return 1; + return ret; +} + +static int stream_array_emulate_read_fd_set(zval *stream_array TSRMLS_DC) +{ + zval **elem, **dest_elem; + php_stream *stream; + HashTable *new_hash; + int ret = 0; + + if (Z_TYPE_P(stream_array) != IS_ARRAY) + return 0; + + ALLOC_HASHTABLE(new_hash); + zend_hash_init(new_hash, 0, NULL, ZVAL_PTR_DTOR, 0); + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream_array)); + zend_hash_get_current_data(Z_ARRVAL_P(stream_array), (void **) &elem) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(stream_array))) { + + php_stream_from_zval_no_verify(stream, elem); + if (stream == NULL) + continue; + + if ((stream->writepos - stream->readpos) > 0) { + /* allow readable non-descriptor based streams to participate in stream_select. + * Non-descriptor streams will only "work" if they have previously buffered the + * data. Not ideal, but better than nothing. + * This branch of code also allows blocking streams with buffered data to + * operate correctly in stream_select. + * */ + zend_hash_next_index_insert(new_hash, (void *)elem, sizeof(zval *), (void **)&dest_elem); + if (dest_elem) + zval_add_ref(dest_elem); + ret++; + continue; + } + } + + if (ret > 0) { + /* destroy old array and add new one */ + zend_hash_destroy(Z_ARRVAL_P(stream_array)); + efree(Z_ARRVAL_P(stream_array)); + + zend_hash_internal_pointer_reset(new_hash); + Z_ARRVAL_P(stream_array) = new_hash; + } else { + zend_hash_destroy(new_hash); + FREE_HASHTABLE(new_hash); + } + + return ret; } /* }}} */ @@ -738,6 +799,17 @@ PHP_FUNCTION(stream_select) tv_p = &tv; } + /* slight hack to support buffered data; if there is data sitting in the + * read buffer of any of the streams in the read array, let's pretend + * that we selected, but return only the readable sockets */ + if (r_array != NULL) { + + retval = stream_array_emulate_read_fd_set(r_array TSRMLS_CC); + if (retval > 0) { + RETURN_LONG(retval); + } + } + retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p); if (retval == -1) { diff --git a/main/php_streams.h b/main/php_streams.h index 6861671360..e3b07f785a 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -455,7 +455,8 @@ PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char /* try really, really hard to make sure the cast happens (socketpair) */ #define PHP_STREAM_CAST_TRY_HARD 0x80000000 #define PHP_STREAM_CAST_RELEASE 0x40000000 /* stream becomes invalid on success */ -#define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE) +#define PHP_STREAM_CAST_INTERNAL 0x20000000 /* stream cast for internal use */ +#define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE | PHP_STREAM_CAST_INTERNAL) PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC); /* use this to check if a stream can be cast into another form */ #define php_stream_can_cast(stream, as) _php_stream_cast((stream), (as), NULL, 0 TSRMLS_CC) diff --git a/main/streams.c b/main/streams.c index cab4e2f001..e288445b3b 100755 --- a/main/streams.c +++ b/main/streams.c @@ -1820,7 +1820,9 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show exit_success: - if ((stream->writepos - stream->readpos) > 0 && stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE) { + if ((stream->writepos - stream->readpos) > 0 && + stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE && + (flags & PHP_STREAM_CAST_INTERNAL) == 0) { /* the data we have buffered will be lost to the third party library that * will be accessing the stream. Emit a warning so that the end-user will * know that they should try something else */ |