mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
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.
This commit is contained in:
parent
102c945501
commit
dabf1053cd
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user