SignaledEvent.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "SignaledEvent.h"
  11. #include "RakAssert.h"
  12. #include "RakSleep.h"
  13. #if defined(__GNUC__)
  14. #include <sys/time.h>
  15. #include <unistd.h>
  16. #endif
  17. using namespace RakNet;
  18. SignaledEvent::SignaledEvent()
  19. {
  20. #ifdef _WIN32
  21. eventList=INVALID_HANDLE_VALUE;
  22. #else
  23. isSignaled=false;
  24. #endif
  25. }
  26. SignaledEvent::~SignaledEvent()
  27. {
  28. // Intentionally do not close event, so it doesn't close twice on linux
  29. }
  30. void SignaledEvent::InitEvent(void)
  31. {
  32. #if defined(WINDOWS_PHONE_8) || defined(WINDOWS_STORE_RT)
  33. eventList=CreateEventEx(0, 0, 0, 0);
  34. #elif defined(_WIN32)
  35. eventList=CreateEvent(0, false, false, 0);
  36. #else
  37. #if !defined(ANDROID)
  38. pthread_condattr_init( &condAttr );
  39. pthread_cond_init(&eventList, &condAttr);
  40. #else
  41. pthread_cond_init(&eventList, 0);
  42. #endif
  43. pthread_mutexattr_init( &mutexAttr );
  44. pthread_mutex_init(&hMutex, &mutexAttr);
  45. #endif
  46. }
  47. void SignaledEvent::CloseEvent(void)
  48. {
  49. #ifdef _WIN32
  50. if (eventList!=INVALID_HANDLE_VALUE)
  51. {
  52. CloseHandle(eventList);
  53. eventList=INVALID_HANDLE_VALUE;
  54. }
  55. #else
  56. pthread_cond_destroy(&eventList);
  57. pthread_mutex_destroy(&hMutex);
  58. #if !defined(ANDROID)
  59. pthread_condattr_destroy( &condAttr );
  60. #endif
  61. pthread_mutexattr_destroy( &mutexAttr );
  62. #endif
  63. }
  64. void SignaledEvent::SetEvent(void)
  65. {
  66. #ifdef _WIN32
  67. ::SetEvent(eventList);
  68. #else
  69. // Different from SetEvent which stays signaled.
  70. // We have to record manually that the event was signaled
  71. isSignaledMutex.Lock();
  72. isSignaled=true;
  73. isSignaledMutex.Unlock();
  74. // Unblock waiting threads
  75. pthread_cond_broadcast(&eventList);
  76. #endif
  77. }
  78. void SignaledEvent::WaitOnEvent(int timeoutMs)
  79. {
  80. #ifdef _WIN32
  81. // WaitForMultipleObjects(
  82. // 2,
  83. // eventList,
  84. // false,
  85. // timeoutMs);
  86. WaitForSingleObjectEx(eventList,timeoutMs,FALSE);
  87. #else
  88. // If was previously set signaled, just unset and return
  89. isSignaledMutex.Lock();
  90. if (isSignaled==true)
  91. {
  92. isSignaled=false;
  93. isSignaledMutex.Unlock();
  94. return;
  95. }
  96. isSignaledMutex.Unlock();
  97. //struct timespec ts;
  98. // Else wait for SetEvent to be called
  99. struct timespec ts;
  100. int rc;
  101. struct timeval tp;
  102. rc = gettimeofday(&tp, NULL);
  103. ts.tv_sec = tp.tv_sec;
  104. ts.tv_nsec = tp.tv_usec * 1000;
  105. // #endif
  106. while (timeoutMs > 30)
  107. {
  108. // Wait 30 milliseconds for the signal, then check again.
  109. // This is in case we missed the signal between the top of this function and pthread_cond_timedwait, or after the end of the loop and pthread_cond_timedwait
  110. ts.tv_nsec += 30*1000000;
  111. if (ts.tv_nsec >= 1000000000)
  112. {
  113. ts.tv_nsec -= 1000000000;
  114. ts.tv_sec++;
  115. }
  116. // [SBC] added mutex lock/unlock around cond_timedwait.
  117. // this prevents airplay from generating a whole much of errors.
  118. // not sure how this works on other platforms since according to
  119. // the docs you are suppost to hold the lock before you wait
  120. // on the cond.
  121. pthread_mutex_lock(&hMutex);
  122. pthread_cond_timedwait(&eventList, &hMutex, &ts);
  123. pthread_mutex_unlock(&hMutex);
  124. timeoutMs-=30;
  125. isSignaledMutex.Lock();
  126. if (isSignaled==true)
  127. {
  128. isSignaled=false;
  129. isSignaledMutex.Unlock();
  130. return;
  131. }
  132. isSignaledMutex.Unlock();
  133. }
  134. // Wait the remaining time, and turn off the signal in case it was set
  135. ts.tv_nsec += timeoutMs*1000000;
  136. if (ts.tv_nsec >= 1000000000)
  137. {
  138. ts.tv_nsec -= 1000000000;
  139. ts.tv_sec++;
  140. }
  141. pthread_mutex_lock(&hMutex);
  142. pthread_cond_timedwait(&eventList, &hMutex, &ts);
  143. pthread_mutex_unlock(&hMutex);
  144. isSignaledMutex.Lock();
  145. isSignaled=false;
  146. isSignaledMutex.Unlock();
  147. #endif
  148. }
粤ICP备19079148号