Bug Summary

File:Source/Core/Core/Src/CoreTiming.cpp
Location:line 469, column 4
Description:Value stored to 'name' is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "Thread.h"
8#include "PowerPC/PowerPC.h"
9#include "CoreTiming.h"
10#include "Core.h"
11#include "StringUtil.h"
12#include "VideoBackendBase.h"
13#include "FifoQueue.h"
14
15#define MAX_SLICE_LENGTH20000 20000
16
17namespace CoreTiming
18{
19
20struct EventType
21{
22 TimedCallback callback;
23 const char *name;
24};
25
26std::vector<EventType> event_types;
27
28struct BaseEvent
29{
30 s64 time;
31 u64 userdata;
32 int type;
33};
34
35typedef LinkedListItem<BaseEvent> Event;
36
37// STATE_TO_SAVE
38static Event *first;
39static std::mutex tsWriteLock;
40Common::FifoQueue<BaseEvent, false> tsQueue;
41
42// event pools
43Event *eventPool = 0;
44
45int downcount, slicelength;
46int maxSliceLength = MAX_SLICE_LENGTH20000;
47
48s64 globalTimer;
49s64 idledCycles;
50
51u32 fakeDecStartValue;
52u64 fakeDecStartTicks;
53u64 fakeTBStartValue;
54u64 fakeTBStartTicks;
55
56int ev_lost;
57
58
59void (*advanceCallback)(int cyclesExecuted) = NULL__null;
60
61Event* GetNewEvent()
62{
63 if(!eventPool)
64 return new Event;
65
66 Event* ev = eventPool;
67 eventPool = ev->next;
68 return ev;
69}
70
71void FreeEvent(Event* ev)
72{
73 ev->next = eventPool;
74 eventPool = ev;
75}
76
77static void EmptyTimedCallback(u64 userdata, int cyclesLate) {}
78
79int RegisterEvent(const char *name, TimedCallback callback)
80{
81 EventType type;
82 type.name = name;
83 type.callback = callback;
84
85 // check for existing type with same name.
86 // we want event type names to remain unique so that we can use them for serialization.
87 for (unsigned int i = 0; i < event_types.size(); ++i)
88 {
89 if (!strcmp(name, event_types[i].name))
90 {
91 WARN_LOG(POWERPC, "Discarded old event type \"%s\" because a new type with the same name was registered.", name)do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::POWERPC, "/home/anal/dolphin-emu/Source/Core/Core/Src/CoreTiming.cpp"
, 91, "Discarded old event type \"%s\" because a new type with the same name was registered."
, name); } } while (0)
;
92 // we don't know if someone might be holding on to the type index,
93 // so we gut the old event type instead of actually removing it.
94 event_types[i].name = "_discarded_event";
95 event_types[i].callback = &EmptyTimedCallback;
96 }
97 }
98
99 event_types.push_back(type);
100 return (int)event_types.size() - 1;
101}
102
103void UnregisterAllEvents()
104{
105 if (first)
106 PanicAlertT("Cannot unregister events with events pending")MsgAlert(false, WARNING, "Cannot unregister events with events pending"
)
;
107 event_types.clear();
108}
109
110void Init()
111{
112 downcount = maxSliceLength;
113 slicelength = maxSliceLength;
114 globalTimer = 0;
115 idledCycles = 0;
116
117 ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback);
118}
119
120void Shutdown()
121{
122 std::lock_guard<std::mutex> lk(tsWriteLock);
123 MoveEvents();
124 ClearPendingEvents();
125 UnregisterAllEvents();
126
127 while(eventPool)
128 {
129 Event *ev = eventPool;
130 eventPool = ev->next;
131 delete ev;
132 }
133}
134
135void EventDoState(PointerWrap &p, BaseEvent* ev)
136{
137 p.Do(ev->time);
138
139 // this is why we can't have (nice things) pointers as userdata
140 p.Do(ev->userdata);
141
142 // we can't savestate ev->type directly because events might not get registered in the same order (or at all) every time.
143 // so, we savestate the event's type's name, and derive ev->type from that when loading.
144 std::string name;
145 if (p.GetMode() != PointerWrap::MODE_READ)
146 name = event_types[ev->type].name;
147
148 p.Do(name);
149 if (p.GetMode() == PointerWrap::MODE_READ)
150 {
151 bool foundMatch = false;
152 for (unsigned int i = 0; i < event_types.size(); ++i)
153 {
154 if (!strcmp(name.c_str(), event_types[i].name))
155 {
156 ev->type = i;
157 foundMatch = true;
158 break;
159 }
160 }
161 if (!foundMatch)
162 {
163 WARN_LOG(POWERPC, "Lost event from savestate because its type, \"%s\", has not been registered.", name.c_str())do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::POWERPC, "/home/anal/dolphin-emu/Source/Core/Core/Src/CoreTiming.cpp"
, 163, "Lost event from savestate because its type, \"%s\", has not been registered."
, name.c_str()); } } while (0)
;
164 ev->type = ev_lost;
165 }
166 }
167}
168
169void DoState(PointerWrap &p)
170{
171 std::lock_guard<std::mutex> lk(tsWriteLock);
172 p.Do(downcount);
173 p.Do(slicelength);
174 p.Do(globalTimer);
175 p.Do(idledCycles);
176 p.Do(fakeDecStartValue);
177 p.Do(fakeDecStartTicks);
178 p.Do(fakeTBStartValue);
179 p.Do(fakeTBStartTicks);
180 p.DoMarker("CoreTimingData");
181
182 MoveEvents();
183
184 p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, EventDoState>(first);
185 p.DoMarker("CoreTimingEvents");
186}
187
188u64 GetTicks()
189{
190 return (u64)globalTimer;
191}
192
193u64 GetIdleTicks()
194{
195 return (u64)idledCycles;
196}
197
198// This is to be called when outside threads, such as the graphics thread, wants to
199// schedule things to be executed on the main thread.
200void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata)
201{
202 std::lock_guard<std::mutex> lk(tsWriteLock);
203 Event ne;
204 ne.time = globalTimer + cyclesIntoFuture;
205 ne.type = event_type;
206 ne.userdata = userdata;
207 tsQueue.Push(ne);
208}
209
210// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
211// in which case the event will get handled immediately, before returning.
212void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata)
213{
214 if(Core::IsCPUThread())
215 {
216 event_types[event_type].callback(userdata, 0);
217 }
218 else
219 {
220 ScheduleEvent_Threadsafe(0, event_type, userdata);
221 }
222}
223
224void ClearPendingEvents()
225{
226 while (first)
227 {
228 Event *e = first->next;
229 FreeEvent(first);
230 first = e;
231 }
232}
233
234void AddEventToQueue(Event* ne)
235{
236 Event* prev = NULL__null;
237 Event** pNext = &first;
238 for(;;)
239 {
240 Event*& next = *pNext;
241 if(!next || ne->time < next->time)
242 {
243 ne->next = next;
244 next = ne;
245 break;
246 }
247 prev = next;
248 pNext = &prev->next;
249 }
250}
251
252// This must be run ONLY from within the cpu thread
253// cyclesIntoFuture may be VERY inaccurate if called from anything else
254// than Advance
255void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata)
256{
257 Event *ne = GetNewEvent();
258 ne->userdata = userdata;
259 ne->type = event_type;
260 ne->time = globalTimer + cyclesIntoFuture;
261 AddEventToQueue(ne);
262}
263
264void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
265{
266 advanceCallback = callback;
267}
268
269bool IsScheduled(int event_type)
270{
271 if (!first)
272 return false;
273 Event *e = first;
274 while (e) {
275 if (e->type == event_type)
276 return true;
277 e = e->next;
278 }
279 return false;
280}
281
282void RemoveEvent(int event_type)
283{
284 if (!first)
285 return;
286
287 while(first)
288 {
289 if (first->type == event_type)
290 {
291 Event *next = first->next;
292 FreeEvent(first);
293 first = next;
294 }
295 else
296 {
297 break;
298 }
299 }
300
301 if (!first)
302 return;
303
304 Event *prev = first;
305 Event *ptr = prev->next;
306 while (ptr)
307 {
308 if (ptr->type == event_type)
309 {
310 prev->next = ptr->next;
311 FreeEvent(ptr);
312 ptr = prev->next;
313 }
314 else
315 {
316 prev = ptr;
317 ptr = ptr->next;
318 }
319 }
320}
321
322void RemoveAllEvents(int event_type)
323{
324 MoveEvents();
325 RemoveEvent(event_type);
326}
327
328void SetMaximumSlice(int maximumSliceLength)
329{
330 maxSliceLength = maximumSliceLength;
331}
332
333void ForceExceptionCheck(int cycles)
334{
335 if (downcount > cycles)
336 {
337 slicelength -= (downcount - cycles); // Account for cycles already executed by adjusting the slicelength
338 downcount = cycles;
339 }
340}
341
342void ResetSliceLength()
343{
344 maxSliceLength = MAX_SLICE_LENGTH20000;
345}
346
347
348//This raise only the events required while the fifo is processing data
349void ProcessFifoWaitEvents()
350{
351 MoveEvents();
352
353 if (!first)
354 return;
355
356 while (first)
357 {
358 if (first->time <= globalTimer)
359 {
360 Event* evt = first;
361 first = first->next;
362 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
363 FreeEvent(evt);
364 }
365 else
366 {
367 break;
368 }
369 }
370}
371
372void MoveEvents()
373{
374 BaseEvent sevt;
375 while (tsQueue.Pop(sevt))
376 {
377 Event *evt = GetNewEvent();
378 evt->time = sevt.time;
379 evt->userdata = sevt.userdata;
380 evt->type = sevt.type;
381 AddEventToQueue(evt);
382 }
383}
384
385void Advance()
386{
387 MoveEvents();
388
389 int cyclesExecuted = slicelength - downcount;
390 globalTimer += cyclesExecuted;
391 downcount = slicelength;
392
393 while (first)
394 {
395 if (first->time <= globalTimer)
396 {
397// LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ",
398// event_types[first->type].name ? event_types[first->type].name : "?", (u64)globalTimer, (u64)first->time);
399 Event* evt = first;
400 first = first->next;
401 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
402 FreeEvent(evt);
403 }
404 else
405 {
406 break;
407 }
408 }
409
410 if (!first)
411 {
412 WARN_LOG(POWERPC, "WARNING - no events in queue. Setting downcount to 10000")do { { if (LogTypes::LWARNING <= 3) GenericLog(LogTypes::LWARNING
, LogTypes::POWERPC, "/home/anal/dolphin-emu/Source/Core/Core/Src/CoreTiming.cpp"
, 412, "WARNING - no events in queue. Setting downcount to 10000"
); } } while (0)
;
413 downcount += 10000;
414 }
415 else
416 {
417 slicelength = (int)(first->time - globalTimer);
418 if (slicelength > maxSliceLength)
419 slicelength = maxSliceLength;
420 downcount = slicelength;
421 }
422
423 if (advanceCallback)
424 advanceCallback(cyclesExecuted);
425}
426
427void LogPendingEvents()
428{
429 Event *ptr = first;
430 while (ptr)
431 {
432 INFO_LOG(POWERPC, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type)do { { if (LogTypes::LINFO <= 3) GenericLog(LogTypes::LINFO
, LogTypes::POWERPC, "/home/anal/dolphin-emu/Source/Core/Core/Src/CoreTiming.cpp"
, 432, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer
, ptr->time, ptr->type); } } while (0)
;
433 ptr = ptr->next;
434 }
435}
436
437void Idle()
438{
439 //DEBUG_LOG(POWERPC, "Idle");
440
441 //When the FIFO is processing data we must not advance because in this way
442 //the VI will be desynchronized. So, We are waiting until the FIFO finish and
443 //while we process only the events required by the FIFO.
444 while (g_video_backend->Video_IsPossibleWaitingSetDrawDone())
445 {
446 ProcessFifoWaitEvents();
447 Common::YieldCPU();
448 }
449
450 idledCycles += downcount;
451 downcount = 0;
452
453 Advance();
454}
455
456std::string GetScheduledEventsSummary()
457{
458 Event *ptr = first;
459 std::string text = "Scheduled events\n";
460 text.reserve(1000);
461 while (ptr)
462 {
463 unsigned int t = ptr->type;
464 if (t >= event_types.size())
465 PanicAlertT("Invalid event type %i", t)MsgAlert(false, WARNING, "Invalid event type %i", t);
466
467 const char *name = event_types[ptr->type].name;
468 if (!name)
469 name = "[unknown]";
Value stored to 'name' is never read
470
471 text += StringFromFormat("%s : %i %08x%08x\n", event_types[ptr->type].name, ptr->time, ptr->userdata >> 32, ptr->userdata);
472 ptr = ptr->next;
473 }
474 return text;
475}
476
477u32 GetFakeDecStartValue()
478{
479 return fakeDecStartValue;
480}
481
482void SetFakeDecStartValue(u32 val)
483{
484 fakeDecStartValue = val;
485}
486
487u64 GetFakeDecStartTicks()
488{
489 return fakeDecStartTicks;
490}
491
492void SetFakeDecStartTicks(u64 val)
493{
494 fakeDecStartTicks = val;
495}
496
497u64 GetFakeTBStartValue()
498{
499 return fakeTBStartValue;
500}
501
502void SetFakeTBStartValue(u64 val)
503{
504 fakeTBStartValue = val;
505}
506
507u64 GetFakeTBStartTicks()
508{
509 return fakeTBStartTicks;
510}
511
512void SetFakeTBStartTicks(u64 val)
513{
514 fakeTBStartTicks = val;
515}
516
517} // namespace
518