...
1 package wasi_snapshot_preview1
2
3 import (
4 "context"
5 "time"
6
7 "github.com/tetratelabs/wazero/api"
8 "github.com/tetratelabs/wazero/experimental/sys"
9 "github.com/tetratelabs/wazero/internal/fsapi"
10 internalsys "github.com/tetratelabs/wazero/internal/sys"
11 "github.com/tetratelabs/wazero/internal/wasip1"
12 "github.com/tetratelabs/wazero/internal/wasm"
13 )
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 var pollOneoff = newHostFunc(
41 wasip1.PollOneoffName, pollOneoffFn,
42 []api.ValueType{i32, i32, i32, i32},
43 "in", "out", "nsubscriptions", "result.nevents",
44 )
45
46 type event struct {
47 eventType byte
48 userData []byte
49 errno wasip1.Errno
50 }
51
52 func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
53 in := uint32(params[0])
54 out := uint32(params[1])
55 nsubscriptions := uint32(params[2])
56 resultNevents := uint32(params[3])
57
58 if nsubscriptions == 0 {
59 return sys.EINVAL
60 }
61
62 mem := mod.Memory()
63
64
65 inBuf, ok := mem.Read(in, nsubscriptions*48)
66 if !ok {
67 return sys.EFAULT
68 }
69 outBuf, ok := mem.Read(out, nsubscriptions*32)
70
71 for i := range outBuf {
72 outBuf[i] = 0
73 }
74
75 if !ok {
76 return sys.EFAULT
77 }
78
79
80
81 if !mod.Memory().WriteUint32Le(resultNevents, nsubscriptions) {
82 return sys.EFAULT
83 }
84
85
86
87
88 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
89
90 var blockingStdinSubs []*event
91
92 var timeout time.Duration = 1<<63 - 1
93
94
95
96 nevents := uint32(0)
97
98
99
100 for i := uint32(0); i < nsubscriptions; i++ {
101 inOffset := i * 48
102 outOffset := nevents * 32
103
104 eventType := inBuf[inOffset+8]
105
106 argBuf := inBuf[inOffset+8+8:]
107 userData := inBuf[inOffset : inOffset+8]
108
109 evt := &event{
110 eventType: eventType,
111 userData: userData,
112 errno: wasip1.ErrnoSuccess,
113 }
114
115 switch eventType {
116 case wasip1.EventTypeClock:
117 newTimeout, err := processClockEvent(argBuf)
118 if err != 0 {
119 return err
120 }
121
122 if newTimeout < timeout {
123 timeout = newTimeout
124 }
125
126 writeEvent(outBuf[outOffset:], evt)
127 nevents++
128 case wasip1.EventTypeFdRead:
129 fd := int32(le.Uint32(argBuf))
130 if fd < 0 {
131 return sys.EBADF
132 }
133 if file, ok := fsc.LookupFile(fd); !ok {
134 evt.errno = wasip1.ErrnoBadf
135 writeEvent(outBuf[outOffset:], evt)
136 nevents++
137 } else if fd != internalsys.FdStdin && file.File.IsNonblock() {
138 writeEvent(outBuf[outOffset:], evt)
139 nevents++
140 } else {
141
142
143 blockingStdinSubs = append(blockingStdinSubs, evt)
144 }
145 case wasip1.EventTypeFdWrite:
146 fd := int32(le.Uint32(argBuf))
147 if fd < 0 {
148 return sys.EBADF
149 }
150 if _, ok := fsc.LookupFile(fd); ok {
151 evt.errno = wasip1.ErrnoNotsup
152 } else {
153 evt.errno = wasip1.ErrnoBadf
154 }
155 nevents++
156 writeEvent(outBuf[outOffset:], evt)
157 default:
158 return sys.EINVAL
159 }
160 }
161
162 sysCtx := mod.(*wasm.ModuleInstance).Sys
163 if nevents == nsubscriptions {
164
165
166
167
168 if timeout > 0 {
169 sysCtx.Nanosleep(int64(timeout))
170 }
171 return 0
172 }
173
174
175 stdin, ok := fsc.LookupFile(internalsys.FdStdin)
176 if !ok {
177 return sys.EBADF
178 }
179
180
181 if stdinReady, errno := stdin.File.Poll(fsapi.POLLIN, int32(timeout.Milliseconds())); errno != 0 {
182 return errno
183 } else if stdinReady {
184
185 for i := range blockingStdinSubs {
186 evt := blockingStdinSubs[i]
187 evt.errno = 0
188 writeEvent(outBuf[nevents*32:], evt)
189 nevents++
190 }
191 }
192
193 if nevents != nsubscriptions {
194 if !mod.Memory().WriteUint32Le(resultNevents, nevents) {
195 return sys.EFAULT
196 }
197 }
198
199 return 0
200 }
201
202
203
204 func processClockEvent(inBuf []byte) (time.Duration, sys.Errno) {
205 _ = le.Uint32(inBuf[0:8])
206 timeout := le.Uint64(inBuf[8:16])
207 _ = le.Uint64(inBuf[16:24])
208 flags := le.Uint16(inBuf[24:32])
209
210 var err sys.Errno
211
212 switch flags {
213 case 0:
214 case 1:
215 err = sys.ENOTSUP
216 default:
217 err = sys.EINVAL
218 }
219
220 if err != 0 {
221 return 0, err
222 } else {
223
224
225
226
227 return time.Duration(timeout), 0
228 }
229 }
230
231
232
233 func writeEvent(outBuf []byte, evt *event) {
234 copy(outBuf, evt.userData)
235 outBuf[8] = byte(evt.errno)
236 outBuf[9] = 0
237 le.PutUint32(outBuf[10:], uint32(evt.eventType))
238
239 }
240
View as plain text