FreeRDP
Loading...
Searching...
No Matches
pollset.c
1#ifndef _WIN32
2#include <errno.h>
3
4#include "pollset.h"
5#include <winpr/handle.h>
6#include <winpr/sysinfo.h>
7#include <winpr/assert.h>
8#include "../log.h"
9
10#define TAG WINPR_TAG("sync.pollset")
11
12#if defined(__EMSCRIPTEN__)
13/* in pollset_emscripten.js: returns once the browser's event loop has run the tasks that were
14 * waiting, without the 4 ms that emscripten_sleep(0) (setTimeout) costs there */
15extern void winpr_pollset_js_yield(void);
16#endif
17
18#ifdef WINPR_HAVE_POLL_H
19static INT16 handle_mode_to_pollevent(ULONG mode)
20{
21 INT16 event = 0;
22
23 if (mode & WINPR_FD_READ)
24 event |= POLLIN;
25
26 if (mode & WINPR_FD_WRITE)
27 event |= POLLOUT;
28
29 return event;
30}
31#endif
32
33BOOL pollset_init(WINPR_POLL_SET* set, size_t nhandles)
34{
35 WINPR_ASSERT(set);
36#ifdef WINPR_HAVE_POLL_H
37 if (nhandles > MAXIMUM_WAIT_OBJECTS)
38 {
39 set->isStatic = FALSE;
40 set->pollset = calloc(nhandles, sizeof(*set->pollset));
41 if (!set->pollset)
42 return FALSE;
43 }
44 else
45 {
46 set->pollset = set->staticSet;
47 set->isStatic = TRUE;
48 }
49#else
50 set->fdIndex = calloc(nhandles, sizeof(*set->fdIndex));
51 if (!set->fdIndex)
52 return FALSE;
53
54 FD_ZERO(&set->rset_base);
55 FD_ZERO(&set->rset);
56 FD_ZERO(&set->wset_base);
57 FD_ZERO(&set->wset);
58 set->maxFd = 0;
59 set->nread = set->nwrite = 0;
60#endif
61
62 set->size = nhandles;
63 set->fillIndex = 0;
64 return TRUE;
65}
66
67void pollset_uninit(WINPR_POLL_SET* set)
68{
69 WINPR_ASSERT(set);
70#ifdef WINPR_HAVE_POLL_H
71 if (!set->isStatic)
72 free(set->pollset);
73#else
74 free(set->fdIndex);
75#endif
76}
77
78void pollset_reset(WINPR_POLL_SET* set)
79{
80 WINPR_ASSERT(set);
81#ifndef WINPR_HAVE_POLL_H
82 FD_ZERO(&set->rset_base);
83 FD_ZERO(&set->wset_base);
84 set->maxFd = 0;
85 set->nread = set->nwrite = 0;
86#endif
87 set->fillIndex = 0;
88}
89
90BOOL pollset_add(WINPR_POLL_SET* set, int fd, ULONG mode)
91{
92 WINPR_ASSERT(set);
93#ifdef WINPR_HAVE_POLL_H
94 struct pollfd* item = nullptr;
95 if (set->fillIndex == set->size)
96 return FALSE;
97
98 item = &set->pollset[set->fillIndex];
99 item->fd = fd;
100 item->revents = 0;
101 item->events = handle_mode_to_pollevent(mode);
102#else
103 FdIndex* fdIndex = &set->fdIndex[set->fillIndex];
104 if (mode & WINPR_FD_READ)
105 {
106 FD_SET(fd, &set->rset_base);
107 set->nread++;
108 }
109
110 if (mode & WINPR_FD_WRITE)
111 {
112 FD_SET(fd, &set->wset_base);
113 set->nwrite++;
114 }
115
116 if (fd > set->maxFd)
117 set->maxFd = fd;
118
119 fdIndex->fd = fd;
120 fdIndex->mode = mode;
121#endif
122 set->fillIndex++;
123 return TRUE;
124}
125
126int pollset_poll(WINPR_POLL_SET* set, DWORD dwMilliseconds)
127{
128 WINPR_ASSERT(set);
129 int ret = 0;
130 UINT64 dueTime = 0;
131 UINT64 now = 0;
132
133 now = GetTickCount64();
134 if (dwMilliseconds == INFINITE)
135 dueTime = 0xFFFFFFFFFFFFFFFF;
136 else
137 dueTime = now + dwMilliseconds;
138
139#ifdef WINPR_HAVE_POLL_H
140 int timeout = 0;
141
142 do
143 {
144 if (dwMilliseconds == INFINITE)
145 timeout = -1;
146 else
147 timeout = (int)(dueTime - now);
148
149 ret = poll(set->pollset, WINPR_ASSERTING_INT_CAST(nfds_t, set->fillIndex), timeout);
150 if (ret >= 0)
151 {
152#if defined(__EMSCRIPTEN__)
153 /* If we have tried 10 times unsuccessfully we will yield in emscripten so pending event
154 * handlers might be run */
155 if (ret == 0)
156 {
157 if (++set->yieldCounter > 10)
158 {
159 winpr_pollset_js_yield();
160 set->yieldCounter = 0;
161 }
162 }
163 else
164 set->yieldCounter = 0;
165#endif
166 return ret;
167 }
168
169 if (errno != EINTR)
170 return -1;
171
172 now = GetTickCount64();
173 } while (now < dueTime);
174
175#else
176 do
177 {
178 struct timeval staticTimeout;
179 struct timeval* timeout;
180
181 fd_set* rset = nullptr;
182 fd_set* wset = nullptr;
183
184 if (dwMilliseconds == INFINITE)
185 {
186 timeout = nullptr;
187 }
188 else
189 {
190 long waitTime = (long)(dueTime - now);
191
192 timeout = &staticTimeout;
193 timeout->tv_sec = waitTime / 1000;
194 timeout->tv_usec = (waitTime % 1000) * 1000;
195 }
196
197 if (set->nread)
198 {
199 rset = &set->rset;
200 memcpy(rset, &set->rset_base, sizeof(*rset));
201 }
202
203 if (set->nwrite)
204 {
205 wset = &set->wset;
206 memcpy(wset, &set->wset_base, sizeof(*wset));
207 }
208
209 ret = select(set->maxFd + 1, rset, wset, nullptr, timeout);
210 if (ret >= 0)
211 return ret;
212
213 if (errno != EINTR)
214 return -1;
215
216 now = GetTickCount64();
217
218 } while (now < dueTime);
219
220 FD_ZERO(&set->rset);
221 FD_ZERO(&set->wset);
222#endif
223
224 return 0; /* timeout */
225}
226
227BOOL pollset_isSignaled(WINPR_POLL_SET* set, size_t idx)
228{
229 WINPR_ASSERT(set);
230
231 if (idx > set->fillIndex)
232 {
233 WLog_ERR(TAG, "index=%" PRIuz " out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
234 return FALSE;
235 }
236
237#ifdef WINPR_HAVE_POLL_H
238 return !!(set->pollset[idx].revents & set->pollset[idx].events);
239#else
240 FdIndex* fdIndex = &set->fdIndex[idx];
241 if (fdIndex->fd < 0)
242 return FALSE;
243
244 if ((fdIndex->mode & WINPR_FD_READ) && FD_ISSET(fdIndex->fd, &set->rset))
245 return TRUE;
246
247 if ((fdIndex->mode & WINPR_FD_WRITE) && FD_ISSET(fdIndex->fd, &set->wset))
248 return TRUE;
249
250 return FALSE;
251#endif
252}
253
254BOOL pollset_isReadSignaled(WINPR_POLL_SET* set, size_t idx)
255{
256 WINPR_ASSERT(set);
257
258 if (idx > set->fillIndex)
259 {
260 WLog_ERR(TAG, "index=%" PRIuz " out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
261 return FALSE;
262 }
263
264#ifdef WINPR_HAVE_POLL_H
265 return !!(set->pollset[idx].revents & POLLIN);
266#else
267 FdIndex* fdIndex = &set->fdIndex[idx];
268 if (fdIndex->fd < 0)
269 return FALSE;
270
271 return FD_ISSET(fdIndex->fd, &set->rset);
272#endif
273}
274
275BOOL pollset_isWriteSignaled(WINPR_POLL_SET* set, size_t idx)
276{
277 WINPR_ASSERT(set);
278
279 if (idx > set->fillIndex)
280 {
281 WLog_ERR(TAG, "index=%" PRIuz " out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
282 return FALSE;
283 }
284
285#ifdef WINPR_HAVE_POLL_H
286 return !!(set->pollset[idx].revents & POLLOUT);
287#else
288 FdIndex* fdIndex = &set->fdIndex[idx];
289 if (fdIndex->fd < 0)
290 return FALSE;
291
292 return FD_ISSET(fdIndex->fd, &set->wset);
293#endif
294}
295
296#endif