| 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;
|
| }
|
|
|