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