eathread_barrier_kettle.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EABase/eabase.h>
  5. #include <eathread/eathread_barrier.h>
  6. #include <eathread/eathread.h>
  7. #include <kernel.h>
  8. #include <time.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <new>
  12. EABarrierData::EABarrierData()
  13. : mCV(), mMutex(), mnHeight(0), mnCurrent(0), mnCycle(0), mbValid(false)
  14. {}
  15. EA::Thread::BarrierParameters::BarrierParameters(int height, bool bIntraProcess, const char* pName)
  16. : mHeight(height), mbIntraProcess(bIntraProcess)
  17. {
  18. if(pName)
  19. strncpy(mName, pName, sizeof(mName)-1);
  20. else
  21. mName[0] = 0;
  22. }
  23. EA::Thread::Barrier::Barrier(const BarrierParameters* pBarrierParameters, bool bDefaultParameters)
  24. {
  25. if(!pBarrierParameters && bDefaultParameters)
  26. {
  27. BarrierParameters parameters;
  28. Init(&parameters);
  29. }
  30. else
  31. Init(pBarrierParameters);
  32. }
  33. EA::Thread::Barrier::Barrier(int height)
  34. {
  35. BarrierParameters parameters(height);
  36. Init(&parameters);
  37. }
  38. EA::Thread::Barrier::~Barrier()
  39. {
  40. if(mBarrierData.mbValid){
  41. EAT_ASSERT(mBarrierData.mnCurrent == mBarrierData.mnHeight);
  42. int result = scePthreadMutexDestroy(&mBarrierData.mMutex);
  43. EA_UNUSED(result);
  44. EAT_ASSERT(result == 0);
  45. result = scePthreadCondDestroy(&mBarrierData.mCV);
  46. EAT_ASSERT(result == 0);
  47. EA_UNUSED( result ); //if compiling without asserts
  48. }
  49. }
  50. bool EA::Thread::Barrier::Init(const BarrierParameters* pBarrierParameters)
  51. {
  52. if(pBarrierParameters && !mBarrierData.mbValid)
  53. {
  54. mBarrierData.mbValid = false;
  55. mBarrierData.mnHeight = pBarrierParameters->mHeight;
  56. mBarrierData.mnCurrent = pBarrierParameters->mHeight;
  57. mBarrierData.mnCycle = 0;
  58. int result = scePthreadMutexInit(&mBarrierData.mMutex, NULL, pBarrierParameters->mName);
  59. if(result == 0){
  60. result = scePthreadCondInit(&mBarrierData.mCV, NULL, pBarrierParameters->mName);
  61. if(result == 0)
  62. mBarrierData.mbValid = true;
  63. else
  64. scePthreadMutexDestroy(&mBarrierData.mMutex);
  65. }
  66. return mBarrierData.mbValid;
  67. }
  68. return false;
  69. }
  70. EA::Thread::Barrier::Result EA::Thread::Barrier::Wait(const ThreadTime& timeoutAbsolute)
  71. {
  72. if(!mBarrierData.mbValid){
  73. EAT_ASSERT(false);
  74. return kResultError;
  75. }
  76. int result = scePthreadMutexLock(&mBarrierData.mMutex);
  77. if(result != 0){
  78. EAT_ASSERT(false);
  79. return kResultError;
  80. }
  81. const unsigned long nCurrentCycle = (unsigned)mBarrierData.mnCycle;
  82. bool bPrimary = false;
  83. if(--mBarrierData.mnCurrent == 0){ // This is not an atomic operation. We are within a mutex lock.
  84. // The last barrier can never time out, as its action is always immediate.
  85. mBarrierData.mnCycle++;
  86. mBarrierData.mnCurrent = mBarrierData.mnHeight;
  87. result = scePthreadCondBroadcast(&mBarrierData.mCV);
  88. // The last thread into the barrier will return a result of
  89. // kResultPrimary rather than kResultSecondary.
  90. if(result == 0)
  91. bPrimary = true;
  92. //else leave result as an error value.
  93. }
  94. else{
  95. // timeoutMilliseconds
  96. // Wait with cancellation disabled, because pthreads barrier_wait
  97. // should not be a cancellation point.
  98. #if defined(SCE_PTHREAD_CANCEL_DISABLE)
  99. int cancel;
  100. scePthreadSetcancelstate(SCE_PTHREAD_CANCEL_DISABLE, &cancel);
  101. #endif
  102. // Wait until the barrier's cycle changes, which means that
  103. // it has been broadcast, and we don't want to wait anymore.
  104. while(nCurrentCycle == mBarrierData.mnCycle){
  105. do{
  106. // Under SMP systems, pthread_cond_wait can return the success value 'spuriously'.
  107. // This is by design and we must retest the predicate condition and if it has
  108. // not true, we must go back to waiting.
  109. result = scePthreadCondTimedwait(&mBarrierData.mCV, &mBarrierData.mMutex, RelativeTimeoutFromAbsoluteTimeout(timeoutAbsolute));
  110. } while((result == 0) && (nCurrentCycle == mBarrierData.mnCycle));
  111. if(result != 0)
  112. break;
  113. }
  114. #if defined(SCE_PTHREAD_CANCEL_DISABLE)
  115. int cancelTemp;
  116. scePthreadSetcancelstate(cancel, &cancelTemp);
  117. #endif
  118. }
  119. // We declare a new result2 value because the old one
  120. // might have a special value from above in it.
  121. const int result2 = scePthreadMutexUnlock(&mBarrierData.mMutex); (void)result2;
  122. EAT_ASSERT(result2 == 0);
  123. if(result == 0)
  124. return bPrimary ? kResultPrimary : kResultSecondary;
  125. else if(result == ETIMEDOUT)
  126. return kResultTimeout;
  127. return kResultError;
  128. }
  129. EA::Thread::Barrier* EA::Thread::BarrierFactory::CreateBarrier()
  130. {
  131. EA::Thread::Allocator* pAllocator = EA::Thread::GetAllocator();
  132. if(pAllocator)
  133. return new(pAllocator->Alloc(sizeof(EA::Thread::Barrier))) EA::Thread::Barrier;
  134. else
  135. return new EA::Thread::Barrier;
  136. }
  137. void EA::Thread::BarrierFactory::DestroyBarrier(EA::Thread::Barrier* pBarrier)
  138. {
  139. EA::Thread::Allocator* pAllocator = EA::Thread::GetAllocator();
  140. if(pAllocator)
  141. {
  142. pBarrier->~Barrier();
  143. pAllocator->Free(pBarrier);
  144. }
  145. else
  146. delete pBarrier;
  147. }