OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdSchedulerPoll.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 #include "C4Include.h"
18 #include "platform/StdScheduler.h"
19 
20 #ifdef HAVE_POLL_H
21 #include <stdio.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #ifdef HAVE_IO_H
26 #include <io.h>
27 #endif
28 #ifdef HAVE_SHARE_H
29 #include <share.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <map>
35 
36 // Is this process currently signaled?
38 {
39  // Initialize file descriptor sets
40  std::vector<struct pollfd> fds;
41 
42  // Get file descriptors
43  GetFDs(fds);
44 
45  // Test
46  return poll(&fds[0], fds.size(), 0) > 0;
47 }
48 
49 namespace
50 {
51  void Fail(const char* msg)
52  {
53  Log(msg);
54  }
55 }
56 
57 #ifdef HAVE_SYS_EVENTFD_H
58 #include <sys/eventfd.h>
59 
61 {
62  fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
63  if (fds[0] == -1)
64  Fail("eventfd failed");
65 }
67 {
68  close(fds[0]);
69 }
71 {
72  uint64_t n = 1;
73  if (write(fds[0], &n, 8) == -1)
74  Fail("write failed");
75 }
77 {
78  uint64_t n;
79  return (read(fds[0], &n, 8) != -1);
80 }
81 #else
83 {
84  if (pipe(fds) == -1)
85  Fail("pipe failed");
86  fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
87  fcntl(fds[0], F_SETFD, FD_CLOEXEC);
88  fcntl(fds[1], F_SETFD, FD_CLOEXEC);
89 }
91 {
92  close(fds[0]);
93  close(fds[1]);
94 }
96 {
97  char c = 42;
98  if (write(fds[1], &c, 1) == -1)
99  Fail("write failed");
100 }
102 {
103  bool r = false;
104  while (1)
105  {
106  char c;
107  if (read(fds[0], &c, 1) <= 0)
108  break;
109  else
110  r = true;
111  }
112  return r;
113 }
114 #endif
115 void CStdNotifyProc::GetFDs(std::vector<struct pollfd> & checkfds)
116 {
117  pollfd pfd = { fds[0], POLLIN, 0 };
118  checkfds.push_back(pfd);
119 }
120 
121 bool StdScheduler::DoScheduleProcs(int iTimeout)
122 {
123  // Initialize file descriptor sets
124  std::vector<struct pollfd> fds;
125  std::map<StdSchedulerProc *, std::pair<unsigned int, unsigned int> > fds_for_proc;
126 
127  // Collect file descriptors
128  for (auto proc : procs)
129  {
130  unsigned int os = fds.size();
131  proc->GetFDs(fds);
132  if (os != fds.size())
133  fds_for_proc[proc] = std::pair<unsigned int, unsigned int>(os, fds.size());
134  }
135 
136  // Wait for something to happen
137  int cnt = poll(&fds[0], fds.size(), iTimeout);
138 
139  bool fSuccess = true;
140 
141  if (cnt >= 0)
142  {
143  bool any_executed = false;
144  auto tNow = C4TimeMilliseconds::Now();
145  // Which process?
146  for (size_t i = 0; i < procs.size(); i++)
147  {
148  auto proc = procs[i];
149  auto tProcTick = proc->GetNextTick(tNow);
150  if (tProcTick <= tNow)
151  {
152  struct pollfd * pfd = 0;
153  if (fds_for_proc.find(proc) != fds_for_proc.end())
154  pfd = &fds[fds_for_proc[proc].first];
155  if (!proc->Execute(0, pfd))
156  {
157  OnError(proc);
158  fSuccess = false;
159  }
160  any_executed = true;
161  continue;
162  }
163  // no fds?
164  if (fds_for_proc.find(proc) == fds_for_proc.end())
165  continue;
166  // Check intersection
167  unsigned int begin = fds_for_proc[proc].first;
168  unsigned int end = fds_for_proc[proc].second;
169  for (unsigned int j = begin; j < end; ++j)
170  {
171  if (fds[j].events & fds[j].revents)
172  {
173  if (any_executed && proc->IsLowPriority())
174  break;
175  if (!proc->Execute(0, &fds[begin]))
176  {
177  OnError(proc);
178  fSuccess = false;
179  }
180  any_executed = true;
181  // the list of procs might have been changed, but procs must be in both ppProcs and
182  // fds_for_proc to be executed, which prevents execution of any proc not polled this round
183  // or deleted. Some procs might be skipped or executed twice, but that should be save.
184  break;
185  }
186  }
187  }
188  }
189  else if (cnt < 0 && errno != EINTR)
190  {
191  printf("StdScheduler::%s: poll failed: %s\n",__func__,strerror(errno));
192  }
193  return fSuccess;
194 }
195 
196 #if defined(HAVE_SYS_TIMERFD_H)
197 #include <sys/timerfd.h>
199 {
200  fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
201  if (fd == -1)
202  Log("timerfd_create failed");
203  SetDelay(iDelay);
204 }
205 
206 CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
207 {
208  close(fd);
209 }
210 
211 void CStdMultimediaTimerProc::SetDelay(uint32_t inDelay)
212 {
213  struct itimerspec nv, ov;
214  nv.it_interval.tv_sec = inDelay / 1000;
215  nv.it_interval.tv_nsec = (inDelay % 1000) * 1000000;
216  nv.it_value = nv.it_interval;
217  timerfd_settime(fd, 0, &nv, &ov);
218 }
219 
220 void CStdMultimediaTimerProc::Set()
221 {
222  struct itimerspec nv, ov;
223  timerfd_gettime(fd, &nv);
224  nv.it_value.tv_sec = 0;
225  nv.it_value.tv_nsec = 1;
226  timerfd_settime(fd, 0, &nv, &ov);
227 }
228 
229 bool CStdMultimediaTimerProc::CheckAndReset()
230 {
231  uint64_t n;
232  return read(fd, &n, 8) != -1;
233 }
234 
235 void CStdMultimediaTimerProc::GetFDs(std::vector<struct pollfd> & checkfds)
236 {
237  pollfd pfd = { fd, POLLIN, 0 };
238  checkfds.push_back(pfd);
239 }
240 #endif // HAVE_SYS_TIMERFD_H
241 
242 #if !defined(USE_COCOA)
247 #endif
248 #endif // HAVE_POLL_H
virtual void GetFDs(std::vector< struct pollfd > &checkfds)
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
void Removing(StdSchedulerProc *pProc)
virtual void OnError(StdSchedulerProc *)
Definition: StdScheduler.h:272
StdSchedulerProc * proc
#define CStdMultimediaTimerProc
Definition: StdScheduler.h:220
bool CheckAndReset()
virtual void GetFDs(std::vector< struct pollfd > &)
Definition: StdScheduler.h:76
void StartOnCurrentThread()
bool Log(const char *szMessage)
Definition: C4Log.cpp:195
void Changed(StdSchedulerProc *pProc)
virtual bool DoScheduleProcs(int iTimeout)
void Added(StdSchedulerProc *pProc)
static C4TimeMilliseconds Now()