From 3d7042176307f0d7700a3640f3b3bcc8790b8fcd Mon Sep 17 00:00:00 2001 From: vladlosev Date: Thu, 20 Nov 2008 01:40:35 +0000 Subject: Value-parameterized tests and many bugfixes --- include/gtest/internal/gtest-linked_ptr.h | 242 ++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 include/gtest/internal/gtest-linked_ptr.h (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h new file mode 100644 index 00000000..f98af0b1 --- /dev/null +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -0,0 +1,242 @@ +// Copyright 2003 Google Inc. +// 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. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + +#include + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +extern Mutex g_linked_ptr_mutex; + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + // Release ownership of the pointed object and returns it. + // Sole ownership by this linked_ptr object is required. + T* release() { + bool last = link_.depart(); + assert(last); + T* v = value_; + value_ = NULL; + return v; + } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -- cgit v1.2.3 From 3bef459eac9aa84c579f34249aebc9ff56832054 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Feb 2010 17:19:25 +0000 Subject: Adds threading support (by Miklos Fazekas, Vlad Losev, and Chandler Carruth); adds wide InitGoogleTest to gtest.def (by Vlad Losev); updates the version number (by Zhanyong Wan); updates the release notes for 1.5.0 (by Vlad Losev); removes scons scripts from the distribution (by Zhanyong Wan); adds the cmake build script to the distribution (by Zhanyong Wan); adds fused source files to the distribution (by Vlad Losev and Chandler Carruth). --- include/gtest/internal/gtest-linked_ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index f98af0b1..5304bcc2 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -77,7 +77,7 @@ namespace testing { namespace internal { // Protects copying of all linked_ptr objects. -extern Mutex g_linked_ptr_mutex; +GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to -- cgit v1.2.3 From 83589cca345d2f03d93b0555437aa480e0ed6699 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 5 Mar 2010 21:21:06 +0000 Subject: Supports building gtest as a DLL (by Vlad Losev). --- include/gtest/internal/gtest-linked_ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index 5304bcc2..540ef4cd 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -77,7 +77,7 @@ namespace testing { namespace internal { // Protects copying of all linked_ptr objects. -GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to -- cgit v1.2.3 From dac3e879c56a50696a36f53e1e5e353e48fa665f Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Tue, 14 Sep 2010 05:35:59 +0000 Subject: Include gtest headers as user headers instead of system headers. --- include/gtest/internal/gtest-linked_ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index 540ef4cd..78750b14 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -71,7 +71,7 @@ #include #include -#include +#include "gtest/internal/gtest-port.h" namespace testing { namespace internal { -- cgit v1.2.3 From c18438ca2983d4f334cfdbd4453e15c41111fa17 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Mon, 11 Oct 2010 06:28:54 +0000 Subject: Makes gtest wokr on MinGW (by Vlad Losev); removes unused linked_ptr::release() method (by Zhanyong Wan). --- include/gtest/internal/gtest-linked_ptr.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index 78750b14..57147b4e 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -172,15 +172,6 @@ class linked_ptr { T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } - // Release ownership of the pointed object and returns it. - // Sole ownership by this linked_ptr object is required. - T* release() { - bool last = link_.depart(); - assert(last); - T* v = value_; - value_ = NULL; - return v; - } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } -- cgit v1.2.3 From 4c11f25f8c972bc5bed6d92abe2a0a3e41f499d7 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Mon, 24 Oct 2011 21:13:56 +0000 Subject: Expressed the thread-safety annotations in code, replacing the existing comment-based system (by Aaron Jacobs). --- include/gtest/internal/gtest-linked_ptr.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index 57147b4e..b1362cd0 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -105,8 +105,8 @@ class linked_ptr_internal { // framework. // Join an existing circle. - // L < g_linked_ptr_mutex - void join(linked_ptr_internal const* ptr) { + void join(linked_ptr_internal const* ptr) + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; @@ -117,8 +117,8 @@ class linked_ptr_internal { // Leave whatever circle we're part of. Returns true if we were the // last member of the circle. Once this is done, you can join() another. - // L < g_linked_ptr_mutex - bool depart() { + bool depart() + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; -- cgit v1.2.3 From 8209a45e2484a7eecc31a20a6dc6b8fd423d0b87 Mon Sep 17 00:00:00 2001 From: kosak Date: Sat, 14 Feb 2015 02:13:32 +0000 Subject: Add asserts to prevent mysterious hangs in a non-thread-safe gmock build. --- include/gtest/internal/gtest-linked_ptr.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'include/gtest/internal/gtest-linked_ptr.h') diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index b1362cd0..36029422 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -110,7 +110,12 @@ class linked_ptr_internal { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; + while (p->next_ != ptr) { + assert(p->next_ != this && + "Trying to join() a linked ring we are already in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = this; next_ = ptr; } @@ -123,7 +128,12 @@ class linked_ptr_internal { if (next_ == this) return true; linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; + while (p->next_ != this) { + assert(p->next_ != next_ && + "Trying to depart() a linked ring we are not in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = next_; return false; } -- cgit v1.2.3