Coverage Report

Created: 2025-11-24 06:34

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