namespace internal {
-template<typename Record>
-CircularQueue<Record>::CircularQueue(int desired_buffer_size_in_bytes)
- : buffer_(NewArray<Record>(desired_buffer_size_in_bytes / sizeof(Record))),
- buffer_end_(buffer_ + desired_buffer_size_in_bytes / sizeof(Record)),
- enqueue_semaphore_(
- OS::CreateSemaphore(static_cast<int>(buffer_end_ - buffer_) - 1)),
- enqueue_pos_(buffer_),
- dequeue_pos_(buffer_) {
- // To be able to distinguish between a full and an empty queue
- // state, the queue must be capable of containing at least 2
- // records.
- ASSERT((buffer_end_ - buffer_) >= 2);
-}
-
-
-template<typename Record>
-CircularQueue<Record>::~CircularQueue() {
- DeleteArray(buffer_);
- delete enqueue_semaphore_;
-}
-
-
-template<typename Record>
-void CircularQueue<Record>::Dequeue(Record* rec) {
- ASSERT(!IsEmpty());
- *rec = *dequeue_pos_;
- dequeue_pos_ = Next(dequeue_pos_);
- // Tell we have a spare record.
- enqueue_semaphore_->Signal();
-}
-
-
-template<typename Record>
-void CircularQueue<Record>::Enqueue(const Record& rec) {
- // Wait until we have at least one spare record.
- enqueue_semaphore_->Wait();
- ASSERT(Next(enqueue_pos_) != dequeue_pos_);
- *enqueue_pos_ = rec;
- enqueue_pos_ = Next(enqueue_pos_);
-}
-
-
-template<typename Record>
-Record* CircularQueue<Record>::Next(Record* curr) {
- return ++curr != buffer_end_ ? curr : buffer_;
-}
-
-
void* SamplingCircularQueue::Enqueue() {
WrapPositionIfNeeded(&producer_pos_->enqueue_pos);
void* result = producer_pos_->enqueue_pos;
namespace internal {
-// Lock-based blocking circular queue for small records. Intended for
-// transfer of small records between a single producer and a single
-// consumer. Blocks on enqueue operation if the queue is full.
-template<typename Record>
-class CircularQueue {
- public:
- inline explicit CircularQueue(int desired_buffer_size_in_bytes);
- inline ~CircularQueue();
-
- INLINE(void Dequeue(Record* rec));
- INLINE(void Enqueue(const Record& rec));
- INLINE(bool IsEmpty()) { return enqueue_pos_ == dequeue_pos_; }
-
- private:
- INLINE(Record* Next(Record* curr));
-
- Record* buffer_;
- Record* const buffer_end_;
- Semaphore* enqueue_semaphore_;
- Record* enqueue_pos_;
- Record* dequeue_pos_;
-
- DISALLOW_COPY_AND_ASSIGN(CircularQueue);
-};
-
-
// Lock-free cache-friendly sampling circular queue for large
// records. Intended for fast transfer of large records between a
// single producer and a single consumer. If the queue is full,
#include "circular-queue-inl.h"
#include "profile-generator-inl.h"
+#include "unbound-queue-inl.h"
namespace v8 {
namespace internal {
ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator)
: generator_(generator),
running_(false),
- events_buffer_(kEventsBufferSize),
ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize,
kTickSamplesBufferChunksCount),
#ifdef ENABLE_LOGGING_AND_PROFILING
#include "circular-queue.h"
+#include "unbound-queue.h"
namespace v8 {
namespace internal {
ProfileGenerator* generator_;
bool running_;
- CircularQueue<CodeEventsContainer> events_buffer_;
+ UnboundQueue<CodeEventsContainer> events_buffer_;
SamplingCircularQueue ticks_buffer_;
unsigned enqueue_order_;
};
}
+#ifdef V8_TARGET_ARCH_ARM
+// 0xffff0fa0 is the hard coded address of a function provided by
+// the kernel which implements a memory barrier. On older
+// ARM architecture revisions (pre-v6) this may be implemented using
+// a syscall. This address is stable, and in active use (hard coded)
+// by at least glibc-2.7 and the Android C library.
+typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+ (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+#endif
+
+void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
+#ifdef V8_TARGET_ARCH_ARM
+ pLinuxKernelMemoryBarrier();
+#else
+ __asm__ __volatile__("" : : : "memory");
+ // An x86 store acts as a release barrier.
+#endif
+ *ptr = value;
+}
+
+
const char* OS::LocalTimezone(double time) {
if (isnan(time)) return "";
time_t tv = static_cast<time_t>(floor(time/msPerSecond));
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
+#include <libkern/OSAtomic.h>
#include <mach/mach.h>
#include <mach/semaphore.h>
#include <mach/task.h>
}
+void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
+ OSMemoryBarrier();
+ *ptr = value;
+}
+
+
const char* OS::LocalTimezone(double time) {
if (isnan(time)) return "";
time_t tv = static_cast<time_t>(floor(time/msPerSecond));
}
+void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+
bool VirtualMemory::IsReserved() {
return address_ != NULL;
}
// the platform doesn't care. Guaranteed to be a power of two.
static int ActivationFrameAlignment();
+ static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value);
+
private:
static const int msPerSecond = 1000;
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_UNBOUND_QUEUE_INL_H_
+#define V8_UNBOUND_QUEUE_INL_H_
+
+#include "unbound-queue.h"
+
+namespace v8 {
+namespace internal {
+
+template<typename Record>
+struct UnboundQueue<Record>::Node: public Malloced {
+ explicit Node(const Record& value)
+ : value(value), next(NULL) {
+ }
+
+ Record value;
+ Node* next;
+};
+
+
+template<typename Record>
+UnboundQueue<Record>::UnboundQueue() {
+ first_ = new Node(Record());
+ divider_ = last_ = reinterpret_cast<AtomicWord>(first_);
+}
+
+
+template<typename Record>
+UnboundQueue<Record>::~UnboundQueue() {
+ while (first_ != NULL) DeleteFirst();
+}
+
+
+template<typename Record>
+void UnboundQueue<Record>::DeleteFirst() {
+ Node* tmp = first_;
+ first_ = tmp->next;
+ delete tmp;
+}
+
+
+template<typename Record>
+void UnboundQueue<Record>::Dequeue(Record* rec) {
+ ASSERT(divider_ != last_);
+ Node* next = reinterpret_cast<Node*>(divider_)->next;
+ *rec = next->value;
+ OS::ReleaseStore(÷r_, reinterpret_cast<AtomicWord>(next));
+}
+
+
+template<typename Record>
+void UnboundQueue<Record>::Enqueue(const Record& rec) {
+ Node*& next = reinterpret_cast<Node*>(last_)->next;
+ next = new Node(rec);
+ OS::ReleaseStore(&last_, reinterpret_cast<AtomicWord>(next));
+ while (first_ != reinterpret_cast<Node*>(divider_)) DeleteFirst();
+}
+
+} } // namespace v8::internal
+
+#endif // V8_UNBOUND_QUEUE_INL_H_
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_UNBOUND_QUEUE_
+#define V8_UNBOUND_QUEUE_
+
+namespace v8 {
+namespace internal {
+
+
+// Lock-free unbound queue for small records. Intended for
+// transferring small records between a Single producer and a Single
+// consumer. Doesn't have restrictions on the number of queued
+// elements, so producer never blocks. Implemented after Herb
+// Sutter's article:
+// http://www.ddj.com/high-performance-computing/210604448
+template<typename Record>
+class UnboundQueue BASE_EMBEDDED {
+ public:
+ inline UnboundQueue();
+ inline ~UnboundQueue();
+
+ INLINE(void Dequeue(Record* rec));
+ INLINE(void Enqueue(const Record& rec));
+ INLINE(bool IsEmpty()) { return divider_ == last_; }
+
+ private:
+ INLINE(void DeleteFirst());
+
+ struct Node;
+
+ Node* first_;
+ AtomicWord divider_; // Node*
+ AtomicWord last_; // Node*
+
+ DISALLOW_COPY_AND_ASSIGN(UnboundQueue);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_UNBOUND_QUEUE_
Top::TearDown();
- CpuProfiler::TearDown();
-
Heap::TearDown();
+ CpuProfiler::TearDown();
+
Logger::TearDown();
is_running_ = false;
'test-strings.cc',
'test-threads.cc',
'test-thread-termination.cc',
+ 'test-unbound-queue.cc',
'test-utils.cc',
'test-version.cc'
],
// Copyright 2010 the V8 project authors. All rights reserved.
//
-// Tests of circular queues.
+// Tests of the circular queue.
#include "v8.h"
#include "circular-queue-inl.h"
namespace i = v8::internal;
-using i::CircularQueue;
using i::SamplingCircularQueue;
-TEST(SingleRecordCircularQueue) {
- typedef int Record;
- CircularQueue<Record> cq(sizeof(Record) * 2);
- CHECK(cq.IsEmpty());
- cq.Enqueue(1);
- CHECK(!cq.IsEmpty());
- Record rec = 0;
- cq.Dequeue(&rec);
- CHECK_EQ(1, rec);
- CHECK(cq.IsEmpty());
-}
-
-
-TEST(MultipleRecordsCircularQueue) {
- typedef int Record;
- const int kQueueSize = 10;
- CircularQueue<Record> cq(sizeof(Record) * (kQueueSize + 1));
- CHECK(cq.IsEmpty());
- cq.Enqueue(1);
- CHECK(!cq.IsEmpty());
- for (int i = 2; i <= 5; ++i) {
- cq.Enqueue(i);
- CHECK(!cq.IsEmpty());
- }
- Record rec = 0;
- for (int i = 1; i <= 4; ++i) {
- CHECK(!cq.IsEmpty());
- cq.Dequeue(&rec);
- CHECK_EQ(i, rec);
- }
- for (int i = 6; i <= 12; ++i) {
- cq.Enqueue(i);
- CHECK(!cq.IsEmpty());
- }
- for (int i = 5; i <= 12; ++i) {
- CHECK(!cq.IsEmpty());
- cq.Dequeue(&rec);
- CHECK_EQ(i, rec);
- }
- CHECK(cq.IsEmpty());
-}
-
-
TEST(SamplingCircularQueue) {
typedef SamplingCircularQueue::Cell Record;
const int kRecordsPerChunk = 4;
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+//
+// Tests of the unbound queue.
+
+#include "v8.h"
+#include "unbound-queue-inl.h"
+#include "cctest.h"
+
+namespace i = v8::internal;
+
+using i::UnboundQueue;
+
+
+TEST(SingleRecord) {
+ typedef int Record;
+ UnboundQueue<Record> cq;
+ CHECK(cq.IsEmpty());
+ cq.Enqueue(1);
+ CHECK(!cq.IsEmpty());
+ Record rec = 0;
+ cq.Dequeue(&rec);
+ CHECK_EQ(1, rec);
+ CHECK(cq.IsEmpty());
+}
+
+
+TEST(MultipleRecords) {
+ typedef int Record;
+ UnboundQueue<Record> cq;
+ CHECK(cq.IsEmpty());
+ cq.Enqueue(1);
+ CHECK(!cq.IsEmpty());
+ for (int i = 2; i <= 5; ++i) {
+ cq.Enqueue(i);
+ CHECK(!cq.IsEmpty());
+ }
+ Record rec = 0;
+ for (int i = 1; i <= 4; ++i) {
+ CHECK(!cq.IsEmpty());
+ cq.Dequeue(&rec);
+ CHECK_EQ(i, rec);
+ }
+ for (int i = 6; i <= 12; ++i) {
+ cq.Enqueue(i);
+ CHECK(!cq.IsEmpty());
+ }
+ for (int i = 5; i <= 12; ++i) {
+ CHECK(!cq.IsEmpty());
+ cq.Dequeue(&rec);
+ CHECK_EQ(i, rec);
+ }
+ CHECK(cq.IsEmpty());
+}
+
'../../src/top.h',
'../../src/type-info.cc',
'../../src/type-info.h',
+ '../../src/unbound-queue-inl.h',
+ '../../src/unbound-queue.h',
'../../src/unicode-inl.h',
'../../src/unicode.cc',
'../../src/unicode.h',
9FBE03E410BD412600F8BFBA /* fast-codegen-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "fast-codegen-arm.cc"; path = "arm/fast-codegen-arm.cc"; sourceTree = "<group>"; };
9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "oprofile-agent.cc"; sourceTree = "<group>"; };
9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "oprofile-agent.h"; sourceTree = "<group>"; };
+ 9FF7A28211A642EA0051B8F2 /* unbound-queue-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "unbound-queue-inl.h"; sourceTree = "<group>"; };
+ 9FF7A28311A642EA0051B8F2 /* unbound-queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "unbound-queue.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
897FF1910E719B8F00D62E90 /* top.h */,
9FA38BAE1175B2D200C4CD55 /* type-info.cc */,
9FA38BAF1175B2D200C4CD55 /* type-info.h */,
+ 9FF7A28211A642EA0051B8F2 /* unbound-queue-inl.h */,
+ 9FF7A28311A642EA0051B8F2 /* unbound-queue.h */,
897FF1920E719B8F00D62E90 /* unicode-inl.h */,
897FF1930E719B8F00D62E90 /* unicode.cc */,
897FF1940E719B8F00D62E90 /* unicode.h */,
RelativePath="..\..\src\type-info.h"
>
</File>
+ <File
+ RelativePath="..\..\src\unbound-queue-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\unbound-queue.h"
+ >
+ </File>
<File
RelativePath="..\..\src\unicode-inl.h"
>
RelativePath="..\..\src\type-info.h"
>
</File>
+ <File
+ RelativePath="..\..\src\unbound-queue-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\unbound-queue.h"
+ >
+ </File>
<File
RelativePath="..\..\src\unicode-inl.h"
>
RelativePath="..\..\src\type-info.h"
>
</File>
+ <File
+ RelativePath="..\..\src\unbound-queue-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\unbound-queue.h"
+ >
+ </File>
<File
RelativePath="..\..\src\unicode-inl.h"
>
RelativePath="..\..\test\cctest\test-strings.cc"
>
</File>
+ <File
+ RelativePath="..\..\test\cctest\test-unbound-queue.cc"
+ >
+ </File>
<File
RelativePath="..\..\test\cctest\test-utils.cc"
>