the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2
3
4#include "C4JThread.h"
5#ifdef __PSVITA__
6#include "..\Minecraft.Client\PSVita\PSVitaExtras\ShutdownManager.h"
7#include "..\Minecraft.Client\PSVita\PSVitaExtras\PSVitaTLSStorage.h"
8
9// AP - this comes from the low level user_malloc.c file used to overide the default memory functions. These must be called when a thread is started/stopped
10extern "C" {
11extern void user_registerthread();
12extern void user_removethread();
13}
14#else
15#include "..\Minecraft.Client\PS3\PS3Extras\ShutdownManager.h"
16
17#endif
18
19std::vector<C4JThread*> C4JThread::ms_threadList;
20CRITICAL_SECTION C4JThread::ms_threadListCS;
21
22#ifdef _XBOX_ONE
23 // 4J Stu - On XboxOne the main thread is not the one that does all the static init, so we have to set this up later
24C4JThread *C4JThread::m_mainThread = NULL;
25
26void C4JThread::StaticInit()
27{
28 m_mainThread = new C4JThread("Main thread");
29}
30#else
31C4JThread C4JThread::m_mainThread("Main thread");
32#endif
33
34#ifdef __ORBIS__
35__thread SceKernelCpumask C4JThread::m_oldAffinityMask;
36#endif
37
38
39#if __PSVITA__
40static SceInt32 g_DefaultCPU;
41static SceInt32 g_DefaultPriority;
42#endif
43
44C4JThread::C4JThread( C4JThreadStartFunc* startFunc, void* param, const char* threadName, int stackSize/* = 0*/ )
45{
46 m_startFunc = startFunc;
47 m_threadParam = param;
48 m_stackSize = stackSize;
49
50 // to match XBox, if the stack size is zero, use the default 64k
51 if(m_stackSize == 0)
52 m_stackSize = 65536 * 2;
53 // make sure it's at least 16K
54 if(m_stackSize < 16384)
55 m_stackSize = 16384;
56
57#ifdef __PS3__
58 sprintf(m_threadName, "(4J) %s", threadName );
59#else
60 sprintf_s(m_threadName,64, "(4J) %s", threadName );
61#endif
62
63 m_isRunning = false;
64 m_hasStarted = false;
65
66 m_exitCode = STILL_ACTIVE;
67
68#ifdef __PS3__
69 m_completionFlag = new Event(Event::e_modeManualClear);
70 m_threadID = 0;
71 m_lastSleepTime = 0;
72 m_priority = 1002; // main thread has priority 1001
73#elif defined __ORBIS__
74 m_completionFlag = new Event(Event::e_modeManualClear);
75 m_threadID = 0;
76 m_lastSleepTime = 0;
77 scePthreadAttrInit(&m_threadAttr);
78 int err = scePthreadAttrSetaffinity(&m_threadAttr, 63); // set the thread affinity to all cores to start with
79 assert(err == SCE_OK);
80 m_oldAffinityMask = 0;
81 m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT;
82#elif defined __PSVITA__
83 m_completionFlag = new Event(Event::e_modeManualClear);
84 m_threadID = 0;
85 m_lastSleepTime = 0;
86 m_priority = g_DefaultPriority;
87 //m_CPUMask = SCE_KERNEL_CPU_MASK_USER_ALL;
88
89 // AP - I had trouble getting the cpu to change once the thread was created so I've hard coded them here
90 // The main work division is...
91 // 0 - Main
92 // 1 - Chunk/Tile Update
93 // 2 - Server/Audio
94 // These three can sometimes consume ALL the CPU time so they are set to below average priority so as not to block other critical threads
95 int CPU = SCE_KERNEL_CPU_MASK_USER_ALL;
96 if( !strcmp(threadName, "Chunk update") )
97 {
98 CPU = SCE_KERNEL_CPU_MASK_USER_2;
99 m_priority = g_DefaultPriority + 1;
100 }
101 if( !strcmp(threadName, "Server" ) )
102 {
103 CPU = SCE_KERNEL_CPU_MASK_USER_1;
104 m_priority = g_DefaultPriority + 1;
105 }
106 // make sure Tile Update doesn't go on cpu 0 because it will hold up the main thread. And it can't go on cpu 1 because Chunk Update crashes.
107 if( !strcmp(threadName, "Tile update") )
108 {
109 CPU = SCE_KERNEL_CPU_MASK_USER_1;
110 }
111
112 m_threadID = sceKernelCreateThread(m_threadName, entryPoint, g_DefaultPriority, m_stackSize, 0, CPU, NULL);
113 app.DebugPrintf("***************************** start thread %s **************************\n", m_threadName);
114#else
115 m_threadID = 0;
116 m_threadHandle = 0;
117 m_threadHandle = CreateThread(NULL, m_stackSize, entryPoint, this, CREATE_SUSPENDED, &m_threadID);
118#endif
119 EnterCriticalSection(&ms_threadListCS);
120 ms_threadList.push_back(this);
121 LeaveCriticalSection(&ms_threadListCS);
122}
123
124// only used for the main thread
125C4JThread::C4JThread( const char* mainThreadName)
126{
127#ifdef __PSVITA__
128 user_registerthread();
129#endif
130
131 m_startFunc = NULL;
132 m_threadParam = NULL;
133 m_stackSize = 0;
134
135#ifdef __PS3__
136 sprintf(m_threadName, "(4J) %s", mainThreadName);
137#else
138 sprintf_s(m_threadName, 64, "(4J) %s", mainThreadName);
139#endif
140 m_isRunning = true;
141 m_hasStarted = true;
142 m_lastSleepTime = System::currentTimeMillis();
143
144 // should be the first thread to be created, so init the static critical section for the threadlist here
145 InitializeCriticalSection(&ms_threadListCS);
146
147
148#ifdef __PS3__
149 m_completionFlag = new Event(Event::e_modeManualClear);
150 sys_ppu_thread_get_id(&m_threadID);
151#elif defined __ORBIS__
152 m_completionFlag = new Event(Event::e_modeManualClear);
153 m_threadID = scePthreadSelf();
154 m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT;
155#elif defined __PSVITA__
156 m_completionFlag = new Event(Event::e_modeManualClear);
157 g_DefaultPriority = sceKernelGetThreadCurrentPriority();
158 m_threadID = sceKernelGetThreadId();
159 int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, SCE_KERNEL_CPU_MASK_USER_0);
160// sceKernelChangeThreadPriority(m_threadID, g_DefaultPriority + 1);
161 g_DefaultCPU = SCE_KERNEL_CPU_MASK_USER_ALL;//sceKernelGetThreadCpuAffinityMask(m_threadID);
162#else
163 m_threadID = GetCurrentThreadId();
164 m_threadHandle = GetCurrentThread();
165#endif
166#ifdef _XBOX_ONE
167 SetThreadName(-1, m_threadName);
168#endif
169 EnterCriticalSection(&ms_threadListCS);
170 ms_threadList.push_back(this);
171 LeaveCriticalSection(&ms_threadListCS);
172}
173
174C4JThread::~C4JThread()
175{
176#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
177 delete m_completionFlag;
178#endif
179
180#if defined __ORBIS__
181 scePthreadJoin(m_threadID, NULL);
182#endif
183
184 EnterCriticalSection(&ms_threadListCS);
185
186 for( AUTO_VAR(it,ms_threadList.begin()); it != ms_threadList.end(); it++ )
187 {
188 if( (*it) == this )
189 {
190 ms_threadList.erase(it);
191 LeaveCriticalSection(&ms_threadListCS);
192 return;
193 }
194 }
195
196 LeaveCriticalSection(&ms_threadListCS);
197}
198
199#ifdef __PS3__
200void C4JThread::entryPoint(uint64_t param)
201{
202 C4JThread* pThread = (C4JThread*)param;
203 pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
204 pThread->m_completionFlag->Set();
205 pThread->m_isRunning = false;
206 sys_ppu_thread_exit(0);
207}
208#elif defined __ORBIS__
209void * C4JThread::entryPoint(void *param)
210{
211 C4JThread* pThread = (C4JThread*)param;
212 pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
213 pThread->m_completionFlag->Set();
214 pThread->m_isRunning = false;
215 scePthreadExit(NULL);
216}
217#elif defined __PSVITA__
218struct StrArg {
219 C4JThread* Thread;
220};
221
222SceInt32 C4JThread::entryPoint(SceSize argSize, void *pArgBlock)
223{
224 StrArg *strArg = (StrArg*)pArgBlock;
225 C4JThread* pThread = strArg->Thread;
226 user_registerthread();
227 pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
228 app.DebugPrintf("***************************** thread exit %s **************************\n", pThread->m_threadName);
229 pThread->m_completionFlag->Set();
230 pThread->m_isRunning = false;
231
232 // AP - make sure we clean up this thread's storage and memory
233 PSVitaTLSStorage::RemoveThread(pThread->m_threadID);
234 user_removethread();
235
236 sceKernelExitDeleteThread(NULL);
237
238 return pThread->m_exitCode;
239}
240#else
241DWORD WINAPI C4JThread::entryPoint(LPVOID lpParam)
242{
243 C4JThread* pThread = (C4JThread*)lpParam;
244 SetThreadName(-1, pThread->m_threadName);
245 pThread->m_exitCode = (*pThread->m_startFunc)(pThread->m_threadParam);
246 pThread->m_isRunning = false;
247 return pThread->m_exitCode;
248}
249#endif
250
251
252
253
254void C4JThread::Run()
255{
256#ifdef __PS3__
257 // prio specifies the priority value of the PPU thread within the range from 0 to 3071 where 0 is the highest.
258 // One of the following values is set to flags:
259 // 0 - non-joinable non-interrupt thread
260 // SYS_PPU_THREAD_CREATE_JOINABLE - Create a joinable thread
261 // SYS_PPU_THREAD_CREATE_INTERRUPT - Create an interrupt thread
262 uint64_t flags = 0;
263 int err = sys_ppu_thread_create(&m_threadID, entryPoint, (uint64_t)this, m_priority, m_stackSize, flags, m_threadName);
264#elif defined __ORBIS__
265 scePthreadAttrSetstacksize(&m_threadAttr, m_stackSize);
266 scePthreadAttrSetguardsize(&m_threadAttr, 1024);
267 int ret = scePthreadCreate(&m_threadID, &m_threadAttr, entryPoint, this, m_threadName);
268 assert( ret == SCE_OK );
269 scePthreadSetprio(m_threadID,m_priority);
270 scePthreadAttrDestroy(&m_threadAttr);
271#elif defined __PSVITA__
272 StrArg strArg = {this};
273// m_threadID = sceKernelCreateThread(m_threadName, entryPoint, m_priority, m_stackSize, 0, m_CPUMask, NULL);
274 sceKernelStartThread( m_threadID, sizeof(strArg), &strArg);
275#else
276 ResumeThread(m_threadHandle);
277#endif
278 m_lastSleepTime = System::currentTimeMillis();
279 m_isRunning = true;
280 m_hasStarted = true;
281}
282
283void C4JThread::SetProcessor( int proc )
284{
285#ifdef __PS3__
286 // does nothing since we only have the 1 processor
287#elif defined __ORBIS__
288 scePthreadAttrSetaffinity(&m_threadAttr, 1 << proc);
289#elif defined __PSVITA__
290 int Proc = proc >> 1; // convert from 360's 3 cores * 2 hardware threads to Vita's 3 cores
291 int Mask = SCE_KERNEL_CPU_MASK_USER_0 << Proc;
292 //m_CPUMask = Mask;
293// int err = sceKernelChangeThreadCpuAffinityMask(m_threadID, Mask);
294 int Newmask = sceKernelGetThreadCpuAffinityMask(m_threadID);
295 app.DebugPrintf("***************************** set thread proc %s %d %d %d **************************\n", m_threadName, proc, Mask, Newmask);
296#elif defined _DURANGO
297 SetThreadAffinityMask(m_threadHandle, 1 << proc );
298#else
299 XSetThreadProcessor( m_threadHandle, proc);
300#endif
301}
302
303void C4JThread::SetPriority( int priority )
304{
305#ifdef __PS3__
306 switch(priority)
307 {
308 case THREAD_PRIORITY_LOWEST: m_priority = 1003; break;
309 case THREAD_PRIORITY_BELOW_NORMAL: m_priority = 1002; break;
310 case THREAD_PRIORITY_NORMAL: m_priority = 1001; break; // same as main thread
311 case THREAD_PRIORITY_ABOVE_NORMAL: m_priority = 1000; break;
312 case THREAD_PRIORITY_HIGHEST: m_priority = 999; break;
313 }
314 if(m_threadID != 0)
315 sys_ppu_thread_set_priority(m_threadID, m_priority);
316 //int erro = sys_ppu_thread_set_priority(m_threadID, priority);
317#elif defined __ORBIS__
318
319 switch(priority)
320 {
321 case THREAD_PRIORITY_LOWEST: m_priority = SCE_KERNEL_PRIO_FIFO_LOWEST; break;
322 case THREAD_PRIORITY_BELOW_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_LOWEST + ((SCE_KERNEL_PRIO_FIFO_DEFAULT-SCE_KERNEL_PRIO_FIFO_LOWEST)/2); break;
323 case THREAD_PRIORITY_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT; break; // same as main thread
324 case THREAD_PRIORITY_ABOVE_NORMAL: m_priority = SCE_KERNEL_PRIO_FIFO_DEFAULT + ((SCE_KERNEL_PRIO_FIFO_HIGHEST-SCE_KERNEL_PRIO_FIFO_DEFAULT)/2); break;
325 case THREAD_PRIORITY_HIGHEST: m_priority = SCE_KERNEL_PRIO_FIFO_HIGHEST; break;
326 }
327
328 if( m_threadID != 0 )
329 {
330 scePthreadSetprio(m_threadID,m_priority);
331 }
332#elif defined __PSVITA__
333 int Mid = g_DefaultPriority;//(SCE_KERNEL_LOWEST_PRIORITY_USER + SCE_KERNEL_HIGHEST_PRIORITY_USER) / 2;
334 switch(priority)
335 {
336 case THREAD_PRIORITY_LOWEST:
337 m_priority = SCE_KERNEL_LOWEST_PRIORITY_USER;
338 break;
339 case THREAD_PRIORITY_BELOW_NORMAL:
340 m_priority = Mid + 1;
341 break;
342 case THREAD_PRIORITY_NORMAL:
343 m_priority = Mid;
344 break; // same as main thread
345 case THREAD_PRIORITY_ABOVE_NORMAL:
346 m_priority = Mid - 1;
347 break;
348 case THREAD_PRIORITY_HIGHEST:
349 m_priority = SCE_KERNEL_HIGHEST_PRIORITY_USER;
350 break;
351 }
352
353// sceKernelChangeThreadPriority(m_threadID, m_priority);
354 app.DebugPrintf("***************************** set thread prio %s %d %d **************************\n", m_threadName, priority, m_priority);
355#else
356 SetThreadPriority(m_threadHandle, priority);
357#endif // __PS3__
358}
359
360DWORD C4JThread::WaitForCompletion( int timeoutMs )
361{
362#ifdef __PS3__
363 if(timeoutMs == INFINITE)
364 timeoutMs = SYS_NO_TIMEOUT ;
365 return m_completionFlag->WaitForSignal(timeoutMs);
366#elif defined __ORBIS__
367 return m_completionFlag->WaitForSignal( timeoutMs );
368#elif defined __PSVITA__
369 return m_completionFlag->WaitForSignal( timeoutMs );
370/* SceUInt32 Timeout = timeoutMs * 1000;
371 SceInt32 err = sceKernelWaitThreadEnd(m_threadID, &m_exitCode, &Timeout);
372 if( err == 0 )
373 {
374 return m_exitCode;
375 }
376 else
377 {
378 if( err == SCE_KERNEL_ERROR_WAIT_TIMEOUT )
379 {
380 return WAIT_TIMEOUT;
381 }
382 else
383 {
384 // AP - not sure what to do here
385 return 0;
386 }
387 }*/
388
389// return m_exitCode;
390#else
391 return WaitForSingleObject(m_threadHandle, timeoutMs);
392#endif // __PS3__
393}
394
395int C4JThread::GetExitCode()
396{
397#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
398 return m_exitCode;
399#else
400 DWORD exitcode = 0;
401 GetExitCodeThread(m_threadHandle, &exitcode);
402
403 return *((int *)&exitcode);
404#endif
405}
406
407void C4JThread::Sleep( int millisecs )
408{
409#ifdef __PS3__
410 if(millisecs == 0)
411 {
412 // https://ps3.scedev.net/forums/thread/116470/
413 // "sys_timer_usleep(0) does not yield the CPU."
414 sys_ppu_thread_yield();
415 }
416 else
417 sys_timer_usleep(millisecs * 1000);
418#elif defined __ORBIS__
419 sceKernelUsleep(((SceKernelUseconds)millisecs) * 1000);
420#elif defined __PSVITA__
421 // 4J Stu - 0 is an error, so add a tiny sleep when we just want to yield
422 sceKernelDelayThread(millisecs * 1000 + 1);
423#else
424 ::Sleep(millisecs);
425#endif // __PS3__
426}
427
428C4JThread* C4JThread::getCurrentThread()
429{
430#ifdef __PS3__
431 sys_ppu_thread_t currThreadID;
432 sys_ppu_thread_get_id(&currThreadID);
433#elif defined __ORBIS__
434 ScePthread currThreadID = scePthreadSelf();
435#elif defined __PSVITA__
436 SceUID currThreadID = sceKernelGetThreadId();
437#else
438 DWORD currThreadID = GetCurrentThreadId();
439#endif //__PS3__
440 EnterCriticalSection(&ms_threadListCS);
441
442 for(int i=0;i<ms_threadList.size(); i++)
443 {
444 if(currThreadID == ms_threadList[i]->m_threadID)
445 {
446 LeaveCriticalSection(&ms_threadListCS);
447 return ms_threadList[i];
448 }
449 }
450
451 LeaveCriticalSection(&ms_threadListCS);
452
453 return NULL;
454}
455
456bool C4JThread::isMainThread()
457{
458#ifdef _XBOX_ONE
459 return getCurrentThread() == m_mainThread;
460#else
461 return getCurrentThread() == &m_mainThread;
462#endif
463}
464
465C4JThread::Event::Event(EMode mode/* = e_modeAutoClear*/)
466{
467 m_mode = mode;
468#ifdef __PS3__
469 sys_event_flag_attribute_t attr;
470 // default values taken from sys_event_flag_attribute_initialize
471 attr.attr_protocol = SYS_SYNC_PRIORITY;
472 attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED;
473 attr.key = 0;
474 attr.flags = 0;
475 attr.type = SYS_SYNC_WAITER_SINGLE;
476 attr.name[0] = '\0';
477 sys_event_flag_attribute_initialize(attr);
478
479 int err = sys_event_flag_create(&m_event, &attr, 0);
480
481#elif defined __ORBIS__
482 char name[1] = {0};
483 sceKernelCreateEventFlag( &m_event, name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
484#elif defined __PSVITA__
485 char name[1] = {0};
486 m_event = sceKernelCreateEventFlag( name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
487#else
488 m_event = CreateEvent( NULL, (m_mode == e_modeManualClear), FALSE, NULL );
489#endif //__PS3__
490}
491
492
493C4JThread::Event::~Event()
494{
495#ifdef __PS3__
496 sys_event_flag_destroy(m_event);
497#elif defined __ORBIS__
498 sceKernelDeleteEventFlag(m_event);
499#elif defined __PSVITA__
500 sceKernelDeleteEventFlag(m_event);
501#else
502 CloseHandle( m_event );
503#endif // __PS3__
504}
505
506
507void C4JThread::Event::Set()
508{
509#ifdef __PS3__
510 int err =sys_event_flag_set(m_event, 1);
511#elif defined __ORBIS__
512 sceKernelSetEventFlag(m_event, 1);
513#elif defined __PSVITA__
514 sceKernelSetEventFlag(m_event, 1);
515#else
516 SetEvent(m_event);
517#endif //__PS3__
518}
519
520void C4JThread::Event::Clear()
521{
522#ifdef __PS3__
523 int err =sys_event_flag_clear(m_event, ~(1));
524#elif defined __ORBIS__
525 sceKernelClearEventFlag(m_event, ~(1));
526#elif defined __PSVITA__
527 sceKernelClearEventFlag(m_event, ~1);
528#else
529 ResetEvent(m_event);
530#endif //__PS3__
531}
532
533DWORD C4JThread::Event::WaitForSignal( int timeoutMs )
534{
535#ifdef __PS3__
536 if(timeoutMs == INFINITE)
537 timeoutMs = SYS_NO_TIMEOUT ;
538 int timoutMicrosecs = timeoutMs * 1000;
539 uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
540 if(m_mode == e_modeAutoClear)
541 mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
542 int err = sys_event_flag_wait(m_event, 1, mode, 0, timoutMicrosecs);
543
544 switch(err)
545 {
546 case CELL_OK: return WAIT_OBJECT_0;
547 case ETIMEDOUT: return WAIT_TIMEOUT;
548 case ECANCELED: return WAIT_ABANDONED;
549 default: return WAIT_FAILED;
550 }
551
552#elif defined __ORBIS__
553 SceKernelUseconds timeoutMicrosecs;
554 SceKernelUseconds *pTimeoutMicrosecs;
555 if( timeoutMs == INFINITE )
556 {
557 pTimeoutMicrosecs = NULL;
558 }
559 else
560 {
561 timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
562 pTimeoutMicrosecs = &timeoutMicrosecs;
563 }
564 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
565 if(m_mode == e_modeAutoClear)
566 {
567 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
568 }
569 int err = sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs);
570 switch(err)
571 {
572 case SCE_OK: return WAIT_OBJECT_0;
573 case SCE_KERNEL_ERROR_ETIMEDOUT: return WAIT_TIMEOUT;
574 case SCE_KERNEL_ERROR_ECANCELED: return WAIT_ABANDONED;
575 default: return WAIT_FAILED;
576 }
577#elif defined __PSVITA__
578 SceUInt32 timeoutMicrosecs;
579 SceUInt32 *pTimeoutMicrosecs;
580 if( timeoutMs == INFINITE )
581 {
582 pTimeoutMicrosecs = NULL;
583 }
584 else
585 {
586 timeoutMicrosecs = ((SceInt32)timeoutMs) * 1000;
587 pTimeoutMicrosecs = &timeoutMicrosecs;
588 }
589 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
590 if(m_mode == e_modeAutoClear)
591 {
592 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
593 }
594 int err = sceKernelWaitEventFlag(m_event, 1, waitMode, NULL, pTimeoutMicrosecs);
595 switch(err)
596 {
597 case SCE_OK: return WAIT_OBJECT_0;
598 case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
599 case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
600 default: return WAIT_FAILED;
601 }
602#else
603 return WaitForSingleObject(m_event, timeoutMs);
604#endif // __PS3__
605}
606
607C4JThread::EventArray::EventArray( int size, EMode mode/* = e_modeAutoClear*/)
608{
609 assert(size<32);
610 m_size = size;
611 m_mode = mode;
612#ifdef __PS3__
613 sys_event_flag_attribute_t attr;
614 // default values taken from sys_event_flag_attribute_initialize
615 attr.attr_protocol = SYS_SYNC_PRIORITY;
616 attr.attr_pshared = SYS_SYNC_NOT_PROCESS_SHARED;
617 attr.key = 0;
618 attr.flags = 0;
619 attr.type = SYS_SYNC_WAITER_SINGLE;
620 attr.name[0] = '\0';
621 sys_event_flag_attribute_initialize(attr);
622 int err = sys_event_flag_create(&m_events, &attr, 0);
623 assert(err == CELL_OK);
624#elif defined __ORBIS__
625 char name[1] = {0};
626 sceKernelCreateEventFlag( &m_events, name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
627#elif defined __PSVITA__
628 char name[1] = {0};
629 m_events = sceKernelCreateEventFlag( name, SCE_KERNEL_EVF_ATTR_TH_FIFO | SCE_KERNEL_EVF_ATTR_MULTI, 0, NULL);
630#else
631 m_events = new HANDLE[size];
632 for(int i=0;i<size;i++)
633 {
634 m_events[i] = CreateEvent(NULL, (m_mode == e_modeManualClear), FALSE, NULL );
635 }
636#endif // __PS3__
637}
638
639
640void C4JThread::EventArray::Set(int index)
641{
642#ifdef __PS3__
643 int err =sys_event_flag_set(m_events, 1<<index);
644 assert(err == CELL_OK);
645#elif defined __ORBIS__
646 sceKernelSetEventFlag(m_events, 1<<index);
647#elif defined __PSVITA__
648 sceKernelSetEventFlag(m_events, 1<<index);
649#else
650 SetEvent(m_events[index]);
651#endif //__PS3__
652}
653
654void C4JThread::EventArray::Clear(int index)
655{
656#ifdef __PS3__
657 int err =sys_event_flag_clear(m_events, ~(1<<index));
658 assert(err == CELL_OK);
659#elif defined __ORBIS__
660 sceKernelClearEventFlag(m_events, ~(1<<index));
661#elif defined __PSVITA__
662 sceKernelClearEventFlag(m_events, ~(1<<index));
663#else
664 ResetEvent(m_events[index]);
665#endif //__PS3__
666}
667
668void C4JThread::EventArray::SetAll()
669{
670 for(int i=0;i<m_size;i++)
671 Set(i);
672}
673
674void C4JThread::EventArray::ClearAll()
675{
676 for(int i=0;i<m_size;i++)
677 Clear(i);
678}
679
680DWORD C4JThread::EventArray::WaitForSingle(int index, int timeoutMs )
681{
682 DWORD retVal;
683#ifdef __PS3__
684 int timeoutMicrosecs;
685 if(timeoutMs == INFINITE)
686 timeoutMicrosecs = SYS_NO_TIMEOUT;
687 else
688 timeoutMicrosecs = timeoutMs * 1000;
689 uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
690 if(m_mode == e_modeAutoClear)
691 mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
692
693 int err = sys_event_flag_wait(m_events, 1<<index, mode, 0, timeoutMicrosecs);
694
695 switch(err)
696 {
697 case CELL_OK:
698 retVal = WAIT_OBJECT_0;
699 break;
700 case ETIMEDOUT:
701 retVal = WAIT_TIMEOUT;
702 break;
703 case ECANCELED:
704 retVal = WAIT_ABANDONED;
705 break;
706 default:
707 assert(0);
708 retVal = WAIT_FAILED;
709 break;
710 }
711#elif defined __ORBIS__
712 SceKernelUseconds timeoutMicrosecs;
713 SceKernelUseconds *pTimeoutMicrosecs;
714 if( timeoutMs == INFINITE )
715 {
716 pTimeoutMicrosecs = NULL;
717 }
718 else
719 {
720 timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
721 pTimeoutMicrosecs = &timeoutMicrosecs;
722 }
723 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
724 if(m_mode == e_modeAutoClear)
725 {
726 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
727 }
728 uint64_t resultPat;
729 int err = sceKernelWaitEventFlag(m_events, 1<<index, waitMode, &resultPat, pTimeoutMicrosecs);
730 assert(err != SCE_KERNEL_ERROR_ETIMEDOUT);
731 switch(err)
732 {
733 case SCE_OK:
734 retVal = WAIT_OBJECT_0;
735 break;
736 case SCE_KERNEL_ERROR_ETIMEDOUT:
737 retVal = WAIT_TIMEOUT;
738 break;
739 case SCE_KERNEL_ERROR_ECANCELED:
740 retVal = WAIT_ABANDONED;
741 break;
742 default:
743 retVal = WAIT_FAILED;
744 break;
745 }
746#elif defined __PSVITA__
747 SceUInt32 timeoutMicrosecs;
748 SceUInt32 *pTimeoutMicrosecs;
749 if( timeoutMs == INFINITE )
750 {
751 pTimeoutMicrosecs = NULL;
752 }
753 else
754 {
755 timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
756 pTimeoutMicrosecs = &timeoutMicrosecs;
757 }
758 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
759 if(m_mode == e_modeAutoClear)
760 {
761 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
762 }
763 int err = sceKernelWaitEventFlag(m_events, 1<<index, waitMode, NULL, pTimeoutMicrosecs);
764 switch(err)
765 {
766 case SCE_OK: return WAIT_OBJECT_0;
767 case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
768 case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
769 default: return WAIT_FAILED;
770 }
771#else
772 retVal = WaitForSingleObject(m_events[index], timeoutMs);
773#endif // __PS3__
774
775 return retVal;
776}
777
778DWORD C4JThread::EventArray::WaitForAll(int timeoutMs )
779{
780 DWORD retVal;
781#ifdef __PS3__
782 if(timeoutMs == INFINITE)
783 timeoutMs = SYS_NO_TIMEOUT ;
784 int timoutMicrosecs = timeoutMs * 1000;
785 unsigned int bitmask = 0;
786 for(int i=0;i<m_size;i++)
787 bitmask |= (1<<i);
788
789 uint32_t mode = SYS_EVENT_FLAG_WAIT_AND;
790 if(m_mode == e_modeAutoClear)
791 mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
792
793 int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs);
794
795 switch(err)
796 {
797 case CELL_OK:
798 retVal = WAIT_OBJECT_0;
799 break;
800 case ETIMEDOUT:
801 retVal = WAIT_TIMEOUT;
802 break;
803 case ECANCELED:
804 retVal = WAIT_ABANDONED;
805 break;
806 default:
807 assert(0);
808 retVal = WAIT_FAILED;
809 break;
810 }
811
812#elif defined __ORBIS__
813 SceKernelUseconds timeoutMicrosecs;
814 SceKernelUseconds *pTimeoutMicrosecs;
815 if( timeoutMs == INFINITE )
816 {
817 pTimeoutMicrosecs = NULL;
818 }
819 else
820 {
821 timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
822 pTimeoutMicrosecs = &timeoutMicrosecs;
823 }
824 unsigned int bitmask = 0;
825 for(int i=0;i<m_size;i++)
826 bitmask |= (1<<i);
827 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
828 if(m_mode == e_modeAutoClear)
829 {
830 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
831 }
832 int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
833 switch(err)
834 {
835 case SCE_OK:
836 retVal = WAIT_OBJECT_0;
837 break;
838 case SCE_KERNEL_ERROR_ETIMEDOUT:
839 retVal = WAIT_TIMEOUT;
840 break;
841 case SCE_KERNEL_ERROR_ECANCELED:
842 retVal = WAIT_ABANDONED;
843 break;
844 default:
845 retVal = WAIT_FAILED;
846 break;
847 }
848#elif defined __PSVITA__
849 SceUInt32 timeoutMicrosecs;
850 SceUInt32 *pTimeoutMicrosecs;
851 if( timeoutMs == INFINITE )
852 {
853 pTimeoutMicrosecs = NULL;
854 }
855 else
856 {
857 timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
858 pTimeoutMicrosecs = &timeoutMicrosecs;
859 }
860 unsigned int bitmask = 0;
861 for(int i=0;i<m_size;i++)
862 bitmask |= (1<<i);
863 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_AND;
864 if(m_mode == e_modeAutoClear)
865 {
866 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
867 }
868 int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
869 switch(err)
870 {
871 case SCE_OK: return WAIT_OBJECT_0;
872 case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
873 case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
874 default: return WAIT_FAILED;
875 }
876#else
877 retVal = WaitForMultipleObjects(m_size, m_events, true, timeoutMs);
878#endif // __PS3__
879
880 return retVal;
881}
882
883DWORD C4JThread::EventArray::WaitForAny(int timeoutMs )
884{
885#ifdef __PS3__
886 if(timeoutMs == INFINITE)
887 timeoutMs = SYS_NO_TIMEOUT ;
888 int timoutMicrosecs = timeoutMs * 1000;
889 unsigned int bitmask = 0;
890 for(int i=0;i<m_size;i++)
891 bitmask |= (1<<i);
892
893 uint32_t mode = SYS_EVENT_FLAG_WAIT_OR;
894 if(m_mode == e_modeAutoClear)
895 mode |= SYS_EVENT_FLAG_WAIT_CLEAR;
896
897 int err = sys_event_flag_wait(m_events, bitmask, mode, 0, timoutMicrosecs);
898
899 switch(err)
900 {
901 case CELL_OK: return WAIT_OBJECT_0;
902 case ETIMEDOUT: return WAIT_TIMEOUT;
903 case ECANCELED: return WAIT_ABANDONED;
904 default:
905 assert(0);
906 return WAIT_FAILED;
907 }
908
909#elif defined __ORBIS__
910 SceKernelUseconds timeoutMicrosecs;
911 SceKernelUseconds *pTimeoutMicrosecs;
912 if( timeoutMs == INFINITE )
913 {
914 pTimeoutMicrosecs = NULL;
915 }
916 else
917 {
918 timeoutMicrosecs = ((SceKernelUseconds)timeoutMs) * 1000;
919 pTimeoutMicrosecs = &timeoutMicrosecs;
920 }
921 unsigned int bitmask = 0;
922 for(int i=0;i<m_size;i++)
923 bitmask |= (1<<i);
924 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR;
925 if(m_mode == e_modeAutoClear)
926 {
927 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT;
928 }
929 int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
930 switch(err)
931 {
932 case SCE_OK: return WAIT_OBJECT_0;
933 case SCE_KERNEL_ERROR_ETIMEDOUT: return WAIT_TIMEOUT;
934 case SCE_KERNEL_ERROR_ECANCELED: return WAIT_ABANDONED;
935 default: return WAIT_FAILED;
936 }
937#elif defined __PSVITA__
938 SceUInt32 timeoutMicrosecs;
939 SceUInt32 *pTimeoutMicrosecs;
940 if( timeoutMs == INFINITE )
941 {
942 pTimeoutMicrosecs = NULL;
943 }
944 else
945 {
946 timeoutMicrosecs = ((SceUInt32)timeoutMs) * 1000;
947 pTimeoutMicrosecs = &timeoutMicrosecs;
948 }
949 unsigned int bitmask = 0;
950 for(int i=0;i<m_size;i++)
951 bitmask |= (1<<i);
952 uint32_t waitMode = SCE_KERNEL_EVF_WAITMODE_OR;
953 if(m_mode == e_modeAutoClear)
954 {
955 waitMode |= SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL;
956 }
957 int err = sceKernelWaitEventFlag(m_events, bitmask, waitMode, NULL, pTimeoutMicrosecs);
958 switch(err)
959 {
960 case SCE_OK: return WAIT_OBJECT_0;
961 case SCE_KERNEL_ERROR_WAIT_TIMEOUT: return WAIT_TIMEOUT;
962 case SCE_KERNEL_ERROR_WAIT_CANCEL: return WAIT_ABANDONED;
963 default: return WAIT_FAILED;
964 }
965#else
966 return WaitForMultipleObjects(m_size, m_events, false, timeoutMs);
967#endif // __PS3__
968}
969
970#ifdef __PS3__
971void C4JThread::EventArray::Cancel()
972{
973 sys_event_flag_cancel(m_events, NULL);
974}
975#endif
976
977
978
979
980C4JThread::EventQueue::EventQueue( UpdateFunc* updateFunc, ThreadInitFunc threadInitFunc, const char* szThreadName)
981{
982 m_updateFunc = updateFunc;
983 m_threadInitFunc = threadInitFunc;
984 strcpy(m_threadName, szThreadName);
985 m_thread = NULL;
986 m_startEvent = NULL;
987 m_finishedEvent = NULL;
988 m_processor = -1;
989 m_priority = THREAD_PRIORITY_HIGHEST+1;
990}
991
992void C4JThread::EventQueue::init()
993{
994 m_startEvent = new C4JThread::EventArray(1);
995 m_finishedEvent = new C4JThread::Event();
996 InitializeCriticalSection(&m_critSect);
997 m_thread = new C4JThread(threadFunc, this, m_threadName);
998 if(m_processor >= 0)
999 m_thread->SetProcessor(m_processor);
1000 if(m_priority != THREAD_PRIORITY_HIGHEST+1)
1001 m_thread->SetPriority(m_priority);
1002 m_thread->Run();
1003}
1004
1005void C4JThread::EventQueue::sendEvent( Level* pLevel )
1006{
1007 if(m_thread == NULL)
1008 init();
1009 EnterCriticalSection(&m_critSect);
1010 m_queue.push(pLevel);
1011 m_startEvent->Set(0);
1012 m_finishedEvent->Clear();
1013 LeaveCriticalSection(&m_critSect);
1014}
1015
1016void C4JThread::EventQueue::waitForFinish()
1017{
1018 if(m_thread == NULL)
1019 init();
1020 EnterCriticalSection(&m_critSect);
1021 if(m_queue.empty())
1022 {
1023 LeaveCriticalSection((&m_critSect));
1024 return;
1025 }
1026 LeaveCriticalSection((&m_critSect));
1027 m_finishedEvent->WaitForSignal(INFINITE);
1028}
1029
1030int C4JThread::EventQueue::threadFunc( void* lpParam )
1031{
1032 EventQueue* p = (EventQueue*)lpParam;
1033 p->threadPoll();
1034 return 0;
1035}
1036
1037void C4JThread::EventQueue::threadPoll()
1038{
1039 ShutdownManager::HasStarted(ShutdownManager::eEventQueueThreads, m_startEvent);
1040
1041 if(m_threadInitFunc)
1042 m_threadInitFunc();
1043
1044 while(ShutdownManager::ShouldRun(ShutdownManager::eEventQueueThreads))
1045 {
1046
1047 DWORD err = m_startEvent->WaitForAny(INFINITE);
1048 if(err == WAIT_OBJECT_0)
1049 {
1050 bool bListEmpty = true;
1051 do
1052 {
1053 EnterCriticalSection(&m_critSect);
1054 void* updateParam = m_queue.front();
1055 LeaveCriticalSection(&m_critSect);
1056
1057 m_updateFunc(updateParam);
1058
1059 EnterCriticalSection(&m_critSect);
1060 m_queue.pop();
1061 bListEmpty = m_queue.empty();
1062 if(bListEmpty)
1063 {
1064 m_finishedEvent->Set();
1065 }
1066 LeaveCriticalSection(&m_critSect);
1067
1068 } while(!bListEmpty);
1069 }
1070 };
1071
1072 ShutdownManager::HasFinished(ShutdownManager::eEventQueueThreads);
1073}
1074
1075
1076#ifdef __ORBIS__
1077
1078void C4JThread::PushAffinityAllCores()
1079{
1080 assert(m_oldAffinityMask == 0);
1081 int err;
1082 ScePthread currThreadID = scePthreadSelf();
1083 err = scePthreadGetaffinity(currThreadID, &m_oldAffinityMask);
1084 assert(err == SCE_OK);
1085 err = scePthreadSetaffinity(currThreadID, 63);
1086 assert(err == SCE_OK);
1087
1088
1089}
1090
1091void C4JThread::PopAffinity()
1092{
1093 int err;
1094 ScePthread currThreadID = scePthreadSelf();
1095 err = scePthreadSetaffinity(currThreadID, m_oldAffinityMask);
1096 m_oldAffinityMask = 0;
1097 assert(err == SCE_OK);
1098}
1099
1100#endif // __ORBIS__