StateQueue.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * Copyright (C) 2012 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG "StateQueue"
  17. //#define LOG_NDEBUG 0
  18. #include "Configuration.h"
  19. #include <time.h>
  20. #include <cutils/atomic.h>
  21. #include <utils/Log.h>
  22. #include "StateQueue.h"
  23. namespace android {
  24. #ifdef STATE_QUEUE_DUMP
  25. void StateQueueObserverDump::dump(int fd)
  26. {
  27. dprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
  28. }
  29. void StateQueueMutatorDump::dump(int fd)
  30. {
  31. dprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
  32. mPushDirty, mPushAck, mBlockedSequence);
  33. }
  34. #endif
  35. // Constructor and destructor
  36. template<typename T> StateQueue<T>::StateQueue() :
  37. mAck(NULL), mCurrent(NULL),
  38. mMutating(&mStates[0]), mExpecting(NULL),
  39. mInMutation(false), mIsDirty(false), mIsInitialized(false)
  40. #ifdef STATE_QUEUE_DUMP
  41. , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump)
  42. #endif
  43. {
  44. atomic_init(&mNext, static_cast<uintptr_t>(0));
  45. }
  46. template<typename T> StateQueue<T>::~StateQueue()
  47. {
  48. }
  49. // Observer APIs
  50. template<typename T> const T* StateQueue<T>::poll()
  51. {
  52. const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire);
  53. if (next != mCurrent) {
  54. mAck = next; // no additional barrier needed
  55. mCurrent = next;
  56. #ifdef STATE_QUEUE_DUMP
  57. mObserverDump->mStateChanges++;
  58. #endif
  59. }
  60. return next;
  61. }
  62. // Mutator APIs
  63. template<typename T> T* StateQueue<T>::begin()
  64. {
  65. ALOG_ASSERT(!mInMutation, "begin() called when in a mutation");
  66. mInMutation = true;
  67. return mMutating;
  68. }
  69. template<typename T> void StateQueue<T>::end(bool didModify)
  70. {
  71. ALOG_ASSERT(mInMutation, "end() called when not in a mutation");
  72. ALOG_ASSERT(mIsInitialized || didModify, "first end() must modify for initialization");
  73. if (didModify) {
  74. mIsDirty = true;
  75. mIsInitialized = true;
  76. }
  77. mInMutation = false;
  78. }
  79. template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block)
  80. {
  81. #define PUSH_BLOCK_ACK_NS 3000000L // 3 ms: time between checks for ack in push()
  82. // FIXME should be configurable
  83. static const struct timespec req = {0, PUSH_BLOCK_ACK_NS};
  84. ALOG_ASSERT(!mInMutation, "push() called when in a mutation");
  85. #ifdef STATE_QUEUE_DUMP
  86. if (block == BLOCK_UNTIL_ACKED) {
  87. mMutatorDump->mPushAck++;
  88. }
  89. #endif
  90. if (mIsDirty) {
  91. #ifdef STATE_QUEUE_DUMP
  92. mMutatorDump->mPushDirty++;
  93. #endif
  94. // wait for prior push to be acknowledged
  95. if (mExpecting != NULL) {
  96. #ifdef STATE_QUEUE_DUMP
  97. unsigned count = 0;
  98. #endif
  99. for (;;) {
  100. const T *ack = (const T *) mAck; // no additional barrier needed
  101. if (ack == mExpecting) {
  102. // unnecessary as we're about to rewrite
  103. //mExpecting = NULL;
  104. break;
  105. }
  106. if (block == BLOCK_NEVER) {
  107. return false;
  108. }
  109. #ifdef STATE_QUEUE_DUMP
  110. if (count == 1) {
  111. mMutatorDump->mBlockedSequence++;
  112. }
  113. ++count;
  114. #endif
  115. nanosleep(&req, NULL);
  116. }
  117. #ifdef STATE_QUEUE_DUMP
  118. if (count > 1) {
  119. mMutatorDump->mBlockedSequence++;
  120. }
  121. #endif
  122. }
  123. // publish
  124. atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release);
  125. mExpecting = mMutating;
  126. // copy with circular wraparound
  127. if (++mMutating >= &mStates[kN]) {
  128. mMutating = &mStates[0];
  129. }
  130. *mMutating = *mExpecting;
  131. mIsDirty = false;
  132. }
  133. // optionally wait for this push or a prior push to be acknowledged
  134. if (block == BLOCK_UNTIL_ACKED) {
  135. if (mExpecting != NULL) {
  136. #ifdef STATE_QUEUE_DUMP
  137. unsigned count = 0;
  138. #endif
  139. for (;;) {
  140. const T *ack = (const T *) mAck; // no additional barrier needed
  141. if (ack == mExpecting) {
  142. mExpecting = NULL;
  143. break;
  144. }
  145. #ifdef STATE_QUEUE_DUMP
  146. if (count == 1) {
  147. mMutatorDump->mBlockedSequence++;
  148. }
  149. ++count;
  150. #endif
  151. nanosleep(&req, NULL);
  152. }
  153. #ifdef STATE_QUEUE_DUMP
  154. if (count > 1) {
  155. mMutatorDump->mBlockedSequence++;
  156. }
  157. #endif
  158. }
  159. }
  160. return true;
  161. }
  162. } // namespace android
  163. // hack for gcc
  164. #ifdef STATE_QUEUE_INSTANTIATIONS
  165. #include STATE_QUEUE_INSTANTIATIONS
  166. #endif