OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdScheduler.h
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 /* A simple scheduler for ccoperative multitasking */
17 
18 #ifndef STDSCHEDULER_H
19 #define STDSCHEDULER_H
20 
21 #include "platform/StdSync.h"
22 
23 // Events are Windows-specific
24 #ifdef _WIN32
25 #define STDSCHEDULER_USE_EVENTS
26 #define HAVE_WINTHREAD
27 #define STDSCHEDULER_EVENT_MESSAGE INVALID_HANDLE_VALUE
28 struct pollfd;
29 #ifndef STDSCHEDULER_USE_EVENTS
31 #include <winsock2.h>
32 #endif // STDSCHEDULER_USE_EVENTS
33 #else // _WIN32
34 #ifdef HAVE_POLL_H
35 #include <poll.h>
36 #include <vector>
37 #else // HAVE_POLL_H
38 #include <sys/select.h>
39 #endif // HAVE_POLL_H
40 #ifdef HAVE_PTHREAD
41 #include <pthread.h>
42 #endif // HAVE_PTHREAD
43 #ifdef __APPLE__
44 #include <sched.h>
45 #endif
46 #endif // _WIN32
47 
48 
49 #include <vector>
50 
51 typedef struct _GMainLoop GMainLoop;
52 
53 // Abstract class for a process
55 {
56 private:
57  class StdScheduler *scheduler;
58 protected:
59  void Changed();
60 public:
61 
62  StdSchedulerProc(): scheduler(nullptr) {}
63  virtual ~StdSchedulerProc() { }
64 
65  // Do whatever the process wishes to do. Should not block longer than the timeout value.
66  // Is called whenever the process is signaled or a timeout occurs.
67  virtual bool Execute(int iTimeout = -1, pollfd * readyfds = 0) = 0;
68 
69  // As Execute, but won't return until the given timeout value has elapsed or a failure occurs
70  bool ExecuteUntil(int iTimeout = -1);
71 
72  // Signal for calling Execute()
73 #ifdef STDSCHEDULER_USE_EVENTS
74  virtual HANDLE GetEvent() { return 0; }
75 #else
76  virtual void GetFDs(std::vector<struct pollfd> &) { }
77 #endif
78 
79  // Call Execute() after this time has elapsed
81 
82  // Is the process signal currently set?
83  bool IsSignaled();
84 
85  // Is this the expensive game tick?
86  virtual bool IsLowPriority() { return false; }
87  virtual bool IsNotify() { return false; }
88  virtual uint32_t TimerInterval() { return 0; }
89 
90  friend class StdScheduler;
91 
92 };
93 
94 // A simple timer proc
96 {
97 public:
98  CStdTimerProc(uint32_t iDelay) : tLastTimer(C4TimeMilliseconds::NegativeInfinity), iDelay(iDelay) { }
100 
101 private:
102  C4TimeMilliseconds tLastTimer;
103  uint32_t iDelay;
104 
105 public:
106  void Set()
107  {
109  }
110  void SetDelay(uint32_t inDelay) { iDelay = inDelay; Changed(); }
112  {
114  if (tTime < tLastTimer + iDelay) return false;
115  // Compensate light drifting
116  int32_t iDrift = tTime - (tLastTimer + iDelay); // a positive time difference because of above check
117  tLastTimer = tTime - std::min(iDrift, (int32_t) iDelay / 2);
118  return true;
119  }
120 
121  // StdSchedulerProc override
123  {
124  return tLastTimer + iDelay;
125  }
126  virtual uint32_t TimerInterval() { return iDelay; }
127 };
128 
130 {
131 public:
133  virtual void OnSec1Timer() = 0;
134 protected:
135  virtual bool Execute(int, pollfd *)
136  {
137  if (CheckAndReset())
138  OnSec1Timer();
139  return true;
140  }
141 };
142 
143 // A simple alertable proc
145 {
146 public:
147  CStdNotifyProc();
148 
149  void Notify();
150  bool CheckAndReset();
151  virtual bool IsNotify() { return true; }
152 
153 #ifdef STDSCHEDULER_USE_EVENTS
154  ~CStdNotifyProc() { }
155 
156  // StdSchedulerProc override
157  virtual HANDLE GetEvent() { return Event.GetEvent(); }
158 
159 private:
160  CStdEvent Event;
161 
162 #else // STDSCHEDULER_USE_EVENTS
163  ~CStdNotifyProc();
164 
165  // StdSchedulerProc override
166  virtual void GetFDs(std::vector<struct pollfd> & checkfds);
167 
168 private:
169  int fds[2];
170 
171 #endif
172 };
173 
174 #ifdef STDSCHEDULER_USE_EVENTS
176 {
177 public:
178  CStdMultimediaTimerProc(uint32_t iDelay);
180 
181 private:
182  static int iTimePeriod;
183  uint32_t uCriticalTimerDelay;
184 
185  UINT idCriticalTimer,uCriticalTimerResolution;
186  CStdEvent Event;
187  bool Check() { return Event.WaitFor(0); }
188 
189 public:
190 
191  void SetDelay(uint32_t iDelay);
192  void Set() { Event.Set(); }
193  bool CheckAndReset();
194 
195  // StdSchedulerProc overrides
196  virtual HANDLE GetEvent() { return Event.GetEvent(); }
197 
198 };
199 
200 #elif defined(HAVE_SYS_TIMERFD_H)
201 // timer proc using a timerfd
203 {
204 public:
205  CStdMultimediaTimerProc(uint32_t iDelay);
207 
208 private:
209  int fd;
210 
211 public:
212  void Set();
213  void SetDelay(uint32_t inDelay);
214  bool CheckAndReset();
215  // StdSchedulerProc overrides
216  virtual void GetFDs(std::vector<struct pollfd> & checkfds);
217 };
218 
219 #else
220 #define CStdMultimediaTimerProc CStdTimerProc
221 #endif
222 
223 // A simple process scheduler
225 {
226 public:
227  StdScheduler();
228  virtual ~StdScheduler();
229 
230 private:
231  // Process list
232  std::vector<StdSchedulerProc*> procs;
233  bool isInManualLoop;
234 
235  // Unblocker
236  class NoopNotifyProc : public CStdNotifyProc
237  {
238  public: virtual bool Execute(int, pollfd *) { CheckAndReset(); return true; }
239  };
240  NoopNotifyProc Unblocker;
241 
242  // Dummy lists (preserved to reduce allocs)
243 #ifdef STDSCHEDULER_USE_EVENTS
244  std::vector<HANDLE> eventHandles;
245  std::vector<StdSchedulerProc*> eventProcs;
246 #endif
247 
248 public:
249  int getProcCnt() const { return procs.size()-1; } // ignore internal NoopNotifyProc
250  bool hasProc(StdSchedulerProc *pProc) { return std::find(procs.begin(), procs.end(), pProc) != procs.end(); }
251  bool IsInManualLoop() { return isInManualLoop; }
252 
253  void Clear();
254  void Set(StdSchedulerProc **ppProcs, int iProcCnt);
255  void Add(StdSchedulerProc *pProc);
256  void Remove(StdSchedulerProc *pProc);
257 
258  // extra events for above Add/Remove methods
259  void Added(StdSchedulerProc *pProc);
260  void Removing(StdSchedulerProc *pProc);
261  // called by StdSchedulerProcs when something important about their configuration changed
262  void Changed(StdSchedulerProc *pProc);
263  // needs to be called on thread tasks for this scheduler are meant to be run on
264  void StartOnCurrentThread();
265 
267  bool ScheduleProcs(int iTimeout = 1000/36);
268  void UnBlock();
269 
270 protected:
271  // overridable
272  virtual void OnError(StdSchedulerProc *) { }
273  virtual bool DoScheduleProcs(int iTimeout);
274 };
275 
276 // A simple process scheduler thread
278 {
279 public:
281  virtual ~StdSchedulerThread();
282 
283 private:
284 
285  // thread control
286  bool fRunThreadRun;
287 
288  bool fThread;
289 #ifdef HAVE_WINTHREAD
290  uintptr_t iThread;
291 #elif defined(HAVE_PTHREAD)
292  pthread_t Thread;
293 #endif
294 
295 public:
296  void Clear();
297  void Set(StdSchedulerProc **ppProcs, int iProcCnt);
298  void Add(StdSchedulerProc *pProc);
299  void Remove(StdSchedulerProc *pProc);
300 
301  bool Start();
302  void Stop();
303 
304 private:
305 
306  // thread func
307 #ifdef HAVE_WINTHREAD
308  static void __cdecl _ThreadFunc(void *);
309 #elif defined(HAVE_PTHREAD)
310  static void *_ThreadFunc(void *);
311 #endif
312  unsigned int ThreadFunc();
313 
314 };
315 
317 {
318 private:
319  bool fStarted;
320  bool fStopSignaled;
321 
322 #ifdef HAVE_WINTHREAD
323  uintptr_t iThread;
324 #elif defined(HAVE_PTHREAD)
325  pthread_t Thread;
326 #endif
327 
328 public:
329  StdThread();
330  virtual ~StdThread() { Stop(); }
331 
332  bool Start();
333  void SignalStop(); // mark thread to stop but don't wait
334  void Stop();
335 
336  bool IsStarted() { return fStarted; }
337 
338 protected:
339  virtual void Execute() = 0;
340 
341  bool IsStopSignaled();
342  virtual bool IsSelfDestruct() { return false; } // whether thread should delete itself after execution finished
343 
344 private:
345  // thread func
346 #ifdef HAVE_WINTHREAD
347  static void __cdecl _ThreadFunc(void *);
348 #elif defined(HAVE_PTHREAD)
349  static void *_ThreadFunc(void *);
350 #endif
351  unsigned int ThreadFunc();
352 };
353 
354 #endif
bool hasProc(StdSchedulerProc *pProc)
Definition: StdScheduler.h:250
int getProcCnt() const
Definition: StdScheduler.h:249
virtual void GetFDs(std::vector< struct pollfd > &checkfds)
bool IsStopSignaled()
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
void Removing(StdSchedulerProc *pProc)
void Set(StdSchedulerProc **ppProcs, int iProcCnt)
C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
virtual ~StdThread()
Definition: StdScheduler.h:330
virtual uint32_t TimerInterval()
Definition: StdScheduler.h:126
virtual void OnError(StdSchedulerProc *)
Definition: StdScheduler.h:272
void Remove(StdSchedulerProc *pProc)
void Add(StdSchedulerProc *pProc)
bool Start()
virtual bool IsSelfDestruct()
Definition: StdScheduler.h:342
virtual ~StdSchedulerProc()
Definition: StdScheduler.h:63
bool CheckAndReset()
Definition: StdScheduler.h:111
CStdTimerProc(uint32_t iDelay)
Definition: StdScheduler.h:98
virtual bool Execute(int, pollfd *)
Definition: StdScheduler.h:135
bool WaitFor(int)
Definition: StdSync.h:161
virtual uint32_t TimerInterval()
Definition: StdScheduler.h:88
void SetDelay(uint32_t inDelay)
Definition: StdScheduler.h:110
#define CStdMultimediaTimerProc
Definition: StdScheduler.h:220
bool ExecuteUntil(int iTimeout=-1)
void SignalStop()
virtual bool Execute(int iTimeout=-1, pollfd *readyfds=0)=0
bool CheckAndReset()
virtual bool IsLowPriority()
Definition: StdScheduler.h:86
virtual void Execute()=0
void Remove(StdSchedulerProc *pProc)
virtual void GetFDs(std::vector< struct pollfd > &)
Definition: StdScheduler.h:76
virtual bool IsNotify()
Definition: StdScheduler.h:151
void StartOnCurrentThread()
virtual ~StdScheduler()
virtual void OnSec1Timer()=0
void Set()
Definition: StdSync.h:158
void Changed(StdSchedulerProc *pProc)
bool ScheduleProcs(int iTimeout=1000/36)
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
Definition: StdScheduler.h:122
virtual bool DoScheduleProcs(int iTimeout)
void Set(StdSchedulerProc **ppProcs, int iProcCnt)
void Added(StdSchedulerProc *pProc)
bool IsInManualLoop()
Definition: StdScheduler.h:251
struct _GMainLoop GMainLoop
Definition: StdScheduler.h:51
virtual bool IsNotify()
Definition: StdScheduler.h:87
static C4TimeMilliseconds Now()
virtual ~StdSchedulerThread()
void Add(StdSchedulerProc *pProc)
bool IsStarted()
Definition: StdScheduler.h:336