Bug Summary

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