diff options
Diffstat (limited to 'src/core/lib')
-rw-r--r-- | src/core/lib/iomgr/ev_epoll1_linux.cc | 25 | ||||
-rw-r--r-- | src/core/lib/iomgr/ev_epollex_linux.cc | 10 | ||||
-rw-r--r-- | src/core/lib/iomgr/ev_epollsig_linux.cc | 10 | ||||
-rw-r--r-- | src/core/lib/iomgr/ev_epollsig_linux.h | 4 | ||||
-rw-r--r-- | src/core/lib/iomgr/is_epollexclusive_available.cc | 2 | ||||
-rw-r--r-- | src/core/lib/iomgr/port.h | 7 | ||||
-rw-r--r-- | src/core/lib/support/abstract.h | 5 | ||||
-rw-r--r-- | src/core/lib/support/orphanable.h | 171 | ||||
-rw-r--r-- | src/core/lib/support/ref_counted.h | 13 | ||||
-rw-r--r-- | src/core/lib/support/ref_counted_ptr.h | 9 |
10 files changed, 238 insertions, 18 deletions
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc index 1ab7e516de..aa14d5931a 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.cc +++ b/src/core/lib/iomgr/ev_epoll1_linux.cc @@ -20,12 +20,14 @@ #include <grpc/support/log.h> -/* This polling engine is only relevant on linux kernels supporting epoll() */ +/* This polling engine is only relevant on linux kernels supporting epoll + epoll_create() or epoll_create1() */ #ifdef GRPC_LINUX_EPOLL #include "src/core/lib/iomgr/ev_epoll1_linux.h" #include <assert.h> #include <errno.h> +#include <fcntl.h> #include <limits.h> #include <poll.h> #include <pthread.h> @@ -84,11 +86,28 @@ typedef struct epoll_set { /* The global singleton epoll set */ static epoll_set g_epoll_set; +static int epoll_create_and_cloexec() { +#ifdef GRPC_LINUX_EPOLL_CREATE1 + int fd = epoll_create1(EPOLL_CLOEXEC); + if (fd < 0) { + gpr_log(GPR_ERROR, "epoll_create1 unavailable"); + } +#else + int fd = epoll_create(MAX_EPOLL_EVENTS); + if (fd < 0) { + gpr_log(GPR_ERROR, "epoll_create unavailable"); + } else if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + gpr_log(GPR_ERROR, "fcntl following epoll_create failed"); + return -1; + } +#endif + return fd; +} + /* Must be called *only* once */ static bool epoll_set_init() { - g_epoll_set.epfd = epoll_create1(EPOLL_CLOEXEC); + g_epoll_set.epfd = epoll_create_and_cloexec(); if (g_epoll_set.epfd < 0) { - gpr_log(GPR_ERROR, "epoll unavailable"); return false; } diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 5f5f45a7a5..e4a2d67e4b 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -21,7 +21,7 @@ #include <grpc/support/log.h> /* This polling engine is only relevant on linux kernels supporting epoll() */ -#ifdef GRPC_LINUX_EPOLL +#ifdef GRPC_LINUX_EPOLL_CREATE1 #include "src/core/lib/iomgr/ev_epollex_linux.h" @@ -1442,15 +1442,15 @@ const grpc_event_engine_vtable* grpc_init_epollex_linux( return &vtable; } -#else /* defined(GRPC_LINUX_EPOLL) */ +#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */ #if defined(GRPC_POSIX_SOCKET) #include "src/core/lib/iomgr/ev_epollex_linux.h" -/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return - * NULL */ +/* If GRPC_LINUX_EPOLL_CREATE1 is not defined, it means + epoll_create1 is not available. Return NULL */ const grpc_event_engine_vtable* grpc_init_epollex_linux( bool explicitly_requested) { return nullptr; } #endif /* defined(GRPC_POSIX_SOCKET) */ -#endif /* !defined(GRPC_LINUX_EPOLL) */ +#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */ diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc index 8072a6cbed..3544d4f3a4 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.cc +++ b/src/core/lib/iomgr/ev_epollsig_linux.cc @@ -22,7 +22,7 @@ #include <grpc/support/log.h> /* This polling engine is only relevant on linux kernels supporting epoll() */ -#ifdef GRPC_LINUX_EPOLL +#ifdef GRPC_LINUX_EPOLL_CREATE1 #include "src/core/lib/iomgr/ev_epollsig_linux.h" @@ -1725,11 +1725,11 @@ const grpc_event_engine_vtable* grpc_init_epollsig_linux( return &vtable; } -#else /* defined(GRPC_LINUX_EPOLL) */ +#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */ #if defined(GRPC_POSIX_SOCKET) #include "src/core/lib/iomgr/ev_epollsig_linux.h" -/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return - * NULL */ +/* If GRPC_LINUX_EPOLL_CREATE1 is not defined, it means + epoll_create1 is not available. Return NULL */ const grpc_event_engine_vtable* grpc_init_epollsig_linux( bool explicit_request) { return nullptr; @@ -1737,4 +1737,4 @@ const grpc_event_engine_vtable* grpc_init_epollsig_linux( #endif /* defined(GRPC_POSIX_SOCKET) */ void grpc_use_signal(int signum) {} -#endif /* !defined(GRPC_LINUX_EPOLL) */ +#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */ diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/lib/iomgr/ev_epollsig_linux.h index 5b8aba9d9f..48178d3713 100644 --- a/src/core/lib/iomgr/ev_epollsig_linux.h +++ b/src/core/lib/iomgr/ev_epollsig_linux.h @@ -24,10 +24,10 @@ const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request); -#ifdef GRPC_LINUX_EPOLL +#ifdef GRPC_LINUX_EPOLL_CREATE1 void* grpc_fd_get_polling_island(grpc_fd* fd); void* grpc_pollset_get_polling_island(grpc_pollset* ps); bool grpc_are_polling_islands_equal(void* p, void* q); -#endif /* defined(GRPC_LINUX_EPOLL) */ +#endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */ #endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */ diff --git a/src/core/lib/iomgr/is_epollexclusive_available.cc b/src/core/lib/iomgr/is_epollexclusive_available.cc index e5803532e7..08f9cf2b69 100644 --- a/src/core/lib/iomgr/is_epollexclusive_available.cc +++ b/src/core/lib/iomgr/is_epollexclusive_available.cc @@ -20,7 +20,7 @@ #include "src/core/lib/iomgr/is_epollexclusive_available.h" -#ifdef GRPC_LINUX_EPOLL +#ifdef GRPC_LINUX_EPOLL_CREATE1 #include <grpc/support/log.h> diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h index 9fae8c0052..25090898ed 100644 --- a/src/core/lib/iomgr/port.h +++ b/src/core/lib/iomgr/port.h @@ -37,6 +37,7 @@ #define GRPC_POSIX_SOCKETUTILS 1 #define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_TIMER_USE_GENERIC 1 +#define GRPC_LINUX_EPOLL 1 #elif defined(GPR_WINDOWS) #define GRPC_TIMER_USE_GENERIC 1 #define GRPC_WINSOCK_SOCKET 1 @@ -67,8 +68,11 @@ #define GRPC_POSIX_WAKEUP_FD 1 #define GRPC_TIMER_USE_GENERIC 1 #ifdef __GLIBC_PREREQ -#if __GLIBC_PREREQ(2, 9) +#if __GLIBC_PREREQ(2, 4) #define GRPC_LINUX_EPOLL 1 +#endif +#if __GLIBC_PREREQ(2, 9) +#define GRPC_LINUX_EPOLL_CREATE1 1 #define GRPC_LINUX_EVENTFD 1 #endif #if __GLIBC_PREREQ(2, 10) @@ -77,6 +81,7 @@ #endif #ifndef __GLIBC__ #define GRPC_LINUX_EPOLL 1 +#define GRPC_LINUX_EPOLL_CREATE1 1 #define GRPC_LINUX_EVENTFD 1 #define GRPC_MSG_IOVLEN_TYPE int #endif diff --git a/src/core/lib/support/abstract.h b/src/core/lib/support/abstract.h index 5498769a7d..1dffa30128 100644 --- a/src/core/lib/support/abstract.h +++ b/src/core/lib/support/abstract.h @@ -26,4 +26,9 @@ #define GRPC_ABSTRACT_BASE_CLASS \ static void operator delete(void* p) { abort(); } +// gRPC currently can't depend on libstdc++, so we can't use "= 0" for +// pure virtual methods. Instead, we use this macro. +#define GRPC_ABSTRACT \ + { GPR_ASSERT(false); } + #endif /* GRPC_CORE_LIB_SUPPORT_ABSTRACT_H */ diff --git a/src/core/lib/support/orphanable.h b/src/core/lib/support/orphanable.h new file mode 100644 index 0000000000..2f537573fd --- /dev/null +++ b/src/core/lib/support/orphanable.h @@ -0,0 +1,171 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_ORPHANABLE_H +#define GRPC_CORE_LIB_SUPPORT_ORPHANABLE_H + +#include <grpc/support/log.h> +#include <grpc/support/sync.h> + +#include <memory> + +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/support/abstract.h" +#include "src/core/lib/support/debug_location.h" +#include "src/core/lib/support/memory.h" + +namespace grpc_core { + +// A base class for orphanable objects, which have one external owner +// but are not necessarily destroyed immediately when the external owner +// gives up ownership. Instead, the owner calls the object's Orphan() +// method, and the object then takes responsibility for its own cleanup +// and destruction. +class Orphanable { + public: + // Gives up ownership of the object. The implementation must arrange + // to eventually destroy the object without further interaction from the + // caller. + virtual void Orphan() GRPC_ABSTRACT; + + // Not copyable or movable. + Orphanable(const Orphanable&) = delete; + Orphanable& operator=(const Orphanable&) = delete; + + GRPC_ABSTRACT_BASE_CLASS + + protected: + Orphanable() {} + virtual ~Orphanable() {} +}; + +template <typename T> +class OrphanableDelete { + public: + void operator()(T* p) { p->Orphan(); } +}; + +template <typename T, typename Deleter = OrphanableDelete<T>> +using OrphanablePtr = std::unique_ptr<T, Deleter>; + +template <typename T, typename... Args> +inline OrphanablePtr<T> MakeOrphanable(Args&&... args) { + return OrphanablePtr<T>(New<T>(std::forward<Args>(args)...)); +} + +// A type of Orphanable with internal ref-counting. +class InternallyRefCounted : public Orphanable { + public: + // Not copyable nor movable. + InternallyRefCounted(const InternallyRefCounted&) = delete; + InternallyRefCounted& operator=(const InternallyRefCounted&) = delete; + + GRPC_ABSTRACT_BASE_CLASS + + protected: + InternallyRefCounted() { gpr_ref_init(&refs_, 1); } + virtual ~InternallyRefCounted() {} + + void Ref() { gpr_ref(&refs_); } + + void Unref() { + if (gpr_unref(&refs_)) { + Delete(this); + } + } + + // Allow Delete() to access destructor. + template <typename T> + friend void Delete(T*); + + private: + gpr_refcount refs_; +}; + +// An alternative version of the InternallyRefCounted base class that +// supports tracing. This is intended to be used in cases where the +// object will be handled both by idiomatic C++ code using smart +// pointers and legacy code that is manually calling Ref() and Unref(). +// Once all of our code is converted to idiomatic C++, we may be able to +// eliminate this class. +class InternallyRefCountedWithTracing : public Orphanable { + public: + // Not copyable nor movable. + InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) = + delete; + InternallyRefCountedWithTracing& operator=( + const InternallyRefCountedWithTracing&) = delete; + + GRPC_ABSTRACT_BASE_CLASS + + protected: + // Allow Delete() to access destructor. + template <typename T> + friend void Delete(T*); + + InternallyRefCountedWithTracing() + : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {} + + explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag) + : trace_flag_(trace_flag) { + gpr_ref_init(&refs_, 1); + } + +#ifdef NDEBUG + explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag) + : InternallyRefCountedWithTracing() {} +#endif + + virtual ~InternallyRefCountedWithTracing() {} + + void Ref() { gpr_ref(&refs_); } + + void Ref(const DebugLocation& location, const char* reason) { + if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { + gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); + gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s", + trace_flag_->name(), this, location.file(), location.line(), + old_refs, old_refs + 1, reason); + } + Ref(); + } + + void Unref() { + if (gpr_unref(&refs_)) { + Delete(this); + } + } + + void Unref(const DebugLocation& location, const char* reason) { + if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) { + gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count); + gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s", + trace_flag_->name(), this, location.file(), location.line(), + old_refs, old_refs - 1, reason); + } + Unref(); + } + + private: + TraceFlag* trace_flag_ = nullptr; + gpr_refcount refs_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_ORPHANABLE_H */ diff --git a/src/core/lib/support/ref_counted.h b/src/core/lib/support/ref_counted.h index 4c662f9119..48c11f7bbf 100644 --- a/src/core/lib/support/ref_counted.h +++ b/src/core/lib/support/ref_counted.h @@ -23,6 +23,7 @@ #include <grpc/support/sync.h> #include "src/core/lib/debug/trace.h" +#include "src/core/lib/support/abstract.h" #include "src/core/lib/support/debug_location.h" #include "src/core/lib/support/memory.h" @@ -45,6 +46,8 @@ class RefCounted { RefCounted(const RefCounted&) = delete; RefCounted& operator=(const RefCounted&) = delete; + GRPC_ABSTRACT_BASE_CLASS + protected: // Allow Delete() to access destructor. template <typename T> @@ -98,18 +101,26 @@ class RefCountedWithTracing { RefCountedWithTracing(const RefCountedWithTracing&) = delete; RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete; + GRPC_ABSTRACT_BASE_CLASS + protected: // Allow Delete() to access destructor. template <typename T> friend void Delete(T*); - RefCountedWithTracing() : RefCountedWithTracing(nullptr) {} + RefCountedWithTracing() + : RefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {} explicit RefCountedWithTracing(TraceFlag* trace_flag) : trace_flag_(trace_flag) { gpr_ref_init(&refs_, 1); } +#ifdef NDEBUG + explicit RefCountedWithTracing(DebugOnlyTraceFlag* trace_flag) + : RefCountedWithTracing() {} +#endif + virtual ~RefCountedWithTracing() {} private: diff --git a/src/core/lib/support/ref_counted_ptr.h b/src/core/lib/support/ref_counted_ptr.h index dc2385e369..76ff0bba66 100644 --- a/src/core/lib/support/ref_counted_ptr.h +++ b/src/core/lib/support/ref_counted_ptr.h @@ -76,6 +76,15 @@ class RefCountedPtr { T& operator*() const { return *value_; } T* operator->() const { return value_; } + bool operator==(const RefCountedPtr& other) const { + return value_ == other.value_; + } + bool operator==(const T* other) const { return value_ == other; } + bool operator!=(const RefCountedPtr& other) const { + return value_ != other.value_; + } + bool operator!=(const T* other) const { return value_ != other; } + private: T* value_ = nullptr; }; |