The Pedigree Project  0.1
select-syscalls.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "select-syscalls.h"
21 #include "net-syscalls.h"
22 #include "pedigree/kernel/Subsystem.h"
23 #include "pedigree/kernel/compiler.h"
24 #include "pedigree/kernel/processor/types.h"
25 #include "pedigree/kernel/syscallError.h"
26 #include "poll-syscalls.h"
27 #include <PosixSubsystem.h>
28 
29 int posix_select(
30  int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds,
31  timeval *timeout)
32 {
33  POLL_NOTICE(
34  "select(" << nfds << ", " << readfds << ", " << writefds << ", "
35  << errorfds << ", " << timeout << ")");
36  bool bValidAddresses = true;
37  if (readfds)
38  bValidAddresses =
39  bValidAddresses && PosixSubsystem::checkAddress(
40  reinterpret_cast<uintptr_t>(readfds),
41  sizeof(fd_set), PosixSubsystem::SafeWrite);
42  if (writefds)
43  bValidAddresses =
44  bValidAddresses && PosixSubsystem::checkAddress(
45  reinterpret_cast<uintptr_t>(writefds),
46  sizeof(fd_set), PosixSubsystem::SafeWrite);
47  if (errorfds)
48  bValidAddresses =
49  bValidAddresses && PosixSubsystem::checkAddress(
50  reinterpret_cast<uintptr_t>(errorfds),
51  sizeof(fd_set), PosixSubsystem::SafeWrite);
52  if (timeout)
53  bValidAddresses =
54  bValidAddresses && PosixSubsystem::checkAddress(
55  reinterpret_cast<uintptr_t>(timeout),
56  sizeof(timeval), PosixSubsystem::SafeWrite);
57 
58  if (!bValidAddresses)
59  {
60  SYSCALL_ERROR(InvalidArgument);
61  return -1;
62  }
63 
64  // Count the actual number of fds we have.
65  size_t trueFdCount = 0;
66  for (int i = 0; i < nfds; ++i)
67  {
68  if ((readfds && FD_ISSET(i, readfds)) ||
69  (writefds && FD_ISSET(i, writefds)) ||
70  (errorfds && FD_ISSET(i, errorfds)))
71  {
72  POLL_NOTICE("fd " << i << " is acceptable");
73  ++trueFdCount;
74  }
75  }
76 
77  // Set up pollfds
78  struct pollfd *fds = new struct pollfd[trueFdCount];
79  size_t j = 0;
80  for (int i = 0; i < nfds; ++i)
81  {
82  bool checkRead = readfds && FD_ISSET(i, readfds);
83  bool checkWrite = writefds && FD_ISSET(i, writefds);
84  bool checkError = errorfds && FD_ISSET(i, errorfds);
85 
86  if (!(checkRead || checkWrite || checkError))
87  {
88  continue;
89  }
90 
91  POLL_NOTICE("registering fd " << i << " in slot " << j);
92 
93  fds[j].fd = i;
94  fds[j].events = 0;
95  if (checkRead)
96  fds[j].events |= POLLIN;
97  if (checkWrite)
98  fds[j].events |= POLLOUT;
99  if (checkError)
100  fds[j].events |= POLLERR;
101  fds[j].revents = 0;
102 
103  ++j;
104  }
105 
106  // Default to infinite wait, but handle immediate wait or a specific timeout
107  // too.
108  int timeoutMs = -1;
109  if (timeout)
110  {
111  timeoutMs = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
112  }
113 
114  // Go!
115  POLL_NOTICE(
116  " -> redirecting select() to poll() with " << trueFdCount
117  << " actual fds");
118  int r = posix_poll_safe(fds, trueFdCount, timeoutMs);
119 
120  // Fill fd_sets as needed.
121  j = 0;
122  for (int i = 0; i < nfds; ++i)
123  {
125  bool checkRead = readfds && FD_ISSET(i, readfds);
126  bool checkWrite = writefds && FD_ISSET(i, writefds);
127  bool checkError = errorfds && FD_ISSET(i, errorfds);
128 
129  if (!(checkRead || checkWrite || checkError))
130  {
131  continue;
132  }
133 
134  if (checkRead)
135  {
136  if (fds[j].revents & POLLIN)
137  {
138  FD_SET(i, readfds);
139  }
140  else
141  {
142  FD_CLR(i, readfds);
143  }
144  }
145 
146  if (checkWrite)
147  {
148  if (fds[j].revents & POLLOUT)
149  {
150  FD_SET(i, writefds);
151  }
152  else
153  {
154  FD_CLR(i, writefds);
155  }
156  }
157 
158  if (checkError)
159  {
160  if (fds[j].revents & POLLERR)
161  {
162  FD_SET(i, errorfds);
163  }
164  else
165  {
166  FD_CLR(i, errorfds);
167  }
168  }
169 
170  ++j;
171  }
172 
173  delete[] fds;
174 
175  POLL_NOTICE(" -> select via poll returns " << r);
176  return r;
177 }
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)