Index: test/cctest/test-circular-queue.cc |
diff --git a/test/cctest/test-circular-queue.cc b/test/cctest/test-circular-queue.cc |
index bb69c1bc0245f059a455ce98617094c132115e74..3fa49bfaf3d2cdef923ee7d6a7fc07027fc34158 100644 |
--- a/test/cctest/test-circular-queue.cc |
+++ b/test/cctest/test-circular-queue.cc |
@@ -61,8 +61,6 @@ TEST(SamplingCircularQueue) { |
SamplingCircularQueue scq(sizeof(Record), |
kRecordsPerChunk * sizeof(Record), |
3); |
- scq.SetUpProducer(); |
- scq.SetUpConsumer(); |
// Check that we are using non-reserved values. |
CHECK_NE(SamplingCircularQueue::kClear, 1); |
@@ -121,7 +119,103 @@ TEST(SamplingCircularQueue) { |
// Consumption must still be possible as the first cell of the |
// last chunk is not clean. |
CHECK_NE(NULL, scq.StartDequeue()); |
+} |
+ |
+ |
+namespace { |
+ |
+class ProducerThread: public i::Thread { |
+ public: |
+ typedef SamplingCircularQueue::Cell Record; |
+ |
+ ProducerThread(SamplingCircularQueue* scq, |
+ int records_per_chunk, |
+ Record value, |
+ i::Semaphore* finished) |
+ : scq_(scq), |
+ records_per_chunk_(records_per_chunk), |
+ value_(value), |
+ finished_(finished) { } |
+ |
+ virtual void Run() { |
+ for (Record i = value_; i < value_ + records_per_chunk_; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq_->Enqueue()); |
+ CHECK_NE(NULL, rec); |
+ *rec = i; |
+ } |
+ |
+ finished_->Signal(); |
+ } |
+ |
+ private: |
+ SamplingCircularQueue* scq_; |
+ const int records_per_chunk_; |
+ Record value_; |
+ i::Semaphore* finished_; |
+}; |
+ |
+} // namespace |
+ |
+TEST(SamplingCircularQueueMultithreading) { |
+ // Emulate multiple VM threads working 'one thread at a time.' |
+ // This test enqueues data from different threads. This corresponds |
+ // to the case of profiling under Linux, where signal handler that |
+ // does sampling is called in the context of different VM threads. |
+ |
+ typedef ProducerThread::Record Record; |
+ const int kRecordsPerChunk = 4; |
+ SamplingCircularQueue scq(sizeof(Record), |
+ kRecordsPerChunk * sizeof(Record), |
+ 3); |
+ i::Semaphore* semaphore = i::OS::CreateSemaphore(0); |
+ // Don't poll ahead, making possible to check data in the buffer |
+ // immediately after enqueuing. |
+ scq.FlushResidualRecords(); |
+ |
+ // Check that we are using non-reserved values. |
+ CHECK_NE(SamplingCircularQueue::kClear, 1); |
+ CHECK_NE(SamplingCircularQueue::kEnd, 1); |
+ ProducerThread producer1(&scq, kRecordsPerChunk, 1, semaphore); |
+ ProducerThread producer2(&scq, kRecordsPerChunk, 10, semaphore); |
+ ProducerThread producer3(&scq, kRecordsPerChunk, 20, semaphore); |
+ |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ producer1.Start(); |
+ semaphore->Wait(); |
+ for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.StartDequeue()); |
+ CHECK_NE(NULL, rec); |
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec)); |
+ CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ scq.FinishDequeue(); |
+ CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ } |
+ |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ producer2.Start(); |
+ semaphore->Wait(); |
+ for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.StartDequeue()); |
+ CHECK_NE(NULL, rec); |
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec)); |
+ CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ scq.FinishDequeue(); |
+ CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ } |
+ |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ producer3.Start(); |
+ semaphore->Wait(); |
+ for (Record i = 20; i < 20 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.StartDequeue()); |
+ CHECK_NE(NULL, rec); |
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(*rec)); |
+ CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ scq.FinishDequeue(); |
+ CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ } |
+ |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
- scq.TearDownConsumer(); |
- scq.TearDownProducer(); |
+ delete semaphore; |
} |