| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include <eathread/eathread_futex.h>
- #include <new>
- #if defined(EA_THREAD_NONTHREADED_FUTEX) && EA_THREAD_NONTHREADED_FUTEX
- void EA::Thread::Futex::CreateFSemaphore()
- {
- mSemaphore.mnCount = 0;
- }
- void EA::Thread::Futex::DestroyFSemaphore()
- {
- // Do nothing;
- }
- void EA::Thread::Futex::SignalFSemaphore()
- {
- mSemaphore.mnCount++;
- }
- void EA::Thread::Futex::WaitFSemaphore()
- {
- while(mSemaphore.mnCount <= 0)
- EA_THREAD_DO_SPIN();
- mSemaphore.mnCount--;
- }
- bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime&)
- {
- WaitFSemaphore();
- return true;
- }
- #elif defined(EA_PLATFORM_APPLE) && EATHREAD_MANUAL_FUTEX_ENABLED
- #include <semaphore.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <libkern/OSAtomic.h>
- void EA::Thread::Futex::CreateFSemaphore()
- {
- mSemaphore.Init(0);
- }
- void EA::Thread::Futex::DestroyFSemaphore()
- {
- // Do nothing;
- }
- void EA::Thread::Futex::SignalFSemaphore()
- {
- mSemaphore.Post();
- }
- void EA::Thread::Futex::WaitFSemaphore()
- {
- mSemaphore.Wait();
- }
- bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
- {
- return (mSemaphore.Wait(timeoutAbsolute) >= 0);
- }
- #elif defined(EA_PLATFORM_SONY) && !EATHREAD_MANUAL_FUTEX_ENABLED
- #include <kernel.h>
- #include <eathread/eathread_atomic.h>
- EA::Thread::Futex::Futex()
- : mSpinCount(EATHREAD_FUTEX_SPIN_COUNT)
- {
- }
- EA::Thread::Futex::~Futex()
- {
- }
- void EA::Thread::Futex::Lock()
- {
- Uint spinCount(mSpinCount);
- while(--spinCount)
- {
- if(TryLock())
- return;
- }
- mMutex.Lock();
- }
- void EA::Thread::Futex::Unlock()
- {
- mMutex.Unlock();
- }
- bool EA::Thread::Futex::TryLock()
- {
- if(mMutex.Lock(EA::Thread::kTimeoutImmediate) > 0) // This calls scePthreadMutexTrylock
- return true;
- return false;
- }
- int EA::Thread::Futex::Lock(const ThreadTime& timeoutAbsolute)
- {
- return mMutex.Lock(timeoutAbsolute);
- }
- int EA::Thread::Futex::GetLockCount() const
- {
- return mMutex.GetLockCount();
- }
- bool EA::Thread::Futex::HasLock() const
- {
- return mMutex.HasLock();
- }
- void EA::Thread::Futex::SetSpinCount(Uint spinCount)
- {
- mSpinCount = spinCount;
- }
- #elif defined(EA_PLATFORM_SONY) && EATHREAD_MANUAL_FUTEX_ENABLED
- #include <kernel/semaphore.h>
- #include <sceerror.h>
- void EA::Thread::Futex::CreateFSemaphore()
- {
- // To consider: Copy the Futex name into this semaphore name.
- int result = sceKernelCreateSema(&mSemaphore, "Futex", SCE_KERNEL_SEMA_ATTR_TH_FIFO, 0, 100000, NULL);
- EA_UNUSED(result);
- EAT_ASSERT(result == SCE_OK);
- }
- void EA::Thread::Futex::DestroyFSemaphore()
- {
- int result = sceKernelDeleteSema(mSemaphore);
- EA_UNUSED(result);
- EAT_ASSERT(result == SCE_OK);
- }
- void EA::Thread::Futex::SignalFSemaphore()
- {
- int result = sceKernelSignalSema(mSemaphore, 1);
- EA_UNUSED(result);
- EAT_ASSERT(result == SCE_OK);
- }
- void EA::Thread::Futex::WaitFSemaphore()
- {
- int result = sceKernelWaitSema(mSemaphore, 1, NULL);
- EA_UNUSED(result);
- EAT_ASSERT(result == SCE_OK);
- }
- bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
- {
- SceKernelUseconds timeoutRelativeUs = static_cast<SceKernelUseconds>(RelativeTimeoutFromAbsoluteTimeout(timeoutAbsolute));
- if(timeoutRelativeUs < 1)
- timeoutRelativeUs = 1;
- return (sceKernelWaitSema(mSemaphore, 1, &timeoutRelativeUs) == SCE_OK);
- }
- #elif (defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE) && EATHREAD_MANUAL_FUTEX_ENABLED
- #include <semaphore.h>
- #include <errno.h>
- void EA::Thread::Futex::CreateFSemaphore()
- {
- const int result = sem_init(&mSemaphore, 0, 0);
- (void)result;
- EAT_ASSERT(result != -1);
- }
- void EA::Thread::Futex::DestroyFSemaphore()
- {
- #if defined (EA_PLATFORM_APPLE)
- sem_close(&mSemaphore);
- #elif defined(EA_PLATFORM_ANDROID)
- sem_destroy(&mSemaphore); // Android's sem_destroy is broken. http://code.google.com/p/android/issues/detail?id=3106
- #else
- int result = -1;
-
- for(;;)
- {
- result = sem_destroy(&mSemaphore);
- if((result == -1) && (errno == EBUSY)) // If another thread or process is blocked on this semaphore...
- ThreadSleep(kTimeoutYield); // Yield. If we don't yield, it's possible we could block other other threads or processes from running, on some systems.
- else
- break;
- }
- EAT_ASSERT(result != -1);
- #endif
- }
- void EA::Thread::Futex::SignalFSemaphore()
- {
- sem_post(&mSemaphore);
- }
- void EA::Thread::Futex::WaitFSemaphore()
- {
- // We don't have much choice but to retry interrupted waits,
- // as there is no lock failure return value.
- while((sem_wait(&mSemaphore) == -1) && (errno == EINTR))
- continue;
- }
- bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime&)
- {
- WaitFSemaphore();
- return true;
- }
- #elif defined(EA_PLATFORM_MICROSOFT) && !EA_USE_CPP11_CONCURRENCY && !EATHREAD_MANUAL_FUTEX_ENABLED
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <Windows.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- // Validate what we assume to be invariants.
- EAT_COMPILETIME_ASSERT(sizeof(CRITICAL_SECTION) <= (EA::Thread::FUTEX_PLATFORM_DATA_SIZE / sizeof(uint64_t) * sizeof(uint64_t)));
- #if defined(EA_PLATFORM_MICROSOFT) && defined(EA_PROCESSOR_X86_64)
- EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, RecursionCount) == (3 * sizeof(int)));
- EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, OwningThread) == (4 * sizeof(int)));
- #elif defined(EA_PLATFORM_WIN32)
- EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, RecursionCount) == (2 * sizeof(int)));
- EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, OwningThread) == (3 * sizeof(int)));
- #else
- EAT_FAIL_MSG("Need to verify offsetof.");
- #endif
- #elif defined(EA_PLATFORM_MICROSOFT) && EATHREAD_MANUAL_FUTEX_ENABLED
- #if defined(EA_PLATFORM_WINDOWS)
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <Windows.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- #endif
- void EA::Thread::Futex::CreateFSemaphore()
- {
- mSemaphore = CreateSemaphoreA(NULL, 0, INT_MAX / 2, NULL);
- EAT_ASSERT(mSemaphore != 0);
- }
- void EA::Thread::Futex::DestroyFSemaphore()
- {
- if(mSemaphore)
- CloseHandle(mSemaphore);
- }
- void EA::Thread::Futex::SignalFSemaphore()
- {
- ReleaseSemaphore(mSemaphore, 1, NULL);
- }
- void EA::Thread::Futex::WaitFSemaphore()
- {
- WaitForSingleObject(mSemaphore, INFINITE);
- }
- bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
- {
- int64_t timeoutRelativeMS = (int64_t)(timeoutAbsolute - GetThreadTime());
- if(timeoutRelativeMS < 1)
- timeoutRelativeMS = 1;
- return WaitForSingleObject(mSemaphore, (DWORD)timeoutRelativeMS) == WAIT_OBJECT_0;
- }
- #endif
- namespace EA
- {
- namespace Thread
- {
- extern Allocator* gpAllocator;
- }
- }
- EA::Thread::Futex* EA::Thread::FutexFactory::CreateFutex()
- {
- if(gpAllocator)
- return new(gpAllocator->Alloc(sizeof(EA::Thread::Futex))) EA::Thread::Futex;
- else
- return new EA::Thread::Futex;
- }
- void EA::Thread::FutexFactory::DestroyFutex(EA::Thread::Futex* pFutex)
- {
- if(gpAllocator)
- {
- pFutex->~Futex();
- gpAllocator->Free(pFutex);
- }
- else
- delete pFutex;
- }
- size_t EA::Thread::FutexFactory::GetFutexSize()
- {
- return sizeof(EA::Thread::Futex);
- }
- EA::Thread::Futex* EA::Thread::FutexFactory::ConstructFutex(void* pMemory)
- {
- return new(pMemory) EA::Thread::Futex;
- }
- void EA::Thread::FutexFactory::DestructFutex(EA::Thread::Futex* pFutex)
- {
- pFutex->~Futex();
- }
|