Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ext/standard/io_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ static void php_io_hooks_php_call(zend_fcall_info_cache *fcc, zval *retval, zend
}

/* A Done that hands data to the caller: bytes in its buffer, a descriptor,
* an exited child, a taken signal, a resolved name */
* an exited child, a taken signal, a resolved name, directory changes */
static bool php_io_op_result_is_data(php_io_op *op, const php_io_completion_obj *c)
{
if (c->status != PHP_IO_DONE || c->error) {
Expand All @@ -1356,6 +1356,7 @@ static bool php_io_op_result_is_data(php_io_op *op, const php_io_completion_obj
switch (op->type) {
case PHP_IO_OP_READ:
case PHP_IO_OP_RECV:
case PHP_IO_OP_DIR_CHANGES:
return c->res != 0;
case PHP_IO_OP_ACCEPT:
case PHP_IO_OP_WAITPID:
Expand Down
11 changes: 11 additions & 0 deletions main/io/php_io_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@ PHPAPI void php_io_op_fsync(php_io_op *op, zend_object *handle, php_socket_t fd,
op->u.fsync.data_only = data_only;
}

PHPAPI void php_io_op_dir_changes(php_io_op *op, php_socket_t fd, void *buf, size_t len, bool subtree)
{
ZEND_ASSERT(((uintptr_t) buf & 3) == 0);
php_io_op_init(op, PHP_IO_OP_DIR_CHANGES, NULL, fd, 0, php_io_deadline_infinite());
op->u.dir_changes.buf = buf;
op->u.dir_changes.len = len;
op->u.dir_changes.subtree = subtree;
}

PHPAPI void php_io_op_any(php_io_op *op, php_io_op **members, uint32_t n, php_io_op_result *results)
{
php_io_op_init(op, PHP_IO_OP_ANY, NULL, SOCK_ERR, 0, php_io_deadline_infinite());
Expand Down Expand Up @@ -1022,6 +1031,8 @@ static bool php_io_result_valid(const php_io_op *op, const php_io_op_result *res
case PHP_IO_OP_RECV:
case PHP_IO_OP_SEND:
return result->res >= 0 && (uint64_t) result->res <= op->u.io.len;
case PHP_IO_OP_DIR_CHANGES:
return result->res >= 0 && (uint64_t) result->res <= op->u.dir_changes.len;
case PHP_IO_OP_ACCEPT:
return result->res >= 0;
case PHP_IO_OP_WAITPID:
Expand Down
31 changes: 31 additions & 0 deletions main/io/php_io_ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,12 @@ static zend_always_inline unsigned php_io_ring_io_len(php_io_op *op)
return (unsigned) MIN(op->u.io.len, UINT32_MAX);
}

/* What one directory change wait takes at most: ior counts in unsigned */
static zend_always_inline unsigned php_io_ring_dir_changes_len(const php_io_op *op)
{
return (unsigned) MIN(op->u.dir_changes.len, UINT32_MAX);
}

/* The inputs are copied and the outputs get slots of their own, so that a
* record outliving the op's frame never touches it */
static void php_io_ring_req_capture(php_io_ring_req *req, php_io_op *op)
Expand Down Expand Up @@ -515,6 +521,9 @@ static void php_io_ring_req_capture(php_io_ring_req *req, php_io_op *op)
req->u.io.buf = pemalloc(MAX(php_io_ring_io_len(op), 1), 1);
memcpy(req->u.io.buf, op->u.io.buf, php_io_ring_io_len(op));
break;
case PHP_IO_OP_DIR_CHANGES:
req->u.io.buf = pemalloc(MAX(php_io_ring_dir_changes_len(op), 1), 1);
break;
default:
break;
}
Expand Down Expand Up @@ -569,6 +578,11 @@ static void php_io_ring_req_output(php_io_ring_req *req, php_io_op *op)
memcpy(op->u.io.buf, req->u.io.buf, res);
}
break;
case PHP_IO_OP_DIR_CHANGES:
if (res > 0) {
memcpy(op->u.dir_changes.buf, req->u.io.buf, res);
}
break;
default:
break;
}
Expand Down Expand Up @@ -615,6 +629,7 @@ static void php_io_ring_req_discard(php_io_ring_req *req)
case PHP_IO_OP_RECV:
case PHP_IO_OP_WRITE:
case PHP_IO_OP_SEND:
case PHP_IO_OP_DIR_CHANGES:
if (req->u.io.buf) {
pefree(req->u.io.buf, 1);
}
Expand Down Expand Up @@ -1026,6 +1041,13 @@ static zend_result php_io_ring_submit_one(php_io_ring *ring, php_io_ring_req *re
case PHP_IO_OP_WAITPID:
case PHP_IO_OP_SIGWAIT:
break;
case PHP_IO_OP_DIR_CHANGES:
#ifdef IOR_FEAT_DIR_CHANGES
if (ring->features & IOR_FEAT_DIR_CHANGES) {
break;
}
#endif
ZEND_FALLTHROUGH;
default:
errno = ENOTSUP;
return FAILURE;
Expand Down Expand Up @@ -1106,6 +1128,15 @@ static zend_result php_io_ring_submit_one(php_io_ring *ring, php_io_ring_req *re
err = rc < 0 ? -rc : 0;
break;
}
#ifdef IOR_FEAT_DIR_CHANGES
case PHP_IO_OP_DIR_CHANGES: {
int rc = ior_prep_dir_changes(ctx, sqe, (ior_fd_t) op->fd, req->u.io.buf, php_io_ring_dir_changes_len(op),
op->u.dir_changes.subtree ? IOR_DIR_CHANGES_SUBTREE : 0);
err = rc < 0 ? -rc : 0;
uses_caller = true;
break;
}
#endif
default:
ZEND_UNREACHABLE();
}
Expand Down
10 changes: 10 additions & 0 deletions main/php_io_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ typedef enum {
PHP_IO_OP_FSYNC,
PHP_IO_OP_WAITPID,
PHP_IO_OP_SIGWAIT,
PHP_IO_OP_DIR_CHANGES,
PHP_IO_OP_ANY,
} php_io_op_type;

Expand Down Expand Up @@ -122,6 +123,9 @@ struct _php_io_op {
struct { pid_t pid; int options; int *status; } waitpid;
/* fd is the signalfd, taken a signal a handle recorded */
struct { const php_sigset_t *set; php_siginfo_t *info; int taken; } sigwait;
/* fd is a directory HANDLE opened with FILE_LIST_DIRECTORY and
* FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED */
struct { void *buf; size_t len; bool subtree; } dir_changes;
struct {
php_io_op **ops; /* caller owned */
uint32_t n;
Expand Down Expand Up @@ -172,6 +176,12 @@ PHPAPI void php_io_op_waitpid(php_io_op *op, zend_object *handle, pid_t pid, int
php_deadline dl);
PHPAPI void php_io_op_sigwait(php_io_op *op, zend_object *handle, const php_sigset_t *set,
php_siginfo_t *info, php_deadline dl);
/* Windows: the next changes in a directory, ReadDirectoryChangesW()'s FILE_NOTIFY_INFORMATION
* records in buf, which must be DWORD-aligned. Done with the bytes written; after 0 (changes were
* lost) or any other completion the caller rescans. A queue that cannot wait for them answers
* Unsupported. */
PHPAPI void php_io_op_dir_changes(php_io_op *op, php_socket_t fd, void *buf, size_t len,
bool subtree);
PHPAPI void php_io_op_any(php_io_op *op, php_io_op **members, uint32_t n, php_io_op_result *results);

/* The op's handle, created for a stream op on the first call and kept by the stream: borrowed */
Expand Down
Loading