~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/ThreadEventQueue.h

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2013- PPSSPP Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official git repository and contact information can be found at
 
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
 
17
 
 
18
#pragma once
 
19
 
 
20
#include "base/mutex.h"
 
21
#include "Core/System.h"
 
22
#include "Core/CoreTiming.h"
 
23
#include <deque>
 
24
 
 
25
template <typename B, typename Event, typename EventType, EventType EVENT_INVALID, EventType EVENT_SYNC, EventType EVENT_FINISH>
 
26
struct ThreadEventQueue : public B {
 
27
        ThreadEventQueue() : threadEnabled_(false), eventsRunning_(false), eventsHaveRun_(false) {
 
28
        }
 
29
 
 
30
        void SetThreadEnabled(bool threadEnabled) {
 
31
                threadEnabled_ = threadEnabled;
 
32
        }
 
33
 
 
34
        bool ThreadEnabled() {
 
35
                return threadEnabled_;
 
36
        }
 
37
 
 
38
        void ScheduleEvent(Event ev) {
 
39
                if (threadEnabled_) {
 
40
                        lock_guard guard(eventsLock_);
 
41
                        events_.push_back(ev);
 
42
                        eventsWait_.notify_one();
 
43
                } else {
 
44
                        events_.push_back(ev);
 
45
                }
 
46
 
 
47
                if (!threadEnabled_) {
 
48
                        RunEventsUntil(0);
 
49
                }
 
50
        }
 
51
 
 
52
        bool HasEvents() {
 
53
                if (threadEnabled_) {
 
54
                        lock_guard guard(eventsLock_);
 
55
                        return !events_.empty();
 
56
                } else {
 
57
                        return !events_.empty();
 
58
                }
 
59
        }
 
60
 
 
61
        void NotifyDrain() {
 
62
                if (threadEnabled_) {
 
63
                        lock_guard guard(eventsLock_);
 
64
                        eventsDrain_.notify_one();
 
65
                }
 
66
        }
 
67
 
 
68
        Event GetNextEvent() {
 
69
                if (threadEnabled_) {
 
70
                        lock_guard guard(eventsLock_);
 
71
                        if (events_.empty()) {
 
72
                                NotifyDrain();
 
73
                                return EVENT_INVALID;
 
74
                        }
 
75
 
 
76
                        Event ev = events_.front();
 
77
                        events_.pop_front();
 
78
                        return ev;
 
79
                } else {
 
80
                        if (events_.empty()) {
 
81
                                return EVENT_INVALID;
 
82
                        }
 
83
                        Event ev = events_.front();
 
84
                        events_.pop_front();
 
85
                        return ev;
 
86
                }
 
87
        }
 
88
 
 
89
        void RunEventsUntil(u64 globalticks) {
 
90
                if (!threadEnabled_) {
 
91
                        do {
 
92
                                for (Event ev = GetNextEvent(); EventType(ev) != EVENT_INVALID; ev = GetNextEvent()) {
 
93
                                        ProcessEventIfApplicable(ev, globalticks);
 
94
                                }
 
95
                        } while (CoreTiming::GetTicks() < globalticks);
 
96
                        return;
 
97
                }
 
98
 
 
99
                lock_guard guard(eventsLock_);
 
100
                eventsRunning_ = true;
 
101
                eventsHaveRun_ = true;
 
102
                do {
 
103
                        while (!HasEvents() && !ShouldExitEventLoop()) {
 
104
                                eventsWait_.wait(eventsLock_);
 
105
                        }
 
106
                        // Quit the loop if the queue is drained and coreState has tripped, or threading is disabled.
 
107
                        if (!HasEvents()) {
 
108
                                break;
 
109
                        }
 
110
 
 
111
                        for (Event ev = GetNextEvent(); EventType(ev) != EVENT_INVALID; ev = GetNextEvent()) {
 
112
                                eventsLock_.unlock();
 
113
                                ProcessEventIfApplicable(ev, globalticks);
 
114
                                eventsLock_.lock();
 
115
                        }
 
116
                } while (CoreTiming::GetTicks() < globalticks);
 
117
 
 
118
                // This will force the waiter to check coreState, even if we didn't actually drain.
 
119
                NotifyDrain();
 
120
                eventsRunning_ = false;
 
121
        }
 
122
 
 
123
        void SyncBeginFrame() {
 
124
                if (threadEnabled_) {
 
125
                        lock_guard guard(eventsLock_);
 
126
                        eventsHaveRun_ = false;
 
127
                } else {
 
128
                        eventsHaveRun_ = false;
 
129
                }
 
130
        }
 
131
 
 
132
        inline bool ShouldSyncThread(bool force) {
 
133
                if (!HasEvents())
 
134
                        return false;
 
135
                if (coreState != CORE_RUNNING && !force)
 
136
                        return false;
 
137
 
 
138
                // Don't run if it's not running, but wait for startup.
 
139
                if (!eventsRunning_) {
 
140
                        if (eventsHaveRun_ || coreState == CORE_ERROR || coreState == CORE_POWERDOWN) {
 
141
                                return false;
 
142
                        }
 
143
                }
 
144
 
 
145
                return true;
 
146
        }
 
147
 
 
148
        // Force ignores coreState.
 
149
        void SyncThread(bool force = false) {
 
150
                if (!threadEnabled_) {
 
151
                        return;
 
152
                }
 
153
 
 
154
                lock_guard guard(eventsLock_);
 
155
                // While processing the last event, HasEvents() will be false even while not done.
 
156
                // So we schedule a nothing event and wait for that to finish.
 
157
                ScheduleEvent(EVENT_SYNC);
 
158
                while (ShouldSyncThread(force)) {
 
159
                        eventsDrain_.wait(eventsLock_);
 
160
                }
 
161
        }
 
162
 
 
163
        void FinishEventLoop() {
 
164
                if (!threadEnabled_) {
 
165
                        return;
 
166
                }
 
167
 
 
168
                lock_guard guard(eventsLock_);
 
169
                // Don't schedule a finish if it's not even running.
 
170
                if (eventsRunning_) {
 
171
                        ScheduleEvent(EVENT_FINISH);
 
172
                }
 
173
        }
 
174
 
 
175
protected:
 
176
        virtual void ProcessEvent(Event ev) = 0;
 
177
        virtual bool ShouldExitEventLoop() = 0;
 
178
 
 
179
        inline void ProcessEventIfApplicable(Event &ev, u64 &globalticks) {
 
180
                switch (EventType(ev)) {
 
181
                case EVENT_FINISH:
 
182
                        // Stop waiting.
 
183
                        globalticks = 0;
 
184
                        break;
 
185
 
 
186
                case EVENT_SYNC:
 
187
                        // Nothing special to do, this event it just to wait on, see SyncThread.
 
188
                        break;
 
189
 
 
190
                default:
 
191
                        ProcessEvent(ev);
 
192
                }
 
193
        }
 
194
 
 
195
private:
 
196
        bool threadEnabled_;
 
197
        bool eventsRunning_;
 
198
        bool eventsHaveRun_;
 
199
        std::deque<Event> events_;
 
200
        recursive_mutex eventsLock_;
 
201
        condition_variable eventsWait_;
 
202
        condition_variable eventsDrain_;
 
203
};