OpenClonk
StdSchedulerWin32.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 // Events are Windows-specific
18 #include "C4Include.h"
19 #include "platform/StdScheduler.h"
20 #ifdef STDSCHEDULER_USE_EVENTS
21 
22 #include <mmsystem.h>
23 #include <process.h>
24 
26 {
27  return GetEvent() && WaitForSingleObject(GetEvent(), 0) == WAIT_OBJECT_0;
28 }
29 
30 CStdNotifyProc::CStdNotifyProc() : Event(true) {}
31 void CStdNotifyProc::Notify() { Event.Set(); }
33 {
34  if (!Event.WaitFor(0)) return false;
35  Event.Reset();
36  return true;
37 }
38 
39 bool StdScheduler::DoScheduleProcs(int iTimeout)
40 {
41  size_t i;
42  // Collect event handles
43  int iEventCnt = 0; HANDLE hEvent;
44  StdSchedulerProc *pMessageProc = nullptr;
45  for (i = 0u; i < procs.size(); i++)
46  {
47  auto proc = procs[i];
48  if ( (hEvent = proc->GetEvent()) )
49  {
50  if (hEvent == STDSCHEDULER_EVENT_MESSAGE)
51  pMessageProc = proc;
52  else
53  {
54  eventHandles[iEventCnt] = hEvent;
55  eventProcs[iEventCnt] = proc;
56  iEventCnt++;
57  }
58  }
59  }
60 
61  // Wait for something to happen
62  DWORD ret; DWORD dwMsec = iTimeout < 0 ? INFINITE : iTimeout;
63  if (pMessageProc)
64  ret = MsgWaitForMultipleObjects(iEventCnt, eventHandles.data(), false, dwMsec, QS_ALLINPUT);
65  else
66  ret = WaitForMultipleObjects(iEventCnt, eventHandles.data(), false, dwMsec);
67 
68  bool fSuccess = true;
69 
70  // Event?
71  if (ret != WAIT_TIMEOUT)
72  {
73  // Which event?
74  int iEventNr = ret - WAIT_OBJECT_0;
75 
76  // Execute the signaled process
77  StdSchedulerProc *pProc = iEventNr < iEventCnt ? eventProcs[iEventNr] : pMessageProc;
78  if (!pProc->Execute(0))
79  {
80  OnError(pProc);
81  fSuccess = false;
82  }
83 
84  }
85 
86  // Execute all processes with timeout
87  // Iterate over the index because procedures may be added or removed during execution
88  // (If they are removed, we skip one execution, which doesn't really matter in practice)
89  auto tNow = C4TimeMilliseconds::Now();
90  for (size_t i_proc = 0u; i_proc < procs.size(); ++i_proc)
91  {
92  StdSchedulerProc *proc = procs[i_proc];
93  auto tProcTick = proc->GetNextTick(tNow);
94  if (tProcTick <= tNow)
95  if (!proc->Execute(0))
96  {
97  OnError(proc);
98  fSuccess = false;
99  }
100  }
101  return fSuccess;
102 }
103 
104 /* CStdMultimediaTimerProc */
105 
106 int CStdMultimediaTimerProc::iTimePeriod = 0;
107 
109  uCriticalTimerDelay(28),
110  idCriticalTimer(0),
111  uCriticalTimerResolution(5),
112  Event(true)
113 {
114 
115  if (!iTimePeriod)
116  {
117  // Get resolution caps
118  TIMECAPS tc;
119  timeGetDevCaps(&tc, sizeof(tc));
120  // Establish minimum resolution
121  uCriticalTimerResolution = Clamp(uCriticalTimerResolution, tc.wPeriodMin, tc.wPeriodMax);
122  timeBeginPeriod(uCriticalTimerResolution);
123  }
124  iTimePeriod++;
125 
126  SetDelay(iDelay);
127 
128 }
129 
130 CStdMultimediaTimerProc::~CStdMultimediaTimerProc()
131 {
132  if (idCriticalTimer)
133  {
134  timeKillEvent(idCriticalTimer);
135  idCriticalTimer = 0;
136 
137  iTimePeriod--;
138  if (!iTimePeriod)
139  timeEndPeriod(uCriticalTimerResolution);
140  }
141 }
142 
143 void CStdMultimediaTimerProc::SetDelay(uint32_t iDelay)
144 {
145 
146  // Kill old timer (of any)
147  if (idCriticalTimer)
148  timeKillEvent(idCriticalTimer);
149 
150  // Set new delay
151  uCriticalTimerDelay = iDelay;
152 
153  // Set critical timer
154  idCriticalTimer=timeSetEvent(
155  uCriticalTimerDelay,uCriticalTimerResolution,
156  (LPTIMECALLBACK) Event.GetEvent(),0,TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
157 
158  if(idCriticalTimer == 0)
159  DebugLogF("Creating Critical Timer failed: %d", GetLastError());
160 }
161 
163 {
164  if (procs.size() > eventProcs.size())
165  {
166  eventProcs.resize(procs.size());
167  eventHandles.resize(procs.size()+1);
168  }
169 }
170 
172 {
173 }
174 
176 {
177 }
178 
180 {
181 }
182 
183 bool CStdMultimediaTimerProc::CheckAndReset()
184 {
185  if (!Check()) return false;
186  Event.Reset();
187  return true;
188 }
189 #endif
bool DebugLogF(const char *strMessage ...)
Definition: C4Log.cpp:290
uint32_t DWORD
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
#define CStdMultimediaTimerProc
Definition: StdScheduler.h:216
#define INFINITE
Definition: StdSync.h:58
static C4TimeMilliseconds Now()
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 C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
virtual bool Execute(int iTimeout=-1, pollfd *readyfds=nullptr)=0