Bug Summary

File:Source/Core/Core/Src/CoreTiming.cpp
Location:line 557, 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 = event_types[ev->type].name;
174 p.Do(name);
175 if (p.GetMode() == PointerWrap::MODE_READ)
176 {
177 bool foundMatch = false;
178 for (unsigned int i = 0; i < event_types.size(); ++i)
179 {
180 if (!strcmp(name.c_str(), event_types[i].name))
181 {
182 ev->type = i;
183 foundMatch = true;
184 break;
185 }
186 }
187 if (!foundMatch)
188 {
189 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"
, 189, "Lost event from savestate because its type, \"%s\", has not been registered."
, name.c_str()); } } while (0)
;
190 ev->type = ev_lost;
191 }
192 }
193}
194
195void DoState(PointerWrap &p)
196{
197 std::lock_guard<std::recursive_mutex> lk(externalEventSection);
198 p.Do(downcount);
199 p.Do(slicelength);
200 p.Do(globalTimer);
201 p.Do(idledCycles);
202 p.Do(fakeDecStartValue);
203 p.Do(fakeDecStartTicks);
204 p.Do(fakeTBStartValue);
205 p.Do(fakeTBStartTicks);
206 p.DoMarker("CoreTimingData");
207
208 p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, EventDoState>(first);
209 p.DoMarker("CoreTimingEvents");
210
211 p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, EventDoState>(tsFirst, &tsLast);
212 p.DoMarker("CoreTimingTsEvents");
213}
214
215u64 GetTicks()
216{
217 return (u64)globalTimer;
218}
219
220u64 GetIdleTicks()
221{
222 return (u64)idledCycles;
223}
224
225// This is to be called when outside threads, such as the graphics thread, wants to
226// schedule things to be executed on the main thread.
227void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata)
228{
229 std::lock_guard<std::recursive_mutex> lk(externalEventSection);
230 Event *ne = GetNewTsEvent();
231 ne->time = globalTimer + cyclesIntoFuture;
232 ne->type = event_type;
233 ne->next = 0;
234 ne->userdata = userdata;
235 if(!tsFirst)
236 tsFirst = ne;
237 if(tsLast)
238 tsLast->next = ne;
239 tsLast = ne;
240}
241
242// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
243// in which case the event will get handled immediately, before returning.
244void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata)
245{
246 if(Core::IsCPUThread())
247 {
248 std::lock_guard<std::recursive_mutex> lk(externalEventSection);
249 event_types[event_type].callback(userdata, 0);
250 }
251 else
252 {
253 ScheduleEvent_Threadsafe(0, event_type, userdata);
254 }
255}
256
257void ClearPendingEvents()
258{
259 while (first)
260 {
261 Event *e = first->next;
262 FreeEvent(first);
263 first = e;
264 }
265}
266
267void AddEventToQueue(Event* ne)
268{
269 Event* prev = NULL__null;
270 Event** pNext = &first;
271 for(;;)
272 {
273 Event*& next = *pNext;
274 if(!next || ne->time < next->time)
275 {
276 ne->next = next;
277 next = ne;
278 break;
279 }
280 prev = next;
281 pNext = &prev->next;
282 }
283}
284
285// This must be run ONLY from within the cpu thread
286// cyclesIntoFuture may be VERY inaccurate if called from anything else
287// than Advance
288void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata)
289{
290 Event *ne = GetNewEvent();
291 ne->userdata = userdata;
292 ne->type = event_type;
293 ne->time = globalTimer + cyclesIntoFuture;
294 AddEventToQueue(ne);
295}
296
297void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted))
298{
299 advanceCallback = callback;
300}
301
302bool IsScheduled(int event_type)
303{
304 if (!first)
305 return false;
306 Event *e = first;
307 while (e) {
308 if (e->type == event_type)
309 return true;
310 e = e->next;
311 }
312 return false;
313}
314
315void RemoveEvent(int event_type)
316{
317 if (!first)
318 return;
319
320 while(first)
321 {
322 if (first->type == event_type)
323 {
324 Event *next = first->next;
325 FreeEvent(first);
326 first = next;
327 }
328 else
329 {
330 break;
331 }
332 }
333
334 if (!first)
335 return;
336
337 Event *prev = first;
338 Event *ptr = prev->next;
339 while (ptr)
340 {
341 if (ptr->type == event_type)
342 {
343 prev->next = ptr->next;
344 FreeEvent(ptr);
345 ptr = prev->next;
346 }
347 else
348 {
349 prev = ptr;
350 ptr = ptr->next;
351 }
352 }
353}
354
355void RemoveThreadsafeEvent(int event_type)
356{
357 std::lock_guard<std::recursive_mutex> lk(externalEventSection);
358 if (!tsFirst)
359 {
360 return;
361 }
362
363 while(tsFirst)
364 {
365 if (tsFirst->type == event_type)
366 {
367 Event *next = tsFirst->next;
368 FreeTsEvent(tsFirst);
369 tsFirst = next;
370 }
371 else
372 {
373 break;
374 }
375 }
376
377 if (!tsFirst)
378 {
379 return;
380 }
381
382 Event *prev = tsFirst;
383 Event *ptr = prev->next;
384 while (ptr)
385 {
386 if (ptr->type == event_type)
387 {
388 prev->next = ptr->next;
389 FreeTsEvent(ptr);
390 ptr = prev->next;
391 }
392 else
393 {
394 prev = ptr;
395 ptr = ptr->next;
396 }
397 }
398}
399
400void RemoveAllEvents(int event_type)
401{
402 RemoveThreadsafeEvent(event_type);
403 RemoveEvent(event_type);
404}
405
406void SetMaximumSlice(int maximumSliceLength)
407{
408 maxSliceLength = maximumSliceLength;
409}
410
411void ForceExceptionCheck(int cycles)
412{
413 if (downcount > cycles)
414 {
415 slicelength -= (downcount - cycles); // Account for cycles already executed by adjusting the slicelength
416 downcount = cycles;
417 }
418}
419
420void ResetSliceLength()
421{
422 maxSliceLength = MAX_SLICE_LENGTH20000;
423}
424
425
426//This raise only the events required while the fifo is processing data
427void ProcessFifoWaitEvents()
428{
429 MoveEvents();
430
431 if (!first)
432 return;
433
434 while (first)
435 {
436 if (first->time <= globalTimer)
437 {
438 Event* evt = first;
439 first = first->next;
440 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
441 FreeEvent(evt);
442 }
443 else
444 {
445 break;
446 }
447 }
448}
449
450void MoveEvents()
451{
452 std::lock_guard<std::recursive_mutex> lk(externalEventSection);
453 // Move events from async queue into main queue
454 while (tsFirst)
455 {
456 Event *next = tsFirst->next;
457 AddEventToQueue(tsFirst);
458 tsFirst = next;
459 }
460 tsLast = NULL__null;
461
462 // Move free events to threadsafe pool
463 while(allocatedTsEvents > 0 && eventPool)
464 {
465 Event *ev = eventPool;
466 eventPool = ev->next;
467 ev->next = eventTsPool;
468 eventTsPool = ev;
469 allocatedTsEvents--;
470 }
471}
472
473void Advance()
474{
475 MoveEvents();
476
477 int cyclesExecuted = slicelength - downcount;
478 globalTimer += cyclesExecuted;
479 downcount = slicelength;
480
481 while (first)
482 {
483 if (first->time <= globalTimer)
484 {
485// LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ",
486// event_types[first->type].name ? event_types[first->type].name : "?", (u64)globalTimer, (u64)first->time);
487 Event* evt = first;
488 first = first->next;
489 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
490 FreeEvent(evt);
491 }
492 else
493 {
494 break;
495 }
496 }
497
498 if (!first)
499 {
500 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"
, 500, "WARNING - no events in queue. Setting downcount to 10000"
); } } while (0)
;
501 downcount += 10000;
502 }
503 else
504 {
505 slicelength = (int)(first->time - globalTimer);
506 if (slicelength > maxSliceLength)
507 slicelength = maxSliceLength;
508 downcount = slicelength;
509 }
510
511 if (advanceCallback)
512 advanceCallback(cyclesExecuted);
513}
514
515void LogPendingEvents()
516{
517 Event *ptr = first;
518 while (ptr)
519 {
520 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"
, 520, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer
, ptr->time, ptr->type); } } while (0)
;
521 ptr = ptr->next;
522 }
523}
524
525void Idle()
526{
527 //DEBUG_LOG(POWERPC, "Idle");
528
529 //When the FIFO is processing data we must not advance because in this way
530 //the VI will be desynchronized. So, We are waiting until the FIFO finish and
531 //while we process only the events required by the FIFO.
532 while (g_video_backend->Video_IsPossibleWaitingSetDrawDone())
533 {
534 ProcessFifoWaitEvents();
535 Common::YieldCPU();
536 }
537
538 idledCycles += downcount;
539 downcount = 0;
540
541 Advance();
542}
543
544std::string GetScheduledEventsSummary()
545{
546 Event *ptr = first;
547 std::string text = "Scheduled events\n";
548 text.reserve(1000);
549 while (ptr)
550 {
551 unsigned int t = ptr->type;
552 if (t >= event_types.size())
553 PanicAlertT("Invalid event type %i", t)MsgAlert(false, WARNING, "Invalid event type %i", t);
554
555 const char *name = event_types[ptr->type].name;
556 if (!name)
557 name = "[unknown]";
Value stored to 'name' is never read
558
559 text += StringFromFormat("%s : %i %08x%08x\n", event_types[ptr->type].name, ptr->time, ptr->userdata >> 32, ptr->userdata);
560 ptr = ptr->next;
561 }
562 return text;
563}
564
565u32 GetFakeDecStartValue()
566{
567 return fakeDecStartValue;
568}
569
570void SetFakeDecStartValue(u32 val)
571{
572 fakeDecStartValue = val;
573}
574
575u64 GetFakeDecStartTicks()
576{
577 return fakeDecStartTicks;
578}
579
580void SetFakeDecStartTicks(u64 val)
581{
582 fakeDecStartTicks = val;
583}
584
585u64 GetFakeTBStartValue()
586{
587 return fakeTBStartValue;
588}
589
590void SetFakeTBStartValue(u64 val)
591{
592 fakeTBStartValue = val;
593}
594
595u64 GetFakeTBStartTicks()
596{
597 return fakeTBStartTicks;
598}
599
600void SetFakeTBStartTicks(u64 val)
601{
602 fakeTBStartTicks = val;
603}
604
605} // namespace