diff --git a/libc-bottom-half/cloudlibc/src/libc/poll/poll.c b/libc-bottom-half/cloudlibc/src/libc/poll/poll.c index 0ee14791d..98ee1f746 100644 --- a/libc-bottom-half/cloudlibc/src/libc/poll/poll.c +++ b/libc-bottom-half/cloudlibc/src/libc/poll/poll.c @@ -140,7 +140,11 @@ int poll(struct pollfd* fds, nfds_t nfds, int timeout) for (size_t i = 0; i < nfds; ++i) { descriptor_table_entry_t* entry; if (descriptor_table_get_ref(fds[i].fd, &entry)) { - found_socket = true; + if (entry->tag == DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET + || entry->tag == DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET) + found_socket = true; + else + found_non_socket = true; } else { found_non_socket = true; } @@ -155,16 +159,8 @@ int poll(struct pollfd* fds, nfds_t nfds, int timeout) errno = ENOTSUP; return -1; } - - return poll_wasip2(fds, nfds, timeout); - } else if (found_non_socket) { - return poll_wasip1(fds, nfds, timeout); - } else if (timeout >= 0) { - return poll_wasip2(fds, nfds, timeout); - } else { - errno = ENOTSUP; - return -1; } + return poll_wasip2(fds, nfds, timeout); } #else // not __wasilibc_use_wasip2 int poll(struct pollfd* fds, nfds_t nfds, int timeout) diff --git a/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c b/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c index 335186c41..74dd0f89a 100644 --- a/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c +++ b/libc-bottom-half/cloudlibc/src/libc/sys/ioctl/ioctl.c @@ -57,7 +57,8 @@ int ioctl(int fildes, int request, ...) { return -1; } } - + // TODO: In particular, this doesn't support using FIONREAD + // with file descriptors default: errno = ENOPROTOOPT; return -1; @@ -111,11 +112,6 @@ int ioctl(int fildes, int request, ...) { return 0; } case FIONBIO: { -#ifdef __wasilibc_use_wasip2 - // wasip2 doesn't support setting the non-blocking flag - errno = ENOTSUP; - return -1; -#else // Obtain the current file descriptor flags. __wasi_fdstat_t fds; __wasi_errno_t error = __wasi_fd_fdstat_get(fildes, &fds); @@ -140,7 +136,6 @@ int ioctl(int fildes, int request, ...) { return -1; } return 0; -#endif } default: // Invalid request. diff --git a/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c b/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c index 060c0d135..055b790aa 100644 --- a/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c +++ b/libc-bottom-half/cloudlibc/src/libc/time/clock_nanosleep.c @@ -23,24 +23,22 @@ int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, if ((flags & ~TIMER_ABSTIME) != 0) return EINVAL; - // Prepare polling subscription. - __wasi_subscription_t sub = { - .u.tag = __WASI_EVENTTYPE_CLOCK, - .u.u.clock.id = clock_id->id, - .u.u.clock.flags = flags, - }; - // Convert to wall_clock_datetime_t - wall_clock_datetime_t timeout; - if (!timespec_to_timestamp_clamp(rqtp, &timeout)) - return EINVAL; - sub.u.u.clock.timeout = (timeout.seconds * NSEC_PER_SEC) - + timeout.nanoseconds; + // Note: rmtp is ignored + + if (clock_id != CLOCK_MONOTONIC) { + // wasip2 only provides a pollable for monotonic clocks + return ENOTSUP; + } + + // Prepare pollable + int64_t duration = (rqtp->tv_sec * NSEC_PER_SEC) + rqtp->tv_nsec; + monotonic_clock_own_pollable_t pollable = monotonic_clock_subscribe_duration(duration); // Block until polling event is triggered. - size_t nevents; - __wasi_event_t ev; - __wasi_errno_t error = __wasi_poll_oneoff(&sub, &ev, 1, &nevents); - return error == 0 && ev.error == 0 ? 0 : ENOTSUP; + poll_method_pollable_block(poll_borrow_pollable(pollable)); + + poll_pollable_drop_own(pollable); + return 0; } #else int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c b/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c index 410852142..507286dcf 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/lseek.c @@ -69,13 +69,14 @@ off_t __lseek(int fildes, off_t offset, int whence) { } } // Drop the existing streams + if (entry->stream.read_pollable_is_initialized) + poll_pollable_drop_own(entry->stream.read_pollable); + if (entry->stream.write_pollable_is_initialized) + poll_pollable_drop_own(entry->stream.write_pollable); if (entry->stream.file_info.readable) streams_input_stream_drop_borrow(entry->stream.read_stream); - if (entry->stream.file_info.writable) { - if (entry->stream.pollable_is_initialized) - poll_pollable_drop_own(entry->stream.pollable); + if (entry->stream.file_info.writable) streams_output_stream_drop_borrow(entry->stream.write_stream); - } // Open a new stream with the right offset if (entry->stream.file_info.readable) { @@ -106,9 +107,10 @@ off_t __lseek(int fildes, off_t offset, int whence) { // Update output_stream.stream with the new stream entry->stream.write_stream = streams_borrow_output_stream(new_stream); - entry->stream.pollable_is_initialized = false; } + entry->stream.read_pollable_is_initialized = false; + entry->stream.write_pollable_is_initialized = false; // Update offset entry->stream.offset = offset_to_use; } else { diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/read.c b/libc-bottom-half/cloudlibc/src/libc/unistd/read.c index 4f413eb19..444b64609 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/read.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/read.c @@ -31,6 +31,7 @@ ssize_t read(int fildes, void *buf, size_t nbyte) { // Get the input stream filesystem_error_code_t error_code; streams_own_input_stream_t input_stream_own; + ok = filesystem_method_descriptor_read_via_stream(entry->file.file_handle, 0, &input_stream_own, @@ -62,7 +63,8 @@ ssize_t read(int fildes, void *buf, size_t nbyte) { // for this file new_entry.tag = DESCRIPTOR_TABLE_ENTRY_FILE_STREAM; new_entry.stream.read_stream = input_stream; - new_entry.stream.pollable_is_initialized = false; + new_entry.stream.read_pollable_is_initialized = false; + new_entry.stream.write_pollable_is_initialized = false; new_entry.stream.offset = 0; new_entry.stream.file_info.readable = entry->file.readable; new_entry.stream.file_info.writable = entry->file.writable; diff --git a/libc-bottom-half/cloudlibc/src/libc/unistd/write.c b/libc-bottom-half/cloudlibc/src/libc/unistd/write.c index 10af64084..862bc7ba3 100644 --- a/libc-bottom-half/cloudlibc/src/libc/unistd/write.c +++ b/libc-bottom-half/cloudlibc/src/libc/unistd/write.c @@ -53,11 +53,11 @@ ssize_t write(int fildes, const void *buf, size_t nbyte) { return -1; } output_stream = entry->stream.write_stream; - if (!entry->stream.pollable_is_initialized) { - pollable = entry->stream.pollable = streams_method_output_stream_subscribe(output_stream); - entry->stream.pollable_is_initialized = true; + if (!entry->stream.write_pollable_is_initialized) { + pollable = entry->stream.write_pollable = streams_method_output_stream_subscribe(output_stream); + entry->stream.write_pollable_is_initialized = true; } else - pollable = entry->stream.pollable; + pollable = entry->stream.write_pollable; } else { errno = EBADF; return -1; @@ -114,8 +114,9 @@ ssize_t write(int fildes, const void *buf, size_t nbyte) { } new_entry.stream.read_stream = streams_borrow_input_stream(read_stream); } - new_entry.stream.pollable = pollable; - new_entry.stream.pollable_is_initialized = true; + new_entry.stream.write_pollable = pollable; + new_entry.stream.read_pollable_is_initialized = false; + new_entry.stream.write_pollable_is_initialized = true; new_entry.stream.write_stream = output_stream; new_entry.stream.offset = contents.len; new_entry.stream.file_info.readable = entry->file.readable; diff --git a/libc-bottom-half/headers/private/wasi/descriptor_table.h b/libc-bottom-half/headers/private/wasi/descriptor_table.h index 5acf46c26..2103874bc 100644 --- a/libc-bottom-half/headers/private/wasi/descriptor_table.h +++ b/libc-bottom-half/headers/private/wasi/descriptor_table.h @@ -128,9 +128,11 @@ typedef struct { streams_borrow_output_stream_t write_stream; // Current position in stream, relative to the beginning of the *file*, measured in bytes off_t offset; - // Used for checking readiness to write to stream. Lazily initialized. - streams_own_pollable_t pollable; - bool pollable_is_initialized; + // Used for checking readiness to read/write to stream. Lazily initialized + streams_own_pollable_t read_pollable; + streams_own_pollable_t write_pollable; + bool read_pollable_is_initialized; + bool write_pollable_is_initialized; // When the stream is closed, the caller should // replace this entry in the table with the file handle file_t file_info; diff --git a/libc-bottom-half/headers/private/wasi/file_utils.h b/libc-bottom-half/headers/private/wasi/file_utils.h index cda8bbd93..fab1365c1 100644 --- a/libc-bottom-half/headers/private/wasi/file_utils.h +++ b/libc-bottom-half/headers/private/wasi/file_utils.h @@ -68,6 +68,8 @@ static bool init_stdin() { entry.tag = DESCRIPTOR_TABLE_ENTRY_FILE_STREAM; entry.stream.read_stream = streams_borrow_input_stream(stdin_get_stdin()); entry.stream.offset = 0; + entry.stream.read_pollable_is_initialized = false; + entry.stream.write_pollable_is_initialized = false; entry.stream.file_info.readable = true; entry.stream.file_info.writable = false; // entry.stream.file_info.file_handle is uninitialized, but it will never be used @@ -81,7 +83,8 @@ static bool init_stdout() { entry.tag = DESCRIPTOR_TABLE_ENTRY_FILE_STREAM; entry.stream.write_stream = streams_borrow_output_stream(stdout_get_stdout()); entry.stream.offset = 0; - entry.stream.pollable = streams_method_output_stream_subscribe(entry.stream.write_stream); + entry.stream.read_pollable_is_initialized = false; + entry.stream.write_pollable_is_initialized = false; entry.stream.file_info.readable = false; entry.stream.file_info.writable = true; // entry.stream.file_info.file_handle is uninitialized, but it will never be used @@ -95,7 +98,8 @@ static bool init_stderr() { entry.tag = DESCRIPTOR_TABLE_ENTRY_FILE_STREAM; entry.stream.write_stream = streams_borrow_output_stream(stderr_get_stderr()); entry.stream.offset = 0; - entry.stream.pollable = streams_method_output_stream_subscribe(entry.stream.write_stream); + entry.stream.read_pollable_is_initialized = false; + entry.stream.write_pollable_is_initialized = false; entry.stream.file_info.readable = false; entry.stream.file_info.writable = true; // entry.stream.file_info.file_handle is uninitialized, but it will never be used diff --git a/libc-bottom-half/sources/__wasilibc_fd_renumber.c b/libc-bottom-half/sources/__wasilibc_fd_renumber.c index e76455408..d5c30314b 100644 --- a/libc-bottom-half/sources/__wasilibc_fd_renumber.c +++ b/libc-bottom-half/sources/__wasilibc_fd_renumber.c @@ -122,8 +122,10 @@ int close(int fd) { drop_directory_stream(entry.directory_stream_info.directory_stream); break; case DESCRIPTOR_TABLE_ENTRY_FILE_STREAM: - if (entry.stream.pollable_is_initialized) - poll_pollable_drop_own(entry.stream.pollable); + if (entry.stream.read_pollable_is_initialized) + poll_pollable_drop_own(entry.stream.read_pollable); + if (entry.stream.write_pollable_is_initialized) + poll_pollable_drop_own(entry.stream.write_pollable); if (entry.stream.file_info.readable) streams_input_stream_drop_borrow(entry.stream.read_stream); if (entry.stream.file_info.writable) diff --git a/libc-bottom-half/sources/poll-wasip2.c b/libc-bottom-half/sources/poll-wasip2.c index be7809c66..a2303f03e 100644 --- a/libc-bottom-half/sources/poll-wasip2.c +++ b/libc-bottom-half/sources/poll-wasip2.c @@ -4,254 +4,301 @@ #include typedef struct { - poll_own_pollable_t pollable; - struct pollfd *pollfd; - descriptor_table_entry_t *entry; - short events; + poll_own_pollable_t pollable; + struct pollfd *pollfd; + descriptor_table_entry_t *entry; + short events; } state_t; int poll_wasip2(struct pollfd *fds, size_t nfds, int timeout) { - int event_count = 0; - for (size_t i = 0; i < nfds; ++i) { - fds[i].revents = 0; - } + int event_count = 0; + for (size_t i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } - size_t max_pollables = (2 * nfds) + 1; - state_t states[max_pollables]; - size_t state_index = 0; - for (size_t i = 0; i < nfds; ++i) { - struct pollfd *pollfd = fds + i; - descriptor_table_entry_t *entry; - if (descriptor_table_get_ref(pollfd->fd, &entry)) { - switch (entry->tag) { - case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET: { - tcp_socket_t *socket = &(entry->tcp_socket); - switch (socket->state.tag) { - case TCP_SOCKET_STATE_CONNECTING: - case TCP_SOCKET_STATE_LISTENING: { - if ((pollfd->events & - (POLLRDNORM | POLLWRNORM)) != 0) { - states[state_index++] = (state_t){ - .pollable = - socket->socket_pollable, - .pollfd = pollfd, - .entry = entry, - .events = pollfd->events - }; - } - break; - } + size_t max_pollables = (2 * nfds) + 1; + state_t states[max_pollables]; + size_t state_index = 0; + for (size_t i = 0; i < nfds; ++i) { + struct pollfd *pollfd = fds + i; + descriptor_table_entry_t *entry; + if (descriptor_table_get_ref(pollfd->fd, &entry)) { + switch (entry->tag) { + case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET: { + tcp_socket_t *socket = &(entry->tcp_socket); + switch (socket->state.tag) { + case TCP_SOCKET_STATE_CONNECTING: + case TCP_SOCKET_STATE_LISTENING: { + if ((pollfd->events & + (POLLRDNORM | POLLWRNORM)) != 0) { + states[state_index++] = (state_t){ + .pollable = + socket->socket_pollable, + .pollfd = pollfd, + .entry = entry, + .events = pollfd->events + }; + } + break; + } - case TCP_SOCKET_STATE_CONNECTED: { - if ((pollfd->events & POLLRDNORM) != - 0) { - states[state_index++] = (state_t){ - .pollable = - socket->state - .connected - .input_pollable, - .pollfd = pollfd, - .entry = entry, - .events = POLLRDNORM - }; - } - if ((pollfd->events & POLLWRNORM) != - 0) { - states[state_index++] = (state_t){ - .pollable = - socket->state - .connected - .output_pollable, - .pollfd = pollfd, - .entry = entry, - .events = POLLWRNORM - }; - } - break; - } + case TCP_SOCKET_STATE_CONNECTED: { + if ((pollfd->events & POLLRDNORM) != + 0) { + states[state_index++] = (state_t){ + .pollable = + socket->state + .connected + .input_pollable, + .pollfd = pollfd, + .entry = entry, + .events = POLLRDNORM + }; + } + if ((pollfd->events & POLLWRNORM) != + 0) { + states[state_index++] = (state_t){ + .pollable = + socket->state + .connected + .output_pollable, + .pollfd = pollfd, + .entry = entry, + .events = POLLWRNORM + }; + } + break; + } - case TCP_SOCKET_STATE_CONNECT_FAILED: { - if (pollfd->revents == 0) { - ++event_count; - } - pollfd->revents |= pollfd->events; - break; - } + case TCP_SOCKET_STATE_CONNECT_FAILED: { + if (pollfd->revents == 0) { + ++event_count; + } + pollfd->revents |= pollfd->events; + break; + } - default: - errno = ENOTSUP; - return -1; - } - break; - } + default: + errno = ENOTSUP; + return -1; + } + break; + } - case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET: { - udp_socket_t *socket = &(entry->udp_socket); - switch (socket->state.tag) { - case UDP_SOCKET_STATE_UNBOUND: - case UDP_SOCKET_STATE_BOUND_NOSTREAMS: { - if (pollfd->revents == 0) { - ++event_count; - } - pollfd->revents |= pollfd->events; - break; - } + case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET: { + udp_socket_t *socket = &(entry->udp_socket); + switch (socket->state.tag) { + case UDP_SOCKET_STATE_UNBOUND: + case UDP_SOCKET_STATE_BOUND_NOSTREAMS: { + if (pollfd->revents == 0) { + ++event_count; + } + pollfd->revents |= pollfd->events; + break; + } - case UDP_SOCKET_STATE_BOUND_STREAMING: - case UDP_SOCKET_STATE_CONNECTED: { - udp_socket_streams_t *streams; - if (socket->state.tag == - UDP_SOCKET_STATE_BOUND_STREAMING) { - streams = &( - socket->state - .bound_streaming - .streams); - } else { - streams = &( - socket->state.connected - .streams); - } - if ((pollfd->events & POLLRDNORM) != - 0) { - states[state_index++] = (state_t){ - .pollable = - streams->incoming_pollable, - .pollfd = pollfd, - .entry = entry, - .events = POLLRDNORM - }; - } - if ((pollfd->events & POLLWRNORM) != - 0) { - states[state_index++] = (state_t){ - .pollable = - streams->outgoing_pollable, - .pollfd = pollfd, - .entry = entry, - .events = POLLWRNORM - }; - } - break; - } + case UDP_SOCKET_STATE_BOUND_STREAMING: + case UDP_SOCKET_STATE_CONNECTED: { + udp_socket_streams_t *streams; + if (socket->state.tag == + UDP_SOCKET_STATE_BOUND_STREAMING) { + streams = &( + socket->state + .bound_streaming + .streams); + } else { + streams = &( + socket->state.connected + .streams); + } + if ((pollfd->events & POLLRDNORM) != + 0) { + states[state_index++] = (state_t){ + .pollable = + streams->incoming_pollable, + .pollfd = pollfd, + .entry = entry, + .events = POLLRDNORM + }; + } + if ((pollfd->events & POLLWRNORM) != + 0) { + states[state_index++] = (state_t){ + .pollable = + streams->outgoing_pollable, + .pollfd = pollfd, + .entry = entry, + .events = POLLWRNORM + }; + } + break; + } - default: - errno = ENOTSUP; - return -1; - } - break; - } + default: + errno = ENOTSUP; + return -1; + } + break; + } + case DESCRIPTOR_TABLE_ENTRY_FILE_STREAM: { + file_stream_t *stream = &entry->stream; + if ((pollfd->events & POLLRDNORM) != 0) { + if (!stream->file_info.readable) { + errno = EBADF; + return -1; + } + streams_own_pollable_t input_stream_pollable = stream->read_pollable; + if (!stream->read_pollable_is_initialized) { + input_stream_pollable = stream->read_pollable = streams_method_input_stream_subscribe(stream->read_stream); + stream->read_pollable_is_initialized = true; + } + states[state_index++] = (state_t) { + .pollable = input_stream_pollable, + .pollfd = pollfd, + .entry = entry, + .events = pollfd->events + }; + } + if ((pollfd->events & POLLWRNORM) != 0) { + if (!stream->file_info.writable) { + errno = EBADF; + return -1; + } + streams_own_pollable_t output_stream_pollable = stream->write_pollable; + if (!stream->write_pollable_is_initialized) { + output_stream_pollable = stream->write_pollable = streams_method_output_stream_subscribe(stream->write_stream); + stream->write_pollable_is_initialized = true; + } + states[state_index++] = (state_t){ + .pollable = output_stream_pollable, + .pollfd = pollfd, + .entry = entry, + .events = pollfd->events + }; + } + break; + } + // File must be open + case DESCRIPTOR_TABLE_ENTRY_FILE_HANDLE: + errno = EBADF; + return -1; + default: + errno = ENOTSUP; + return -1; + } + } else { + abort(); + } + } - default: - errno = ENOTSUP; - return -1; - } - } else { - abort(); - } - } + if (event_count > 0 && timeout != 0) { + return event_count; + } - if (event_count > 0 && timeout != 0) { - return event_count; - } + poll_borrow_pollable_t pollables[state_index + 1]; + for (size_t i = 0; i < state_index; ++i) { + pollables[i] = poll_borrow_pollable(states[i].pollable); + } - poll_borrow_pollable_t pollables[state_index + 1]; - for (size_t i = 0; i < state_index; ++i) { - pollables[i] = poll_borrow_pollable(states[i].pollable); - } + poll_own_pollable_t timeout_pollable; + size_t pollable_count = state_index; + if (timeout >= 0) { + timeout_pollable = monotonic_clock_subscribe_duration( + ((monotonic_clock_duration_t)timeout) * 1000000); + pollables[pollable_count++] = + poll_borrow_pollable(timeout_pollable); + } - poll_own_pollable_t timeout_pollable; - size_t pollable_count = state_index; - if (timeout >= 0) { - timeout_pollable = monotonic_clock_subscribe_duration( - ((monotonic_clock_duration_t)timeout) * 1000000); - pollables[pollable_count++] = - poll_borrow_pollable(timeout_pollable); - } + wasip2_list_u32_t ready; + poll_list_borrow_pollable_t list = { + .ptr = (poll_borrow_pollable_t *)&pollables, + .len = pollable_count + }; + poll_poll(&list, &ready); - wasip2_list_u32_t ready; - poll_list_borrow_pollable_t list = { - .ptr = (poll_borrow_pollable_t *)&pollables, - .len = pollable_count - }; - poll_poll(&list, &ready); + for (size_t i = 0; i < ready.len; ++i) { + size_t index = ready.ptr[i]; + if (index < state_index) { + state_t *state = &states[index]; + if (state->entry->tag == + DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET && + state->entry->tcp_socket.state.tag == + TCP_SOCKET_STATE_CONNECTING) { + tcp_socket_t *socket = + &(state->entry->tcp_socket); + tcp_borrow_tcp_socket_t borrow = + tcp_borrow_tcp_socket(socket->socket); + tcp_tuple2_own_input_stream_own_output_stream_t + tuple; + tcp_error_code_t error; + if (tcp_method_tcp_socket_finish_connect( + borrow, &tuple, &error)) { + streams_borrow_input_stream_t + input_stream_borrow = + streams_borrow_input_stream( + tuple.f0); + streams_own_pollable_t input_pollable = + streams_method_input_stream_subscribe( + input_stream_borrow); + streams_borrow_output_stream_t + output_stream_borrow = + streams_borrow_output_stream( + tuple.f1); + streams_own_pollable_t output_pollable = + streams_method_output_stream_subscribe( + output_stream_borrow); + socket->state = + (tcp_socket_state_t){ .tag = TCP_SOCKET_STATE_CONNECTED, + .connected = { + .input_pollable = + input_pollable, + .input = + tuple.f0, + .output_pollable = + output_pollable, + .output = + tuple.f1, + } }; + if (state->pollfd->revents == 0) { + ++event_count; + } + state->pollfd->revents |= state->events; + } else if (error == + NETWORK_ERROR_CODE_WOULD_BLOCK) { + // No events yet -- application will need to poll again + } else { + socket->state = + (tcp_socket_state_t){ .tag = TCP_SOCKET_STATE_CONNECT_FAILED, + .connect_failed = { + .error_code = + error, + } }; + if (state->pollfd->revents == 0) { + ++event_count; + } + state->pollfd->revents |= state->events; + } + } else if (state->entry->tag == DESCRIPTOR_TABLE_ENTRY_FILE_STREAM) { + if (state->pollfd->revents == 0) { + ++event_count; + } + state->pollfd->revents |= state->events; + } + else { + if (state->pollfd->revents == 0) { + ++event_count; + } + state->pollfd->revents |= state->events; + } + } + } - for (size_t i = 0; i < ready.len; ++i) { - size_t index = ready.ptr[i]; - if (index < state_index) { - state_t *state = &states[index]; - if (state->entry->tag == - DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET && - state->entry->tcp_socket.state.tag == - TCP_SOCKET_STATE_CONNECTING) { - tcp_socket_t *socket = - &(state->entry->tcp_socket); - tcp_borrow_tcp_socket_t borrow = - tcp_borrow_tcp_socket(socket->socket); - tcp_tuple2_own_input_stream_own_output_stream_t - tuple; - tcp_error_code_t error; - if (tcp_method_tcp_socket_finish_connect( - borrow, &tuple, &error)) { - streams_borrow_input_stream_t - input_stream_borrow = - streams_borrow_input_stream( - tuple.f0); - streams_own_pollable_t input_pollable = - streams_method_input_stream_subscribe( - input_stream_borrow); - streams_borrow_output_stream_t - output_stream_borrow = - streams_borrow_output_stream( - tuple.f1); - streams_own_pollable_t output_pollable = - streams_method_output_stream_subscribe( - output_stream_borrow); - socket->state = - (tcp_socket_state_t){ .tag = TCP_SOCKET_STATE_CONNECTED, - .connected = { - .input_pollable = - input_pollable, - .input = - tuple.f0, - .output_pollable = - output_pollable, - .output = - tuple.f1, - } }; - if (state->pollfd->revents == 0) { - ++event_count; - } - state->pollfd->revents |= state->events; - } else if (error == - NETWORK_ERROR_CODE_WOULD_BLOCK) { - // No events yet -- application will need to poll again - } else { - socket->state = - (tcp_socket_state_t){ .tag = TCP_SOCKET_STATE_CONNECT_FAILED, - .connect_failed = { - .error_code = - error, - } }; - if (state->pollfd->revents == 0) { - ++event_count; - } - state->pollfd->revents |= state->events; - } - } else { - if (state->pollfd->revents == 0) { - ++event_count; - } - state->pollfd->revents |= state->events; - } - } - } + wasip2_list_u32_free(&ready); - wasip2_list_u32_free(&ready); + if (timeout >= 0) { + poll_pollable_drop_own(timeout_pollable); + } - if (timeout >= 0) { - poll_pollable_drop_own(timeout_pollable); - } - - return event_count; + return event_count; } diff --git a/test/src/misc/clock_nanosleep.c b/test/src/misc/clock_nanosleep.c new file mode 100644 index 000000000..442fe5152 --- /dev/null +++ b/test/src/misc/clock_nanosleep.c @@ -0,0 +1,50 @@ +//! add-flags.py(RUN): --dir fs::/ + +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(c) do { \ + errno = 0; \ + if (!(c)) \ + t_error("%s failed (errno = %d)\n", #c, errno); \ +} while(0) + +int main(void) +{ + // Get the clock resolution + struct timespec clock_resolution; + clock_getres(CLOCK_MONOTONIC, &clock_resolution); + // Not much point running the test if the resolution is >= 1 sec + TEST(clock_resolution.tv_sec==0); + + // Adjust this number if necessary + // In wasip2 we don't get accurate results for sleeping < 1 ms + + struct timespec time_to_sleep = { .tv_sec = 0, + .tv_nsec = 1E6 * clock_resolution.tv_nsec }; + + struct timespec start_time, end_time; + clock_gettime(CLOCK_MONOTONIC, &start_time); + + TEST(clock_nanosleep(CLOCK_MONOTONIC, 0, &time_to_sleep, NULL)==0); + clock_gettime(CLOCK_MONOTONIC, &end_time); + TEST(end_time.tv_sec - start_time.tv_sec <= 1); + + long nanoseconds_elapsed = (end_time.tv_sec - start_time.tv_sec) + - start_time.tv_nsec + + end_time.tv_nsec; + + // Test that the difference between the requested amount of sleep + // and the actual elapsed time is within an acceptable margin + double difference = abs(nanoseconds_elapsed - time_to_sleep.tv_nsec) + / time_to_sleep.tv_nsec; + + // Allow the actual sleep time to be twice as much as the requested time + TEST(difference <= 1); + + return t_status; +} diff --git a/test/src/misc/ioctl.c b/test/src/misc/ioctl.c new file mode 100644 index 000000000..457a77fd2 --- /dev/null +++ b/test/src/misc/ioctl.c @@ -0,0 +1,41 @@ +//! add-flags.py(RUN): --dir fs::/ --wasi=inherit-network=y + +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define TEST(c) do { \ + errno = 0; \ + if (!(c)) \ + t_error("%s failed (errno = %d)\n", #c, errno); \ +} while(0) + +int main(void) +{ + char tmp[] = "testsuite-XXXXXX"; + int fd; + int nbytes = 0; + int flags = 0; + flags |= O_RDWR | O_CREAT | O_EXCL; + + TEST((fd = open(tmp, flags, 0600)) > 2); + TEST(write(fd, "hello", 6)==6); + +#ifdef __wasilibc_use_wasip2 + // Not supported on wasip2 + TEST(ioctl(fd, FIONREAD, &nbytes)==-1); +#else + // Always returns 0? + TEST(ioctl(fd, FIONREAD, &nbytes)==0); +#endif + close(fd); + TEST(unlink(tmp)==0); + + return t_status; +} diff --git a/test/src/misc/poll.c b/test/src/misc/poll.c new file mode 100644 index 000000000..17857ca50 --- /dev/null +++ b/test/src/misc/poll.c @@ -0,0 +1,36 @@ +//! add-flags.py(RUN): --dir fs::/ + +// Modified from libc-test to not use tmpfile or /dev/null + +#include +#include +#include +#include +#include "test.h" + +#define TEST(c, ...) ((c) ? 1 : (t_error(#c" failed: " __VA_ARGS__),0)) + +int main(void) +{ + char tmp[] = "testsuite-XXXXXX"; + int fd; + int flags = 0; + + // Not a very useful test, but it's hard to test poll() without threads + + TEST((fd = open(tmp, flags | O_RDWR | O_CREAT | O_EXCL, 0600)) > 2); + TEST(write(fd, "hello", 6)==6); + + struct pollfd poll_fd = { .fd = fd, .events = POLLRDNORM, .revents = 0 }; + TEST(poll(&poll_fd, 1, 1)==1); + + poll_fd.events = POLLWRNORM; + TEST(poll(&poll_fd, 1, 1)==1); + + close(fd); + + if (fd > 2) + TEST(unlink(tmp) != -1); + + return t_status; +}