OpenClonk
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 #ifdef HAVE_IO_H
22 #include <io.h>
23 #endif
24 #ifdef HAVE_SHARE_H
25 #include <share.h>
26 #endif
27 
28 // Is this process currently signaled?
30 {
31  // Initialize file descriptor sets
32  std::vector<struct pollfd> fds;
33 
34  // Get file descriptors
35  GetFDs(fds);
36 
37  // Test
38  return poll(&fds[0], fds.size(), 0) > 0;
39 }
40 
41 namespace
42 {
43  void Fail(const char* msg)
44  {
45  Log(msg);
46  }
47 }
48 
49 #ifdef HAVE_SYS_EVENTFD_H
50 #include <sys/eventfd.h>
51 
53 {
54  fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
55  if (fds[0] == -1)
56  Fail("eventfd failed");
57 }
59 {
60  close(fds[0]);
61 }
63 {
64  uint64_t n = 1;
65  if (write(fds[0], &n, 8) == -1)
66  Fail("write failed");
67 }
69 {
70  uint64_t n;
71  return (read(fds[0], &n, 8) != -1);
72 }
73 #else
75 {
76  if (pipe(fds) == -1)
77  Fail("pipe failed");
78  fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
79  fcntl(fds[0], F_SETFD, FD_CLOEXEC);
80  fcntl(fds[1], F_SETFD, FD_CLOEXEC);
81 }
83 {
84  close(fds[0]);
85  close(fds[1]);
86 }
88 {
89  char c = 42;
90  if (write(fds[1], &c, 1) == -1)
91  Fail("write failed");
92 }
94 {
95  bool r = false;
96  while (1)
97  {
98  char c;
99  if (read(fds[0], &c, 1) <= 0)
100  break;
101  else
102  r = true;
103  }
104  return r;
105 }
106 #endif
107 void CStdNotifyProc::GetFDs(std::vector<struct pollfd> & checkfds)
108 {
109  pollfd pfd = { fds[0], POLLIN, 0 };
110  checkfds.push_back(pfd);
111 }
112 
113 bool StdScheduler::DoScheduleProcs(int iTimeout)
114 {
115  // Initialize file descriptor sets
116  std::vector<struct pollfd> fds;
117  std::map<StdSchedulerProc *, std::pair<unsigned int, unsigned int> > fds_for_proc;
118 
119  // Collect file descriptors
120  for (auto proc : procs)
121  {
122  unsigned int os = fds.size();
123  proc->GetFDs(fds);
124  if (os != fds.size())
125  fds_for_proc[proc] = std::pair<unsigned int, unsigned int>(os, fds.size());
126  }
127 
128  // Wait for something to happen
129  int cnt = poll(&fds[0], fds.size(), iTimeout);
130 
131  bool fSuccess = true;
132 
133  if (cnt >= 0)
134  {
135  bool any_executed = false;
136  auto tNow = C4TimeMilliseconds::Now();
137  // Which process?
138  for (size_t i = 0; i < procs.size(); i++)
139  {
140  auto proc = procs[i];
141  auto tProcTick = proc->GetNextTick(tNow);
142  if (tProcTick <= tNow)
143  {
144  struct pollfd * pfd = nullptr;
145  if (fds_for_proc.find(proc) != fds_for_proc.end())
146  pfd = &fds[fds_for_proc[proc].first];
147  if (!proc->Execute(0, pfd))
148  {
149  OnError(proc);
150  fSuccess = false;
151  }
152  any_executed = true;
153  continue;
154  }
155  // no fds?
156  if (fds_for_proc.find(proc) == fds_for_proc.end())
157  continue;
158  // Check intersection
159  unsigned int begin = fds_for_proc[proc].first;
160  unsigned int end = fds_for_proc[proc].second;
161  for (unsigned int j = begin; j < end; ++j)
162  {
163  if (fds[j].events & fds[j].revents)
164  {
165  if (any_executed && proc->IsLowPriority())
166  break;
167  if (!proc->Execute(0, &fds[begin]))
168  {
169  OnError(proc);
170  fSuccess = false;
171  }
172  any_executed = true;
173  // the list of procs might have been changed, but procs must be in both ppProcs and
174  // fds_for_proc to be executed, which prevents execution of any proc not polled this round
175  // or deleted. Some procs might be skipped or executed twice, but that should be save.
176  break;
177  }
178  }
179  }
180  }
181  else if (cnt < 0 && errno != EINTR)
182  {
183  printf("StdScheduler::%s: poll failed: %s\n",__func__,strerror(errno));
184  }
185  return fSuccess;
186 }
187 
188 #if defined(HAVE_SYS_TIMERFD_H)
189 #include <sys/timerfd.h>
191 {
192  fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
193  if (fd == -1)
194  Log("timerfd_create failed");
195  SetDelay(iDelay);
196 }
197 
198 CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
199 {
200  close(fd);
201 }
202 
203 void CStdMultimediaTimerProc::SetDelay(uint32_t inDelay)
204 {
205  struct itimerspec nv, ov;
206  nv.it_interval.tv_sec = inDelay / 1000;
207  nv.it_interval.tv_nsec = (inDelay % 1000) * 1000000;
208  nv.it_value = nv.it_interval;
209  timerfd_settime(fd, 0, &nv, &ov);
210 }
211 
212 void CStdMultimediaTimerProc::Set()
213 {
214  struct itimerspec nv, ov;
215  timerfd_gettime(fd, &nv);
216  nv.it_value.tv_sec = 0;
217  nv.it_value.tv_nsec = 1;
218  timerfd_settime(fd, 0, &nv, &ov);
219 }
220 
221 bool CStdMultimediaTimerProc::CheckAndReset()
222 {
223  uint64_t n;
224  return read(fd, &n, 8) != -1;
225 }
226 
227 void CStdMultimediaTimerProc::GetFDs(std::vector<struct pollfd> & checkfds)
228 {
229  pollfd pfd = { fd, POLLIN, 0 };
230  checkfds.push_back(pfd);
231 }
232 #endif // HAVE_SYS_TIMERFD_H
233 
234 #if !defined(USE_COCOA)
239 #endif
240 #endif // HAVE_POLL_H
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
#define CStdMultimediaTimerProc
Definition: StdScheduler.h:216
static C4TimeMilliseconds Now()
~CStdNotifyProc() override
void GetFDs(std::vector< struct pollfd > &checkfds) override
bool CheckAndReset()
virtual void OnError(StdSchedulerProc *)
Definition: StdScheduler.h:268
virtual bool DoScheduleProcs(int iTimeout)
void Added(StdSchedulerProc *pProc)
void StartOnCurrentThread()
void Removing(StdSchedulerProc *pProc)
void Changed(StdSchedulerProc *pProc)
virtual void GetFDs(std::vector< struct pollfd > &)
Definition: StdScheduler.h:72