Index: base/debug/activity_tracker_unittest.cc |
diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc |
index c36d8fac352cb169759d9a9e07db5c9648860010..4b357ad0f1d932fe12a25512c785d8bbb444d8f3 100644 |
--- a/base/debug/activity_tracker_unittest.cc |
+++ b/base/debug/activity_tracker_unittest.cc |
@@ -13,9 +13,11 @@ |
#include "base/files/scoped_temp_dir.h" |
#include "base/memory/ptr_util.h" |
#include "base/pending_task.h" |
+#include "base/rand_util.h" |
#include "base/synchronization/condition_variable.h" |
#include "base/synchronization/lock.h" |
#include "base/synchronization/spin_wait.h" |
+#include "base/threading/platform_thread.h" |
#include "base/threading/simple_thread.h" |
#include "base/time/time.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -37,9 +39,137 @@ class TestActivityTracker : public ThreadActivityTracker { |
std::unique_ptr<char[]> mem_segment_; |
}; |
+ |
+// The interval between which the Queue threads will wait for the queue to |
+// become full or empty. It's prime so that it won't correspond to any other |
+// interval (except itself). |
+const int kQueueTestOperationInterval = 997; |
+ |
+class QueuePushThread : public SimpleThread { |
+ public: |
+ QueuePushThread(LockFreeSimpleQueue<int>* queue, int count) |
+ : SimpleThread("QueuePush", Options()), queue_(queue), count_(count) {} |
+ ~QueuePushThread() override {} |
+ |
+ void Run() override { |
+ int yield_after = RandInt(1, queue_->size() * 2); |
+ for (int i = 0; i < count_; ++i) { |
+ // Two ways of pushing: check for full first or check for failed push. |
+ if (i % 1 == 0) { |
manzagop (departed)
2016/08/23 16:02:03
This is always true?
bcwhite
2016/08/23 16:12:41
Fixed. I had changed in while testing the test an
|
+ // Will fail if full; keep trying. |
+ while (!queue_->push(i)) |
+ ; |
+ } else { |
+ // This is valid because there is exactly one thread pushing. |
+ while (queue_->full()) |
+ ; |
+ DCHECK(queue_->push(i)); |
+ } |
+ |
+ // Take a break once in a while. |
+ if (--yield_after <= 0) { |
+ PlatformThread::YieldCurrentThread(); |
+ yield_after = RandInt(1, queue_->size() * 2); |
+ } |
+ |
+ // Every so often, wait for the queue to empty. |
+ if (i < count_ - kQueueTestOperationInterval && |
+ i % kQueueTestOperationInterval == kQueueTestOperationInterval - 1) { |
+ while (!queue_->empty()) |
manzagop (departed)
2016/08/23 16:02:03
Is it guaranteed that the popper is still alive? S
bcwhite
2016/08/23 16:12:41
There's no protection against thread-death in the
manzagop (departed)
2016/08/23 19:46:08
Ah, what I meant is could it have exited already,
bcwhite
2016/08/23 20:16:46
Acknowledged.
|
+ ; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ LockFreeSimpleQueue<int>* const queue_; |
+ const int count_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(QueuePushThread); |
+}; |
+ |
+class QueuePopThread : public SimpleThread { |
+ public: |
+ QueuePopThread(LockFreeSimpleQueue<int>* queue, int count) |
+ : SimpleThread("QueuePop", Options()), queue_(queue), count_(count) {} |
+ ~QueuePopThread() override {} |
+ |
+ void Run() override { |
+ int yield_after = RandInt(1, queue_->size() * 2); |
+ for (int i = 0; i < count_; ++i) { |
+ int popped; |
+ // Two ways of popping: check for empty first or check for invalid return. |
+ if (i % 2 == 0) { |
+ // Will return "invalid" if empty; keep trying. |
+ while ((popped = queue_->pop()) < 0) |
+ ; |
+ } else { |
+ // This is valid only because there is exactly one thread popping. |
+ while (queue_->empty()) |
+ ; |
+ popped = queue_->pop(); |
+ } |
+ DCHECK_EQ(i, popped); |
+ |
+ // Take a break once in a while. |
+ if (--yield_after <= 0) { |
+ PlatformThread::YieldCurrentThread(); |
+ yield_after = RandInt(1, queue_->size() * 2); |
+ } |
+ |
+ // Every so often, wait for the queue to fill. |
+ if (i < count_ - kQueueTestOperationInterval && |
+ i % kQueueTestOperationInterval == kQueueTestOperationInterval / 2) { |
+ while (!queue_->full()) |
+ ; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ LockFreeSimpleQueue<int>* const queue_; |
+ const int count_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(QueuePopThread); |
+}; |
+ |
} // namespace |
+TEST(LockFreeSimpleQueue, PushPopTest) { |
+ LockFreeSimpleQueue<int> queue(50U, -1); |
+ ASSERT_EQ(50U, queue.size()); |
+ ASSERT_EQ(0U, queue.used()); |
+ |
+ queue.push(1001); |
+ EXPECT_EQ(1U, queue.used()); |
+ |
+ queue.push(2002); |
+ EXPECT_EQ(2U, queue.used()); |
+ |
+ int value = queue.pop(); |
+ EXPECT_EQ(1001, value); |
+ EXPECT_EQ(1U, queue.used()); |
+ |
+ value = queue.pop(); |
+ EXPECT_EQ(2002, value); |
+ EXPECT_EQ(0U, queue.used()); |
+ |
+ value = queue.pop(); |
+ ASSERT_EQ(-1, value); |
+ ASSERT_TRUE(queue.empty()); |
+ |
+ // Test push/pop many times and in parallel. |
+ const int kQueueOperations = 1000000; |
+ QueuePushThread pusher(&queue, kQueueOperations); |
+ QueuePopThread popper(&queue, kQueueOperations); |
+ pusher.Start(); |
+ popper.Start(); |
+ pusher.Join(); |
+ popper.Join(); |
+} |
+ |
+ |
class ActivityTrackerTest : public testing::Test { |
public: |
const int kMemorySize = 1 << 10; // 1MiB |
@@ -72,8 +202,7 @@ class ActivityTrackerTest : public testing::Test { |
GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
if (!global_tracker) |
return 0; |
- return global_tracker->available_memories_count_.load( |
- std::memory_order_relaxed); |
+ return global_tracker->available_memories_.used(); |
} |
static void DoNothing() {} |