eathread_semaphore_kettle.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EABase/eabase.h>
  5. #include <eathread/eathread_semaphore.h>
  6. #if defined(EA_PLATFORM_SONY)
  7. #include <kernel/semaphore.h>
  8. #include <sceerror.h>
  9. EASemaphoreData::EASemaphoreData()
  10. : mSemaphore(NULL), mnMaxCount(INT_MAX), mnCount(0)
  11. {
  12. }
  13. EA::Thread::SemaphoreParameters::SemaphoreParameters(int initialCount, bool bIntraProcess, const char* pName)
  14. : mInitialCount(initialCount), mMaxCount(INT_MAX), mbIntraProcess(bIntraProcess)
  15. {
  16. // Maximum lenght for the semaphore name on Kettle is 32 (including NULL terminator)
  17. EAT_COMPILETIME_ASSERT(sizeof(mName) <= 32);
  18. if (pName)
  19. {
  20. strncpy(mName, pName, sizeof(mName)-1);
  21. mName[sizeof(mName)-1] = 0;
  22. }
  23. else
  24. {
  25. mName[0] = 0;
  26. }
  27. }
  28. EA::Thread::Semaphore::Semaphore(const SemaphoreParameters* pSemaphoreParameters, bool bDefaultParameters)
  29. {
  30. if (!pSemaphoreParameters && bDefaultParameters)
  31. {
  32. SemaphoreParameters parameters;
  33. Init(&parameters);
  34. }
  35. else
  36. {
  37. Init(pSemaphoreParameters);
  38. }
  39. }
  40. EA::Thread::Semaphore::Semaphore(int initialCount)
  41. {
  42. SemaphoreParameters parameters(initialCount);
  43. Init(&parameters);
  44. }
  45. EA::Thread::Semaphore::~Semaphore()
  46. {
  47. int result = sceKernelDeleteSema(mSemaphoreData.mSemaphore);
  48. EAT_ASSERT(result == SCE_OK); EA_UNUSED(result);
  49. }
  50. bool EA::Thread::Semaphore::Init(const SemaphoreParameters* pSemaphoreParameters)
  51. {
  52. if (pSemaphoreParameters
  53. && pSemaphoreParameters->mInitialCount >= 0
  54. && pSemaphoreParameters->mMaxCount >= 0)
  55. {
  56. mSemaphoreData.mnMaxCount = pSemaphoreParameters->mMaxCount;
  57. mSemaphoreData.mnCount = pSemaphoreParameters->mInitialCount;
  58. int result = sceKernelCreateSema(
  59. &mSemaphoreData.mSemaphore,
  60. pSemaphoreParameters->mName,
  61. SCE_KERNEL_SEMA_ATTR_TH_FIFO,
  62. mSemaphoreData.mnCount,
  63. mSemaphoreData.mnMaxCount,
  64. NULL);
  65. if (result == SCE_OK)
  66. return true;
  67. }
  68. // Failure: could not create semaphore
  69. return false;
  70. }
  71. int EA::Thread::Semaphore::Wait(const ThreadTime& timeoutAbsolute)
  72. {
  73. int result = 0;
  74. // Convert timeout from absolute to relative (possibly losing some capacity)
  75. SceKernelUseconds timeoutRelativeUs = static_cast<SceKernelUseconds>(RelativeTimeoutFromAbsoluteTimeout(timeoutAbsolute));
  76. do
  77. {
  78. if (timeoutAbsolute == kTimeoutImmediate)
  79. {
  80. result = sceKernelPollSema(mSemaphoreData.mSemaphore, 1);
  81. }
  82. else
  83. {
  84. result = sceKernelWaitSema(mSemaphoreData.mSemaphore, 1, &timeoutRelativeUs);
  85. }
  86. if (result != SCE_OK)
  87. {
  88. // SCE_KERNEL_ERROR_ETIMEDOUT is the failure case for 'sceKernelWaitSema'
  89. // SCE_KERNEL_ERROR_EBUSY is the failure case for 'sceKernelPollSema'
  90. // We want to consume the SCE_KERNEL_ERROR_EBUSY error code from the polling interface
  91. // users have a consistent error code to check against.
  92. if (result == SCE_KERNEL_ERROR_ETIMEDOUT || result == SCE_KERNEL_ERROR_EBUSY)
  93. {
  94. if (timeoutAbsolute != kTimeoutNone)
  95. return kResultTimeout;
  96. }
  97. else
  98. {
  99. EAT_FAIL_MSG("Semaphore::Wait: sceKernelWaitSema failure.");
  100. return kResultError;
  101. }
  102. }
  103. } while (result != SCE_OK);
  104. // Success
  105. EAT_ASSERT(mSemaphoreData.mnCount.GetValue() > 0);
  106. return static_cast<int>(mSemaphoreData.mnCount.Decrement());
  107. }
  108. int EA::Thread::Semaphore::Post(int count)
  109. {
  110. EAT_ASSERT(count >= 0);
  111. const int currentCount = mSemaphoreData.mnCount;
  112. if (count > 0)
  113. {
  114. // If count would cause an overflow exit early
  115. if ((mSemaphoreData.mnMaxCount - count) < currentCount)
  116. return kResultError;
  117. // We increment the count before we signal the semaphore so that any waken up
  118. // thread will have the right count immediately
  119. mSemaphoreData.mnCount.Add(count);
  120. int result = sceKernelSignalSema(mSemaphoreData.mSemaphore, count);
  121. if (result != SCE_OK)
  122. {
  123. // If not successful set the count back
  124. mSemaphoreData.mnCount.Add(-count);
  125. return kResultError;
  126. }
  127. }
  128. return currentCount + count; // It's possible that another thread may have modified this value since we changed it, but that's not important.
  129. }
  130. int EA::Thread::Semaphore::GetCount() const
  131. {
  132. // There is no way to query the semaphore for the resource count on Kettle,
  133. // we need to rely on our external atomic counter
  134. return mSemaphoreData.mnCount.GetValue();
  135. }
  136. #endif // EA_PLATFORM_SONY