OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4InteractiveThread.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 #include "C4Include.h"
18 
19 #include "game/C4Application.h"
20 
21 // *** C4InteractiveThread
22 
24 {
25  // Add head-item
26  pFirstEvent = pLastEvent = new Event();
27  pFirstEvent->Type = Ev_None;
28  pFirstEvent->Next = nullptr;
29  // reset event handlers
30  ZeroMem(&pCallbacks, sizeof(pCallbacks));
31  // Set notify proc
32  NotifyProc.SetNotify(this);
33  Application.Add(&NotifyProc);
34 }
35 
37 {
38  CStdLock PushLock(&EventPushCSec), PopLock(&EventPopCSec);
39  // Remove all items. This may leak data, if pData was allocated on the heap.
40  while (PopEvent(nullptr, nullptr)) {}
41  // Delete head-item
42  delete pFirstEvent;
43  pFirstEvent = pLastEvent = nullptr;
44  // Unregister notify
45  Application.Remove(&NotifyProc);
46 }
47 
49 {
50  bool fFirst = !Scheduler.getProcCnt();
51  // Add the proc
52  Scheduler.Add(pProc);
53  // Not started yet?
54  if (fFirst)
55  if (!Scheduler.Start())
56  return false;
57  return true;
58 }
59 
61 {
62  // Process not in list?
63  if (!Scheduler.hasProc(pProc))
64  return;
65  // Last proc to be removed?
66  if (Scheduler.getProcCnt() == 1)
67  Scheduler.Stop();
68  // Remove
69  Scheduler.Remove(pProc);
70 }
71 
73 {
74  CStdLock PushLock(&EventPushCSec);
75  if (!pLastEvent) return false;
76  // create event
77  Event *pEvent = new Event;
78  pEvent->Type = eEvent;
79  pEvent->Data = pData;
80 #ifdef _DEBUG
81  pEvent->Time = C4TimeMilliseconds::Now();
82 #endif
83  pEvent->Next = nullptr;
84  // add item (at end)
85  pLastEvent->Next = pEvent;
86  pLastEvent = pEvent;
87  PushLock.Clear();
88  // notify main thread
89  NotifyProc.Notify();
90  return true;
91 }
92 
93 #ifdef _DEBUG
94 double AvgNetEvDelay = 0;
95 #endif
96 
97 bool C4InteractiveThread::PopEvent(C4InteractiveEventType *pEventType, void **ppData) // (by main thread)
98 {
99  CStdLock PopLock(&EventPopCSec);
100  if (!pFirstEvent) return false;
101  // get event
102  Event *pEvent = pFirstEvent->Next;
103  if (!pEvent) return false;
104  // return
105  if (pEventType)
106  *pEventType = pEvent->Type;
107  if (ppData)
108  *ppData = pEvent->Data;
109 #ifdef _DEBUG
110  if (Game.IsRunning)
111  AvgNetEvDelay += ((C4TimeMilliseconds::Now() - pEvent->Time) - AvgNetEvDelay) / 100;
112 #endif
113  // remove
114  delete pFirstEvent;
115  pFirstEvent = pEvent;
116  pFirstEvent->Type = Ev_None;
117  return true;
118 }
119 
120 
121 void C4InteractiveThread::ProcessEvents() // by main thread
122 {
123  C4InteractiveEventType eEventType; void *pEventData;
124  while (PopEvent(&eEventType, &pEventData))
125  switch (eEventType)
126  {
127  // Logging
128  case Ev_Log: case Ev_LogSilent: case Ev_LogFatal: case Ev_LogDebug:
129  {
130  // Reconstruct the StdStrBuf which allocated the data.
131  StdStrBuf pLog;
132  pLog.Take(reinterpret_cast<char *>(pEventData));
133  switch (eEventType)
134  {
135  case Ev_Log:
136  Log(pLog.getData()); break;
137  case Ev_LogSilent:
138  LogSilent(pLog.getData()); break;
139  case Ev_LogFatal:
140  LogFatal(pLog.getData()); break;
141  case Ev_LogDebug:
142  DebugLog(pLog.getData()); break;
143  default: assert(eEventType == Ev_Log || eEventType == Ev_LogSilent || eEventType == Ev_LogFatal || eEventType == Ev_LogDebug); // obviously will not happen, but someone tell gcc
144  }
145 
146  }
147  break;
148 
149  case Ev_Function:
150  {
151  std::unique_ptr<std::function<void ()> > func(static_cast<std::function<void()>*>(pEventData));
152  (*func)();
153  }
154 
155  // Other events: check for a registered handler
156  default:
157  if (eEventType >= Ev_None && eEventType <= Ev_Last)
158  if (pCallbacks[eEventType])
159  pCallbacks[eEventType]->OnThreadEvent(eEventType, pEventData);
160  // Note that memory might leak if the event wasn't processed....
161  }
162 }
163 
164 
165 bool C4InteractiveThread::ThreadLog(const char *szMessage, ...)
166 {
167  // format message
168  va_list lst; va_start(lst, szMessage);
169  StdStrBuf Msg = FormatStringV(szMessage, lst);
170  // send to main thread
171  return PushEvent(Ev_Log, Msg.GrabPointer());
172 }
173 
174 bool C4InteractiveThread::ThreadLogFatal(const char *szMessage, ...)
175 {
176  // format message
177  va_list lst; va_start(lst, szMessage);
178  StdStrBuf Msg = FormatStringV(szMessage, lst);
179  // send to main thread
180  return PushEvent(Ev_LogFatal, Msg.GrabPointer());
181 }
182 
183 bool C4InteractiveThread::ThreadLogS(const char *szMessage, ...)
184 {
185  // format message
186  va_list lst; va_start(lst, szMessage);
187  StdStrBuf Msg = FormatStringV(szMessage, lst);
188  // send to main thread
189  return PushEvent(Ev_LogSilent, Msg.GrabPointer());
190 }
191 
192 bool C4InteractiveThread::ThreadLogDebug(const char *szMessage, ...)
193 {
194  // format message
195  va_list lst; va_start(lst, szMessage);
196  StdStrBuf Msg = FormatStringV(szMessage, lst);
197  // send to main thread
198  return PushEvent(Ev_LogDebug, Msg.GrabPointer());
199 }
200 
202 {
203  if (CheckAndReset())
204  pNotify->ProcessEvents();
205  return true;
206 }
const char * getData() const
Definition: StdBuf.h:442
bool hasProc(StdSchedulerProc *pProc)
Definition: StdScheduler.h:246
bool IsRunning
Definition: C4Game.h:139
int getProcCnt() const
Definition: StdScheduler.h:245
char * GrabPointer()
Definition: StdBuf.h:459
bool LogSilent(const char *szMessage, bool fConsole)
Definition: C4Log.cpp:124
C4Game Game
Definition: C4Globals.cpp:52
virtual void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData)=0
bool ThreadLogS(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
bool DebugLog(const char *strMessage)
Definition: C4Log.cpp:280
bool ThreadLogFatal(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
bool PushEvent(C4InteractiveEventType eEventType, void *pData=nullptr)
void Remove(StdSchedulerProc *pProc)
void Add(StdSchedulerProc *pProc)
bool ThreadLog(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
void Clear()
Definition: StdSync.h:178
void Take(char *pnData)
Definition: StdBuf.h:457
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:237
C4InteractiveEventType
bool CheckAndReset()
StdStrBuf FormatStringV(const char *szFmt, va_list args)
Definition: StdBuf.cpp:276
bool Execute(int iTimeout, pollfd *readyfds) override
bool AddProc(StdSchedulerProc *pProc)
void RemoveProc(StdSchedulerProc *pProc)
void Remove(StdSchedulerProc *pProc)
bool ThreadLogDebug(const char *szMessage,...) GNUC_FORMAT_ATTRIBUTE_O
bool Log(const char *szMessage)
Definition: C4Log.cpp:202
std::enable_if< std::is_pod< T >::value >::type ZeroMem(T *lpMem, size_t dwSize)
Definition: Standard.h:60
void SetNotify(class C4InteractiveThread *pnNotify)
C4Application Application
Definition: C4Globals.cpp:44
static C4TimeMilliseconds Now()
void Add(StdSchedulerProc *pProc)