Skip to content

Commit 09683b3

Browse files
dicejbadeend
andauthored
add descriptor table for mapping fds to handles (#464)
* add descriptor table for mapping fds to handles This introduces `descriptor_table.h` and `descriptor_table.c`, providing a global hashtable for tracking `wasi-libc`-managed file descriptors. WASI Preview 2 has no notion of file descriptors and instead uses unforgeable resource handles. Moreover, there's not necessarily a one-to-one correspondence between POSIX file descriptors and resource handles (e.g. a TCP connection may require separate handles for reading, writing, and polling the same connection). We use this table to map each POSIX descriptor to a set of one or more handles and any extra state which libc needs to track. Note that we've added `descriptor_table.h` to the libc-bottom-half/headers/public/wasi directory, making it part of the public API. The intention is to give applications access to the mapping, enabling them to convert descriptors to handles and vice-versa should they need to interoperate with both libc and WASI directly. Co-authored-by: Dave Bakker <github@davebakker.io> Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add dummy fields to otherwise empty structs The C standard doesn't allow empty structs. Clang doesn't currently complain, but we might as well stick to the spec in case it becomes more strict in the future. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * move descriptor_table.h to headers/private We're not yet ready to commit to making this API public, so we'll make it private for now. I've also expanded a comment in descriptor_table.c to explain the current ABI for resource handles. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * re-run clang-format to fix indentation Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com> Co-authored-by: Dave Bakker <github@davebakker.io>
1 parent 0fe51d2 commit 09683b3

5 files changed

Lines changed: 394 additions & 3 deletions

File tree

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ ifeq ($(WASI_SNAPSHOT), preview1)
7979
# Omit source files not relevant to WASI Preview 1. As we introduce files
8080
# supporting `wasi-sockets` for `wasm32-wasi-preview2`, we'll add those files to
8181
# this list.
82-
LIBC_BOTTOM_HALF_OMIT_SOURCES := $(LIBC_BOTTOM_HALF_SOURCES)/preview2.c
82+
LIBC_BOTTOM_HALF_OMIT_SOURCES := \
83+
$(LIBC_BOTTOM_HALF_SOURCES)/preview2.c \
84+
$(LIBC_BOTTOM_HALF_SOURCES)/descriptor_table.c
8385
LIBC_BOTTOM_HALF_ALL_SOURCES := $(filter-out $(LIBC_BOTTOM_HALF_OMIT_SOURCES),$(LIBC_BOTTOM_HALF_ALL_SOURCES))
84-
# Omit preview2.h from include-all.c test.
85-
INCLUDE_ALL_CLAUSES := -not -name preview2.h
86+
# Omit preview2-specific headers from include-all.c test.
87+
INCLUDE_ALL_CLAUSES := -not -name preview2.h -not -name descriptor_table.h
8688
endif
8789

8890
# FIXME(https://reviews.llvm.org/D85567) - due to a bug in LLD the weak

expected/wasm32-wasi-preview2/defined-symbols.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,9 @@ ctanhl
509509
ctanl
510510
ctime
511511
ctime_r
512+
descriptor_table_get_ref
513+
descriptor_table_insert
514+
descriptor_table_remove
512515
difftime
513516
dirfd
514517
dirname

expected/wasm32-wasi-preview2/undefined-symbols.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ __subtf3
6565
__trunctfdf2
6666
__trunctfsf2
6767
__unordtf2
68+
__wasi_preview1_adapter_close_badfd
69+
__wasi_preview1_adapter_open_badfd
6870
__wasm_call_ctors
6971
__wasm_import_environment_get_arguments
7072
__wasm_import_environment_get_environment
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#ifndef DESCRIPTOR_TABLE_H
2+
#define DESCRIPTOR_TABLE_H
3+
4+
#include <wasi/preview2.h>
5+
6+
typedef struct {
7+
int dummy;
8+
} tcp_socket_state_unbound_t;
9+
typedef struct {
10+
int dummy;
11+
} tcp_socket_state_bound_t;
12+
typedef struct {
13+
int dummy;
14+
} tcp_socket_state_connecting_t;
15+
typedef struct {
16+
int dummy;
17+
} tcp_socket_state_listening_t;
18+
19+
typedef struct {
20+
streams_own_input_stream_t input;
21+
poll_own_pollable_t input_pollable;
22+
streams_own_output_stream_t output;
23+
poll_own_pollable_t output_pollable;
24+
} tcp_socket_state_connected_t;
25+
26+
typedef struct {
27+
network_error_code_t error_code;
28+
} tcp_socket_state_connect_failed_t;
29+
30+
// This is a tagged union. When adding/removing/renaming cases, be sure to keep the tag and union definitions in sync.
31+
typedef struct {
32+
enum {
33+
TCP_SOCKET_STATE_UNBOUND,
34+
TCP_SOCKET_STATE_BOUND,
35+
TCP_SOCKET_STATE_CONNECTING,
36+
TCP_SOCKET_STATE_CONNECTED,
37+
TCP_SOCKET_STATE_CONNECT_FAILED,
38+
TCP_SOCKET_STATE_LISTENING,
39+
} tag;
40+
union {
41+
tcp_socket_state_unbound_t unbound;
42+
tcp_socket_state_bound_t bound;
43+
tcp_socket_state_connecting_t connecting;
44+
tcp_socket_state_connected_t connected;
45+
tcp_socket_state_connect_failed_t connect_failed;
46+
tcp_socket_state_listening_t listening;
47+
};
48+
} tcp_socket_state_t;
49+
50+
typedef struct {
51+
tcp_own_tcp_socket_t socket;
52+
poll_own_pollable_t socket_pollable;
53+
bool blocking;
54+
bool fake_nodelay;
55+
bool fake_reuseaddr;
56+
network_ip_address_family_t family;
57+
tcp_socket_state_t state;
58+
} tcp_socket_t;
59+
60+
typedef struct {
61+
udp_own_incoming_datagram_stream_t incoming;
62+
poll_own_pollable_t incoming_pollable;
63+
udp_own_outgoing_datagram_stream_t outgoing;
64+
poll_own_pollable_t outgoing_pollable;
65+
} udp_socket_streams_t;
66+
67+
typedef struct {
68+
int dummy;
69+
} udp_socket_state_unbound_t;
70+
typedef struct {
71+
int dummy;
72+
} udp_socket_state_bound_nostreams_t;
73+
74+
typedef struct {
75+
udp_socket_streams_t streams; // Streams have no remote_address
76+
} udp_socket_state_bound_streaming_t;
77+
78+
typedef struct {
79+
udp_socket_streams_t streams; // Streams have a remote_address
80+
} udp_socket_state_connected_t;
81+
82+
// This is a tagged union. When adding/removing/renaming cases, be sure to keep the tag and union definitions in sync.
83+
// The "bound" state is split up into two distinct tags:
84+
// - "bound_nostreams": Bound, but no datagram streams set up (yet). That will be done the first time send or recv is called.
85+
// - "bound_streaming": Bound with active streams.
86+
typedef struct {
87+
enum {
88+
UDP_SOCKET_STATE_UNBOUND,
89+
UDP_SOCKET_STATE_BOUND_NOSTREAMS,
90+
UDP_SOCKET_STATE_BOUND_STREAMING,
91+
UDP_SOCKET_STATE_CONNECTED,
92+
} tag;
93+
union {
94+
udp_socket_state_unbound_t unbound;
95+
udp_socket_state_bound_nostreams_t bound_nostreams;
96+
udp_socket_state_bound_streaming_t bound_streaming;
97+
udp_socket_state_connected_t connected;
98+
};
99+
} udp_socket_state_t;
100+
101+
typedef struct {
102+
udp_own_udp_socket_t socket;
103+
poll_own_pollable_t socket_pollable;
104+
bool blocking;
105+
network_ip_address_family_t family;
106+
udp_socket_state_t state;
107+
} udp_socket_t;
108+
109+
// This is a tagged union. When adding/removing/renaming cases, be sure to keep the tag and union definitions in sync.
110+
typedef struct {
111+
enum {
112+
DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET,
113+
DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET,
114+
} tag;
115+
union {
116+
tcp_socket_t tcp_socket;
117+
udp_socket_t udp_socket;
118+
};
119+
} descriptor_table_entry_t;
120+
121+
bool descriptor_table_insert(descriptor_table_entry_t entry, int *fd);
122+
123+
bool descriptor_table_get_ref(int fd, descriptor_table_entry_t **entry);
124+
125+
bool descriptor_table_remove(int fd, descriptor_table_entry_t *entry);
126+
127+
#endif

0 commit comments

Comments
 (0)