~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/HLE/sceKernelEventFlag.cpp

  • 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) 2012- 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
#include "Core/HLE/HLE.h"
 
19
#include "Core/MIPS/MIPS.h"
 
20
#include "Core/CoreTiming.h"
 
21
#include "Core/MemMapHelpers.h"
 
22
#include "Core/Reporting.h"
 
23
#include "Common/ChunkFile.h"
 
24
 
 
25
#include "Core/HLE/sceKernel.h"
 
26
#include "Core/HLE/sceKernelThread.h"
 
27
#include "Core/HLE/sceKernelEventFlag.h"
 
28
#include "Core/HLE/KernelWaitHelpers.h"
 
29
 
 
30
void __KernelEventFlagTimeout(u64 userdata, int cycleslate);
 
31
 
 
32
struct NativeEventFlag {
 
33
        u32_le size;
 
34
        char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
 
35
        u32_le attr;
 
36
        u32_le initPattern;
 
37
        u32_le currentPattern;
 
38
        s32_le numWaitThreads;
 
39
};
 
40
 
 
41
struct EventFlagTh {
 
42
        SceUID threadID;
 
43
        u32 bits;
 
44
        u32 wait;
 
45
        u32 outAddr;
 
46
        u64 pausedTimeout;
 
47
 
 
48
        bool operator ==(const SceUID &otherThreadID) const {
 
49
                return threadID == otherThreadID;
 
50
        }
 
51
};
 
52
 
 
53
class EventFlag : public KernelObject {
 
54
public:
 
55
        const char *GetName() override { return nef.name; }
 
56
        const char *GetTypeName() override { return "EventFlag"; }
 
57
        void GetQuickInfo(char *ptr, int size) override {
 
58
                sprintf(ptr, "init=%08x cur=%08x numwait=%i",
 
59
                        nef.initPattern,
 
60
                        nef.currentPattern,
 
61
                        nef.numWaitThreads);
 
62
        }
 
63
 
 
64
        static u32 GetMissingErrorCode() {
 
65
                return SCE_KERNEL_ERROR_UNKNOWN_EVFID;
 
66
        }
 
67
        static int GetStaticIDType() { return SCE_KERNEL_TMID_EventFlag; }
 
68
        int GetIDType() const override { return SCE_KERNEL_TMID_EventFlag; }
 
69
 
 
70
        void DoState(PointerWrap &p) override {
 
71
                auto s = p.Section("EventFlag", 1);
 
72
                if (!s)
 
73
                        return;
 
74
 
 
75
                p.Do(nef);
 
76
                EventFlagTh eft = { 0 };
 
77
                p.Do(waitingThreads, eft);
 
78
                p.Do(pausedWaits);
 
79
        }
 
80
 
 
81
        NativeEventFlag nef;
 
82
        std::vector<EventFlagTh> waitingThreads;
 
83
        // Key is the callback id it was for, or if no callback, the thread id.
 
84
        std::map<SceUID, EventFlagTh> pausedWaits;
 
85
};
 
86
 
 
87
 
 
88
/** Event flag creation attributes */
 
89
enum PspEventFlagAttributes {
 
90
        /** Allow the event flag to be waited upon by multiple threads */
 
91
        PSP_EVENT_WAITMULTIPLE = 0x200
 
92
};
 
93
 
 
94
/** Event flag wait types */
 
95
enum PspEventFlagWaitTypes {
 
96
        /** Wait for all bits in the pattern to be set */
 
97
        PSP_EVENT_WAITAND = 0x00,
 
98
        /** Wait for one or more bits in the pattern to be set */
 
99
        PSP_EVENT_WAITOR = 0x01,
 
100
        /** Clear the entire pattern when it matches. */
 
101
        PSP_EVENT_WAITCLEARALL = 0x10,
 
102
        /** Clear the wait pattern when it matches */
 
103
        PSP_EVENT_WAITCLEAR = 0x20,
 
104
 
 
105
        PSP_EVENT_WAITKNOWN = PSP_EVENT_WAITCLEAR | PSP_EVENT_WAITCLEARALL | PSP_EVENT_WAITOR,
 
106
};
 
107
 
 
108
static int eventFlagWaitTimer = -1;
 
109
 
 
110
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId);
 
111
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId);
 
112
 
 
113
void __KernelEventFlagInit() {
 
114
        eventFlagWaitTimer = CoreTiming::RegisterEvent("EventFlagTimeout", __KernelEventFlagTimeout);
 
115
        __KernelRegisterWaitTypeFuncs(WAITTYPE_EVENTFLAG, __KernelEventFlagBeginCallback, __KernelEventFlagEndCallback);
 
116
}
 
117
 
 
118
void __KernelEventFlagDoState(PointerWrap &p) {
 
119
        auto s = p.Section("sceKernelEventFlag", 1);
 
120
        if (!s)
 
121
                return;
 
122
 
 
123
        p.Do(eventFlagWaitTimer);
 
124
        CoreTiming::RestoreRegisterEvent(eventFlagWaitTimer, "EventFlagTimeout", __KernelEventFlagTimeout);
 
125
}
 
126
 
 
127
KernelObject *__KernelEventFlagObject() {
 
128
        // Default object to load from state.
 
129
        return new EventFlag;
 
130
}
 
131
 
 
132
static bool __KernelCheckEventFlagMatches(u32 pattern, u32 bits, u8 wait) {
 
133
        // Is this in OR (any bit can match) or AND (all bits must match) mode?
 
134
        if (wait & PSP_EVENT_WAITOR) {
 
135
                return (bits & pattern) != 0;
 
136
        } else {
 
137
                return (bits & pattern) == bits;
 
138
        }
 
139
}
 
140
 
 
141
static bool __KernelApplyEventFlagMatch(u32_le *pattern, u32 bits, u8 wait, u32 outAddr) {
 
142
        if (__KernelCheckEventFlagMatches(*pattern, bits, wait)) {
 
143
                if (Memory::IsValidAddress(outAddr))
 
144
                        Memory::Write_U32(*pattern, outAddr);
 
145
 
 
146
                if (wait & PSP_EVENT_WAITCLEAR)
 
147
                        *pattern &= ~bits;
 
148
                if (wait & PSP_EVENT_WAITCLEARALL)
 
149
                        *pattern = 0;
 
150
                return true;
 
151
        }
 
152
        return false;
 
153
}
 
154
 
 
155
static bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 &error, int result, bool &wokeThreads) {
 
156
        if (!HLEKernel::VerifyWait(th.threadID, WAITTYPE_EVENTFLAG, e->GetUID()))
 
157
                return true;
 
158
 
 
159
        // If result is an error code, we're just letting it go.
 
160
        if (result == 0) {
 
161
                if (!__KernelApplyEventFlagMatch(&e->nef.currentPattern, th.bits, th.wait, th.outAddr))
 
162
                        return false;
 
163
        } else {
 
164
                // Otherwise, we set the current result since we're bailing.
 
165
                if (Memory::IsValidAddress(th.outAddr))
 
166
                        Memory::Write_U32(e->nef.currentPattern, th.outAddr);
 
167
        }
 
168
 
 
169
        u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.threadID, error);
 
170
        if (timeoutPtr != 0 && eventFlagWaitTimer != -1) {
 
171
                // Remove any event for this thread.
 
172
                s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, th.threadID);
 
173
                Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr);
 
174
        }
 
175
 
 
176
        __KernelResumeThreadFromWait(th.threadID, result);
 
177
        wokeThreads = true;
 
178
        return true;
 
179
}
 
180
 
 
181
static bool __KernelClearEventFlagThreads(EventFlag *e, int reason) {
 
182
        u32 error;
 
183
        bool wokeThreads = false;
 
184
        std::vector<EventFlagTh>::iterator iter, end;
 
185
        for (iter = e->waitingThreads.begin(), end = e->waitingThreads.end(); iter != end; ++iter)
 
186
                __KernelUnlockEventFlagForThread(e, *iter, error, reason, wokeThreads);
 
187
        e->waitingThreads.clear();
 
188
 
 
189
        return wokeThreads;
 
190
}
 
191
 
 
192
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) {
 
193
        auto result = HLEKernel::WaitBeginCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, eventFlagWaitTimer);
 
194
        if (result == HLEKernel::WAIT_CB_SUCCESS)
 
195
                DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB: Suspending lock wait for callback");
 
196
        else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA)
 
197
                ERROR_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: wait not found to pause for callback");
 
198
        else
 
199
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB: beginning callback with bad wait id?");
 
200
}
 
201
 
 
202
void __KernelEventFlagEndCallback(SceUID threadID, SceUID prevCallbackId) {
 
203
        auto result = HLEKernel::WaitEndCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId, eventFlagWaitTimer, __KernelUnlockEventFlagForThread);
 
204
        if (result == HLEKernel::WAIT_CB_RESUMED_WAIT)
 
205
                DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB: Resuming lock wait from callback");
 
206
}
 
207
 
 
208
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
 
209
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr) {
 
210
        if (!name) {
 
211
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "invalid name");
 
212
        }
 
213
 
 
214
        // These attributes aren't valid.
 
215
        if ((flag_attr & 0x100) != 0 || flag_attr >= 0x300) {
 
216
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr parameter: %08x", flag_attr);
 
217
        }
 
218
 
 
219
        EventFlag *e = new EventFlag();
 
220
        SceUID id = kernelObjects.Create(e);
 
221
 
 
222
        e->nef.size = sizeof(NativeEventFlag);
 
223
        strncpy(e->nef.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
 
224
        e->nef.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
 
225
        e->nef.attr = flag_attr;
 
226
        e->nef.initPattern = flag_initPattern;
 
227
        e->nef.currentPattern = e->nef.initPattern;
 
228
        e->nef.numWaitThreads = 0;
 
229
 
 
230
        if (optPtr != 0) {
 
231
                u32 size = Memory::Read_U32(optPtr);
 
232
                if (size > 4)
 
233
                        WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateEventFlag(%s) unsupported options parameter, size = %d", name, size);
 
234
        }
 
235
        if ((flag_attr & ~PSP_EVENT_WAITMULTIPLE) != 0)
 
236
                WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateEventFlag(%s) unsupported attr parameter: %08x", name, flag_attr);
 
237
 
 
238
        return hleLogSuccessI(SCEKERNEL, id);
 
239
}
 
240
 
 
241
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr) {
 
242
        u32 error;
 
243
        EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
 
244
        if (e) {
 
245
                e->nef.numWaitThreads = (int) e->waitingThreads.size();
 
246
                if (Memory::IsValidAddress(numWaitThreadsPtr))
 
247
                        Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr);
 
248
 
 
249
                e->nef.currentPattern = pattern;
 
250
 
 
251
                if (__KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL))
 
252
                        hleReSchedule("event flag canceled");
 
253
 
 
254
                return hleLogSuccessI(SCEKERNEL, 0);
 
255
        } else {
 
256
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
257
        }
 
258
}
 
259
 
 
260
u32 sceKernelClearEventFlag(SceUID id, u32 bits) {
 
261
        u32 error;
 
262
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
263
        if (e) {
 
264
                e->nef.currentPattern &= bits;
 
265
                // Note that it's not possible for threads to get woken up by this action.
 
266
                hleEatCycles(430);
 
267
                return hleLogSuccessI(SCEKERNEL, 0);
 
268
        } else {
 
269
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
270
        }
 
271
}
 
272
 
 
273
u32 sceKernelDeleteEventFlag(SceUID uid) {
 
274
        u32 error;
 
275
        EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
 
276
        if (e) {
 
277
                bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
 
278
                if (wokeThreads)
 
279
                        hleReSchedule("event flag deleted");
 
280
 
 
281
                return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy<EventFlag>(uid));
 
282
        } else {
 
283
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
284
        }
 
285
}
 
286
 
 
287
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet) {
 
288
        u32 error;
 
289
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
290
        if (e) {
 
291
                bool wokeThreads = false;
 
292
 
 
293
                e->nef.currentPattern |= bitsToSet;
 
294
 
 
295
                for (size_t i = 0; i < e->waitingThreads.size(); ++i) {
 
296
                        EventFlagTh *t = &e->waitingThreads[i];
 
297
                        if (__KernelUnlockEventFlagForThread(e, *t, error, 0, wokeThreads)) {
 
298
                                e->waitingThreads.erase(e->waitingThreads.begin() + i);
 
299
                                // Try the one that used to be in this place next.
 
300
                                --i;
 
301
                        }
 
302
                }
 
303
 
 
304
                if (wokeThreads)
 
305
                        hleReSchedule("event flag set");
 
306
 
 
307
                hleEatCycles(430);
 
308
                return hleLogSuccessI(SCEKERNEL, 0);
 
309
        } else {
 
310
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
311
        }
 
312
}
 
313
 
 
314
void __KernelEventFlagTimeout(u64 userdata, int cycleslate) {
 
315
        SceUID threadID = (SceUID)userdata;
 
316
 
 
317
        // This still needs to set the result pointer from the wait.
 
318
        u32 error;
 
319
        SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
 
320
        u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
 
321
        EventFlag *e = kernelObjects.Get<EventFlag>(flagID, error);
 
322
        if (e) {
 
323
                if (timeoutPtr != 0)
 
324
                        Memory::Write_U32(0, timeoutPtr);
 
325
 
 
326
                for (size_t i = 0; i < e->waitingThreads.size(); i++) {
 
327
                        EventFlagTh *t = &e->waitingThreads[i];
 
328
                        if (t->threadID == threadID) {
 
329
                                bool wokeThreads;
 
330
 
 
331
                                // This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
 
332
                                // The reason is, if it times out, but what it was waiting on is DELETED prior to it
 
333
                                // actually running, it will get a DELETE result instead of a TIMEOUT.
 
334
                                // So, we need to remember it or we won't be able to mark it DELETE instead later.
 
335
                                __KernelUnlockEventFlagForThread(e, *t, error, SCE_KERNEL_ERROR_WAIT_TIMEOUT, wokeThreads);
 
336
                                break;
 
337
                        }
 
338
                }
 
339
        }
 
340
}
 
341
 
 
342
static void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr) {
 
343
        if (timeoutPtr == 0 || eventFlagWaitTimer == -1)
 
344
                return;
 
345
 
 
346
        int micro = (int) Memory::Read_U32(timeoutPtr);
 
347
 
 
348
        // This seems like the actual timing of timeouts on hardware.
 
349
        if (micro <= 1)
 
350
                micro = 25;
 
351
        else if (micro <= 209)
 
352
                micro = 240;
 
353
 
 
354
        // This should call __KernelEventFlagTimeout() later, unless we cancel it.
 
355
        CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread());
 
356
}
 
357
 
 
358
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) {
 
359
        if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) {
 
360
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait);
 
361
        }
 
362
        // Can't wait on 0, that's guaranteed to wait forever.
 
363
        if (bits == 0) {
 
364
                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern");
 
365
        }
 
366
 
 
367
        if (!__KernelIsDispatchEnabled()) {
 
368
                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled");
 
369
        }
 
370
 
 
371
        u32 error;
 
372
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
373
        if (e) {
 
374
                EventFlagTh th;
 
375
                if (!__KernelApplyEventFlagMatch(&e->nef.currentPattern, bits, wait, outBitsPtr)) {
 
376
                        // If this thread was left in waitingThreads after a timeout, remove it.
 
377
                        // Otherwise we might write the outBitsPtr in the wrong place.
 
378
                        HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread());
 
379
 
 
380
                        u32 timeout = 0xFFFFFFFF;
 
381
                        if (Memory::IsValidAddress(timeoutPtr))
 
382
                                timeout = Memory::Read_U32(timeoutPtr);
 
383
 
 
384
                        // Do we allow more than one thread to wait?
 
385
                        if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) {
 
386
                                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI);
 
387
                        }
 
388
 
 
389
                        (void)hleLogSuccessI(SCEKERNEL, 0, "waiting");
 
390
 
 
391
                        // No match - must wait.
 
392
                        th.threadID = __KernelGetCurThread();
 
393
                        th.bits = bits;
 
394
                        th.wait = wait;
 
395
                        // If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
 
396
                        th.outAddr = timeout == 0 ? 0 : outBitsPtr;
 
397
                        e->waitingThreads.push_back(th);
 
398
 
 
399
                        __KernelSetEventFlagTimeout(e, timeoutPtr);
 
400
                        __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, false, "event flag waited");
 
401
                } else {
 
402
                        (void)hleLogSuccessI(SCEKERNEL, 0);
 
403
                }
 
404
 
 
405
                hleEatCycles(600);
 
406
                return 0;
 
407
        } else {
 
408
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
409
        }
 
410
}
 
411
 
 
412
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) {
 
413
        if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) {
 
414
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait);
 
415
        }
 
416
        // Can't wait on 0, that's guaranteed to wait forever.
 
417
        if (bits == 0) {
 
418
                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern");
 
419
        }
 
420
 
 
421
        if (!__KernelIsDispatchEnabled()) {
 
422
                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_CAN_NOT_WAIT, "dispatch disabled");
 
423
        }
 
424
 
 
425
        u32 error;
 
426
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
427
        if (e) {
 
428
                EventFlagTh th;
 
429
                // We only check, not apply here.  This way the CLEAR/etc. options don't apply yet.
 
430
                // If we run callbacks, we will check again after the callbacks complete.
 
431
                bool doWait = !__KernelCheckEventFlagMatches(e->nef.currentPattern, bits, wait);
 
432
                bool doCallbackWait = false;
 
433
                if (__KernelCurHasReadyCallbacks()) {
 
434
                        doWait = true;
 
435
                        doCallbackWait = true;
 
436
                }
 
437
 
 
438
                if (doWait) {
 
439
                        // If this thread was left in waitingThreads after a timeout, remove it.
 
440
                        // Otherwise we might write the outBitsPtr in the wrong place.
 
441
                        HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread());
 
442
 
 
443
                        u32 timeout = 0xFFFFFFFF;
 
444
                        if (Memory::IsValidAddress(timeoutPtr))
 
445
                                timeout = Memory::Read_U32(timeoutPtr);
 
446
 
 
447
                        // Do we allow more than one thread to wait?
 
448
                        if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) {
 
449
                                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI);
 
450
                        }
 
451
 
 
452
                        (void)hleLogSuccessI(SCEKERNEL, 0, "waiting");
 
453
 
 
454
                        // No match - must wait.
 
455
                        th.threadID = __KernelGetCurThread();
 
456
                        th.bits = bits;
 
457
                        th.wait = wait;
 
458
                        // If < 5ms, sometimes hardware doesn't write this, but it's unpredictable.
 
459
                        th.outAddr = timeout == 0 ? 0 : outBitsPtr;
 
460
                        e->waitingThreads.push_back(th);
 
461
 
 
462
                        __KernelSetEventFlagTimeout(e, timeoutPtr);
 
463
                        if (doCallbackWait)
 
464
                                __KernelWaitCallbacksCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr);
 
465
                        else
 
466
                                __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited");
 
467
                } else {
 
468
                        (void)hleLogSuccessI(SCEKERNEL, 0);
 
469
                        __KernelApplyEventFlagMatch(&e->nef.currentPattern, bits, wait, outBitsPtr);
 
470
                        hleCheckCurrentCallbacks();
 
471
                }
 
472
 
 
473
                return 0;
 
474
        } else {
 
475
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
476
        }
 
477
}
 
478
 
 
479
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr) {
 
480
        if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) {
 
481
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait);
 
482
        }
 
483
        // Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait.
 
484
        if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0) {
 
485
                return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode parameter: %08x", wait);
 
486
        }
 
487
        // Can't wait on 0, it never matches.
 
488
        if (bits == 0) {
 
489
                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_ILPAT, "bad pattern");
 
490
        }
 
491
 
 
492
        u32 error;
 
493
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
494
        if (e) {
 
495
                if (!__KernelApplyEventFlagMatch(&e->nef.currentPattern, bits, wait, outBitsPtr)) {
 
496
                        if (Memory::IsValidAddress(outBitsPtr))
 
497
                                Memory::Write_U32(e->nef.currentPattern, outBitsPtr);
 
498
 
 
499
                        if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) {
 
500
                                return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_MULTI);
 
501
                        }
 
502
 
 
503
                        // No match - return that, this is polling, not waiting.
 
504
                        return hleLogDebug(SCEKERNEL, SCE_KERNEL_ERROR_EVF_COND);
 
505
                } else {
 
506
                        return hleLogSuccessI(SCEKERNEL, 0);
 
507
                }
 
508
        } else {
 
509
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
510
        }
 
511
}
 
512
 
 
513
//int sceKernelReferEventFlagStatus(SceUID event, SceKernelEventFlagInfo *status);
 
514
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr) {
 
515
        u32 error;
 
516
        EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
 
517
        if (e) {
 
518
                if (!Memory::IsValidAddress(statusPtr))
 
519
                        return hleLogWarning(SCEKERNEL, -1, "invalid ptr");
 
520
 
 
521
                HLEKernel::CleanupWaitingThreads(WAITTYPE_EVENTFLAG, id, e->waitingThreads);
 
522
 
 
523
                e->nef.numWaitThreads = (int) e->waitingThreads.size();
 
524
                if (Memory::Read_U32(statusPtr) != 0)
 
525
                        Memory::WriteStruct(statusPtr, &e->nef);
 
526
                return hleLogSuccessI(SCEKERNEL, 0);
 
527
        } else {
 
528
                return hleLogDebug(SCEKERNEL, error, "invalid event flag");
 
529
        }
 
530
}