wasi-libc/libc-bottom-half/sources/__wasilibc_fd_renumber.c
Joel Dice 373f8f0149 wasip2 support for close, poll, pselect (#486)
This enables `wasm32-wasip2` support for `close`, `poll`, and `pselect`.  I
cheated a bit for the latter by re-implementing `pselect` in terms of `poll` to
avoid having to implement wasip2 versions of both.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Co-authored-by: Dave Bakker <github@davebakker.io>
2024-06-25 12:13:35 +02:00

111 lines
3.1 KiB
C

#include <wasi/api.h>
#include <wasi/libc.h>
#include <errno.h>
#include <unistd.h>
int __wasilibc_fd_renumber(int fd, int newfd) {
// Scan the preopen fds before making any changes.
__wasilibc_populate_preopens();
__wasi_errno_t error = __wasi_fd_renumber(fd, newfd);
if (error != 0) {
errno = error;
return -1;
}
return 0;
}
#ifdef __wasilibc_use_wasip2
#include <wasi/descriptor_table.h>
void drop_tcp_socket(tcp_socket_t socket) {
switch (socket.state.tag) {
case TCP_SOCKET_STATE_UNBOUND:
case TCP_SOCKET_STATE_BOUND:
case TCP_SOCKET_STATE_CONNECTING:
case TCP_SOCKET_STATE_LISTENING:
case TCP_SOCKET_STATE_CONNECT_FAILED:
// No additional resources to drop.
break;
case TCP_SOCKET_STATE_CONNECTED: {
tcp_socket_state_connected_t connection = socket.state.connected;
poll_pollable_drop_own(connection.input_pollable);
poll_pollable_drop_own(connection.output_pollable);
streams_input_stream_drop_own(connection.input);
streams_output_stream_drop_own(connection.output);
break;
}
default: /* unreachable */ abort();
}
poll_pollable_drop_own(socket.socket_pollable);
tcp_tcp_socket_drop_own(socket.socket);
}
void drop_udp_socket_streams(udp_socket_streams_t streams) {
poll_pollable_drop_own(streams.incoming_pollable);
poll_pollable_drop_own(streams.outgoing_pollable);
udp_incoming_datagram_stream_drop_own(streams.incoming);
udp_outgoing_datagram_stream_drop_own(streams.outgoing);
}
void drop_udp_socket(udp_socket_t socket) {
switch (socket.state.tag) {
case UDP_SOCKET_STATE_UNBOUND:
case UDP_SOCKET_STATE_BOUND_NOSTREAMS:
// No additional resources to drop.
break;
case UDP_SOCKET_STATE_BOUND_STREAMING:
drop_udp_socket_streams(socket.state.bound_streaming.streams);
break;
case UDP_SOCKET_STATE_CONNECTED: {
drop_udp_socket_streams(socket.state.connected.streams);
break;
}
default: /* unreachable */ abort();
}
poll_pollable_drop_own(socket.socket_pollable);
udp_udp_socket_drop_own(socket.socket);
}
#endif // __wasilibc_use_wasip2
int close(int fd) {
// Scan the preopen fds before making any changes.
__wasilibc_populate_preopens();
#ifdef __wasilibc_use_wasip2
descriptor_table_entry_t entry;
if (descriptor_table_remove(fd, &entry)) {
switch (entry.tag)
{
case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET:
drop_tcp_socket(entry.tcp_socket);
break;
case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET:
drop_udp_socket(entry.udp_socket);
break;
default: /* unreachable */ abort();
}
return 0;
}
#endif // __wasilibc_use_wasip2
__wasi_errno_t error = __wasi_fd_close(fd);
if (error != 0) {
errno = error;
return -1;
}
return 0;
}
weak void __wasilibc_populate_preopens(void) {
// This version does nothing. It may be overridden by a version which does
// something if `__wasilibc_find_abspath` or `__wasilibc_find_relpath` are
// used.
}