The Pedigree Project  0.1
poll-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 "poll-syscalls.h"
21 #include "net-syscalls.h"
22 #include "pedigree/kernel/compiler.h"
23 #include "pedigree/kernel/utilities/assert.h"
24 
25 #include "modules/system/vfs/Directory.h"
26 #include "modules/system/vfs/File.h"
27 #include "modules/system/vfs/LockedFile.h"
29 #include "modules/system/vfs/Symlink.h"
30 #include "modules/system/vfs/VFS.h"
31 #include "pedigree/kernel/process/Process.h"
32 #include "pedigree/kernel/processor/MemoryRegion.h"
33 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
34 #include "pedigree/kernel/processor/Processor.h"
35 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
36 #include "pedigree/kernel/processor/types.h"
37 #include "pedigree/kernel/syscallError.h"
38 #include "pedigree/kernel/utilities/Tree.h"
39 #include "pedigree/kernel/utilities/utility.h"
40 
41 #include "modules/subsys/posix/PollEvent.h"
42 #include "pedigree/kernel/Subsystem.h"
43 #include "modules/subsys/posix/FileDescriptor.h"
44 #include "modules/subsys/posix/PosixSubsystem.h"
45 
46 extern void pollEventHandler(uint8_t *pBuffer);
47 
48 enum TimeoutType
49 {
50  ReturnImmediately,
51  SpecificTimeout,
52  InfiniteTimeout
53 };
54 
59 int posix_poll(struct pollfd *fds, unsigned int nfds, int timeout)
60 {
61  POLL_NOTICE("poll(" << Dec << nfds << ", " << timeout << Hex << ")");
63  reinterpret_cast<uintptr_t>(fds), nfds * sizeof(struct pollfd),
64  PosixSubsystem::SafeWrite))
65  {
66  POLL_NOTICE(" -> invalid address");
67  SYSCALL_ERROR(InvalidArgument);
68  return -1;
69  }
70 
71  // Now checked, and it is safe to continue.
72  return posix_poll_safe(fds, nfds, timeout);
73 }
74 
75 int posix_poll_safe(struct pollfd *fds, unsigned int nfds, int timeout)
76 {
77  POLL_NOTICE("poll_safe(" << Dec << nfds << ", " << timeout << Hex << ")");
78 
79  // Investigate the timeout parameter.
80  TimeoutType timeoutType;
81  size_t timeoutSecs = timeout / 1000;
82  size_t timeoutUSecs = (timeout % 1000) * 1000;
83  if (timeout < 0)
84  {
85  timeoutType = InfiniteTimeout;
86 
87  // Fix timeout to be truly infinite
88  // (negative timeout may divide incorrectly)
89  timeoutSecs = 0;
90  timeoutUSecs = 0;
91  }
92  else if (timeout == 0)
93  {
94  timeoutType = ReturnImmediately;
95  }
96  else
97  {
98  timeoutType = SpecificTimeout;
99  }
100 
101 #ifndef THREADS
102  timeoutType = ReturnImmediately;
103 #endif
104 
105 #ifdef THREADS
106  // Grab the subsystem for this process
107  Thread *pThread = Processor::information().getCurrentThread();
108  Process *pProcess = pThread->getParent();
109  PosixSubsystem *pSubsystem =
110  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
111  if (!pSubsystem)
112  {
113  ERROR("No subsystem for this process!");
114  return -1;
115  }
116 #else
117  Thread *pThread = nullptr;
118 #endif
119 
120  List<PollEvent *> events;
121 
122  bool bError = false;
123  bool bWillReturnImmediately = (timeoutType == ReturnImmediately);
124 
125 #ifdef THREADS
126  // Can be interrupted while waiting for sem - EINTR.
127  Semaphore sem(0, true);
128  Spinlock reentrancyLock;
129  Semaphore *pSem = &sem;
130 #else
131  Semaphore *pSem = nullptr;
132 #endif
133 
134  for (unsigned int i = 0; i < nfds; i++)
135  {
136  // Grab the pollfd structure.
137  struct pollfd *me = &fds[i];
138  me->revents = 0;
139  if (me->fd < 0)
140  {
141  continue;
142  }
143 
144  // valid fd?
145  FileDescriptor *pFd = getDescriptor(me->fd);
146  if (!pFd)
147  {
148  // Error - no such file descriptor.
149  POLL_NOTICE(
150  "poll: no such file descriptor (" << Dec << me->fd << ")");
151  me->revents |= POLLNVAL;
152  bError = true;
153  continue;
154  }
155 
156  bool checkWrite = false;
157 
158  // Check POLLIN, POLLOUT (almost exactly the same code for both).
160  for (size_t j = 0; j < 2; ++j)
161  {
162  short event = POLLIN;
163  if (checkWrite)
164  {
165  event = POLLOUT;
166  }
167 
168  if (me->events & event)
169  {
170  if (pFd->file)
171  {
172  // Has the file already got data in it?
174  if (pFd->file->select(checkWrite, 0))
175  {
176  me->revents |= event;
177  bWillReturnImmediately = true;
178  }
179 #ifdef THREADS
180  else if (!bWillReturnImmediately)
181  {
182  // Need to set up a PollEvent.
183  PollEvent *pEvent =
184  new PollEvent(&sem, me, event, pFd->file);
185  pFd->file->monitor(pThread, pEvent);
186 
187  reentrancyLock.acquire();
188 
189  events.pushBack(pEvent);
190 
191  // Quickly check again now we've added the monitoring
192  // event, to avoid a race condition where we could miss
193  // the event.
194  //
199  if (pFd->file->select(checkWrite, 0))
200  {
201  me->revents |= event;
202  bWillReturnImmediately = true;
203  }
204 
205  reentrancyLock.release();
206  }
207 #endif
208  }
209  else if (pFd->networkImpl)
210  {
211  if (pFd->networkImpl->canPoll())
212  {
213  bool checkingWrite = checkWrite;
214  bool checkingRead = !checkWrite;
215  bool checkingError = false;
216 
217  bool extraCheckingWrite = checkingWrite;
218  bool extraCheckingRead = checkingRead;
219  bool extraCheckingError = checkingError;
220 
221  bool pollResult = pFd->networkImpl->poll(
222  checkingRead, checkingWrite, checkingError, pSem);
223  if (pollResult)
224  {
225  bWillReturnImmediately = pollResult;
226  }
227 
228  // need to do one more check, just in case between
229  // polling and setting up the waiter semaphore we
230  // managed to get a change which would otherwise not
231  // wake the semaphore
232 #ifdef THREADS
233  reentrancyLock.acquire();
234  pollResult = pFd->networkImpl->poll(
235  extraCheckingRead, extraCheckingWrite,
236  extraCheckingError, nullptr);
237  if (pollResult)
238  {
239  bWillReturnImmediately = pollResult;
240  }
241  reentrancyLock.release();
242 #else
243  extraCheckingWrite = false;
244  extraCheckingRead = false;
245  extraCheckingError = false;
246 #endif
247 
248  if (bWillReturnImmediately)
249  {
250  if (checkingWrite || extraCheckingWrite)
251  {
252  me->revents |= POLLOUT;
253  }
254 
255  if (checkingRead || extraCheckingRead)
256  {
257  me->revents |= POLLIN;
258  }
259  }
260  }
261  }
262  }
263 
264  checkWrite = true;
265  }
266 
267  if (me->events & POLLERR)
268  {
269  POLL_NOTICE(" -> POLLERR not yet supported");
270  }
271  }
272 
273 #ifdef THREADS
274  // Grunt work is done, now time to cleanup.
275  while (!bWillReturnImmediately && !bError)
276  {
277  POLL_NOTICE(" -> no fds ready yet, poll will block");
278 
279  // We got here because there is a specific or infinite timeout and
280  // no FD was ready immediately.
281  //
282  // We wait on the semaphore 'sem': Its address has been given to all
283  // the events and will be raised whenever an FD has action.
285  sem.acquireWithResult(1, timeoutSecs, timeoutUSecs);
286 
287  // Did we actually get the semaphore or did we timeout?
288  if (result.hasValue())
289  {
290  // If we didn't actually get the Semaphore but there's not any
291  // other error state, just go around for another go.
292  if (!result.value())
293  {
294  continue;
295  }
296 
297  // We were signalled, so one more FD ready.
298  // While the semaphore is nonzero, more FDs are ready.
299  while (sem.tryAcquire())
300  ;
301 
302  // Good to go for checking why we were woken (for sockets).
303  // We only break out of the main poll() loop if a file was polled,
304  // or a socket actually emits an expected event. This works better
305  // as for sockets in particular, we'll get woken up for ALL events,
306  // not just the ones we care about polling for.
307  bool ok = false;
308  for (size_t i = 0; i < nfds; ++i)
309  {
310  struct pollfd *me = &fds[i];
311  FileDescriptor *pFd = getDescriptor(me->fd);
312  if (!pFd)
313  {
314  continue;
315  }
316 
317  if (pFd->networkImpl && pFd->networkImpl->canPoll())
318  {
319  bool checkingWrite = me->events & POLLOUT;
320  bool checkingRead = me->events & POLLIN;
321  bool checkingError = false;
322 
323  pFd->networkImpl->poll(
324  checkingRead, checkingWrite, checkingError, nullptr);
325 
326  if (checkingWrite && (me->events & POLLOUT))
327  {
328  me->revents |= POLLOUT;
329  ok = true;
330  }
331 
332  if (checkingRead && (me->events & POLLIN))
333  {
334  me->revents |= POLLIN;
335  ok = true;
336  }
337  }
338  else if (pFd->file)
339  {
340  ok = true;
341  }
342  }
343 
344  if (ok)
345  {
346  break;
347  }
348  }
349  else
350  {
351  if (result.error() == Semaphore::TimedOut)
352  {
353  // timed out, not an error
354  POLL_NOTICE(" -> poll interrupted by timeout");
355  }
356  else
357  {
358  // generic interrupt
359  POLL_NOTICE(" -> poll interrupted by external event");
360  SYSCALL_ERROR(Interrupted);
361  bError = true;
362  }
363 
364  break;
365  }
366  }
367 #endif
368 
369  // Only do cleanup and lock acquire/release if we set events up.
370  if (events.count())
371  {
372  // Block any more events being sent to us so we can safely clean up.
373 #ifdef THREADS
374  reentrancyLock.acquire();
375  pThread->inhibitEvent(EventNumbers::PollEvent, true);
376  reentrancyLock.release();
377 #endif
378 
379  for (auto pEvent : events)
380  {
381  pEvent->getFile()->cullMonitorTargets(pThread);
382  }
383 
384  // Ensure there are no events still pending for this thread.
385 #ifdef THREADS
386  pThread->cullEvent(EventNumbers::PollEvent);
387 #endif
388 
389  for (auto pEvent : events)
390  {
391  delete pEvent;
392  }
393 
394  // Cleanup is complete, stop inhibiting events now.
395 #ifdef THREADS
396  pThread->inhibitEvent(EventNumbers::PollEvent, false);
397 #endif
398  }
399 
400  // Prepare return value (number of fds with events).
401  size_t nRet = 0;
402  for (size_t i = 0; i < nfds; ++i)
403  {
404  POLL_NOTICE(
405  " -> pollfd[" << i << "]: fd=" << fds[i].fd
406  << ", events=" << fds[i].events
407  << ", revents=" << fds[i].revents);
408 
409  if (fds[i].revents != 0)
410  {
411  ++nRet;
412  }
413 
414  // Clean up socket Semaphores that we registered, if any.
415  FileDescriptor *pFd = getDescriptor(fds[i].fd);
416  if (!pFd)
417  {
418  continue;
419  }
420 
421  if (pFd->networkImpl && pFd->networkImpl->canPoll())
422  {
423  pFd->networkImpl->unPoll(pSem);
424  }
425  }
426 
427  POLL_NOTICE(" -> " << Dec << ((bError) ? -1 : (int) nRet) << Hex);
428  POLL_NOTICE(" -> nRet is " << nRet << ", error is " << bError);
429 
430  return (bError) ? -1 : nRet;
431 }
void cullEvent(Event *pEvent)
Definition: Thread.cc:580
void release()
Definition: Spinlock.cc:273
void pushBack(const T &value)
Definition: List.h:232
void inhibitEvent(size_t eventNumber, bool bInhibit)
Definition: Thread.cc:571
virtual int select(bool bWriting=false, int timeout=0)
Definition: File.cc:534
void monitor(Thread *pThread, Event *pEvent)
Definition: File.cc:683
SharedPointer< class NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it&#39;s a socket).
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
Definition: Result.h:36
static ProcessorInformation & information()
Definition: Processor.cc:45
File * file
Our open file pointer.
void cullMonitorTargets(Thread *pThread)
Definition: File.cc:691
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
Definition: List.h:64
Memory-mapped file interface.
Definition: Log.h:136
Process * getParent() const
Definition: Thread.h:181
Definition: Thread.h:54
#define ERROR(text)
Definition: Log.h:82
Definition: Log.h:138
size_t count() const
Definition: List.h:227