aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib')
-rw-r--r--src/core/lib/debug/trace.cc4
-rw-r--r--src/core/lib/iomgr/fork_posix.cc88
-rw-r--r--src/core/lib/iomgr/fork_windows.cc39
-rw-r--r--src/core/lib/iomgr/port.h4
-rw-r--r--src/core/lib/support/debug_location.h52
-rw-r--r--src/core/lib/support/fork.cc62
-rw-r--r--src/core/lib/support/fork.h35
-rw-r--r--src/core/lib/support/murmur_hash.cc19
-rw-r--r--src/core/lib/support/ref_counted.h122
-rw-r--r--src/core/lib/support/ref_counted_ptr.h90
-rw-r--r--src/core/lib/support/stack_lockfree.cc137
-rw-r--r--src/core/lib/support/stack_lockfree.h46
-rw-r--r--src/core/lib/support/thd_internal.h30
-rw-r--r--src/core/lib/support/thd_posix.cc56
-rw-r--r--src/core/lib/support/thd_windows.cc2
-rw-r--r--src/core/lib/surface/init.cc6
-rw-r--r--src/core/lib/surface/server.cc2
-rw-r--r--src/core/lib/surface/version.cc2
-rw-r--r--src/core/lib/transport/transport.cc2
19 files changed, 599 insertions, 199 deletions
diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc
index 4c63983bdc..a76c1afb4c 100644
--- a/src/core/lib/debug/trace.cc
+++ b/src/core/lib/debug/trace.cc
@@ -75,8 +75,8 @@ void TraceFlagList::LogAllTracers() {
}
// Flags register themselves on the list during construction
-TraceFlag::TraceFlag(bool default_enabled, const char* name)
- : name_(name), value_(default_enabled) {
+TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
+ set_enabled(default_enabled);
TraceFlagList::Add(this);
}
diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc
new file mode 100644
index 0000000000..a55b3a349a
--- /dev/null
+++ b/src/core/lib/iomgr/fork_posix.cc
@@ -0,0 +1,88 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_POSIX_FORK
+
+#include <string.h>
+
+#include <grpc/fork.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/fork.h"
+#include "src/core/lib/support/thd_internal.h"
+#include "src/core/lib/surface/init.h"
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ * AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_prefork() {
+ if (!grpc_fork_support_enabled()) {
+ gpr_log(GPR_ERROR,
+ "Fork support not enabled; try running with the "
+ "environment variable GRPC_ENABLE_FORK_SUPPORT=1");
+ return;
+ }
+ if (grpc_is_initialized()) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_timer_manager_set_threading(false);
+ grpc_executor_set_threading(&exec_ctx, false);
+ grpc_exec_ctx_finish(&exec_ctx);
+ if (!gpr_await_threads(
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_seconds(3, GPR_TIMESPAN)))) {
+ gpr_log(GPR_ERROR, "gRPC thread still active! Cannot fork!");
+ }
+ }
+}
+
+void grpc_postfork_parent() {
+ if (grpc_is_initialized()) {
+ grpc_timer_manager_set_threading(true);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_executor_set_threading(&exec_ctx, true);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+}
+
+void grpc_postfork_child() {
+ if (grpc_is_initialized()) {
+ grpc_timer_manager_set_threading(true);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_executor_set_threading(&exec_ctx, true);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+}
+
+void grpc_fork_handlers_auto_register() {
+ if (grpc_fork_support_enabled()) {
+ pthread_atfork(grpc_prefork, grpc_postfork_parent, grpc_postfork_child);
+ }
+}
+
+#endif // GRPC_POSIX_FORK
diff --git a/src/core/lib/iomgr/fork_windows.cc b/src/core/lib/iomgr/fork_windows.cc
new file mode 100644
index 0000000000..f9986f33c7
--- /dev/null
+++ b/src/core/lib/iomgr/fork_windows.cc
@@ -0,0 +1,39 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifndef GRPC_POSIX_FORK
+
+#include <grpc/fork.h>
+#include <grpc/support/log.h>
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ * AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_prefork() { gpr_log(GPR_ERROR, "Forking not supported on Windows"); }
+
+void grpc_postfork_parent() {}
+
+void grpc_postfork_child() {}
+
+void grpc_fork_handlers_auto_register() {}
+
+#endif // GRPC_POSIX_FORK
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 1cc6d98491..9fae8c0052 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -30,6 +30,7 @@
#define GRPC_HAVE_IP_PKTINFO 1
#define GRPC_HAVE_MSG_NOSIGNAL 1
#define GRPC_HAVE_UNIX_SOCKET 1
+#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1
@@ -59,6 +60,7 @@
#define GRPC_HAVE_MSG_NOSIGNAL 1
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1
+#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_HOST_NAME_MAX 1
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1
@@ -90,6 +92,7 @@
#define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_MSG_IOVLEN_TYPE int
+#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1
@@ -103,6 +106,7 @@
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_SO_NOSIGPIPE 1
#define GRPC_HAVE_UNIX_SOCKET 1
+#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
#define GRPC_POSIX_SOCKETADDR 1
diff --git a/src/core/lib/support/debug_location.h b/src/core/lib/support/debug_location.h
new file mode 100644
index 0000000000..0939da595d
--- /dev/null
+++ b/src/core/lib/support/debug_location.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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_DEBUG_LOCATION_H
+#define GRPC_CORE_LIB_SUPPORT_DEBUG_LOCATION_H
+
+namespace grpc_core {
+
+// Used for tracking file and line where a call is made for debug builds.
+// No-op for non-debug builds.
+// Callers can use the DEBUG_LOCATION macro in either case.
+#ifndef NDEBUG
+class DebugLocation {
+ public:
+ DebugLocation(const char* file, int line) : file_(file), line_(line) {}
+ bool Log() const { return true; }
+ const char* file() const { return file_; }
+ int line() const { return line_; }
+
+ private:
+ const char* file_;
+ const int line_;
+};
+#define DEBUG_LOCATION DebugLocation(__FILE__, __LINE__)
+#else
+class DebugLocation {
+ public:
+ bool Log() const { return false; }
+ const char* file() const { return nullptr; }
+ int line() const { return -1; }
+};
+#define DEBUG_LOCATION DebugLocation()
+#endif
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_DEBUG_LOCATION_H */
diff --git a/src/core/lib/support/fork.cc b/src/core/lib/support/fork.cc
new file mode 100644
index 0000000000..d59ca5584c
--- /dev/null
+++ b/src/core/lib/support/fork.cc
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/lib/support/fork.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/support/env.h"
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ * AROUND VERY SPECIFIC USE CASES.
+ */
+
+static int override_fork_support_enabled = -1;
+static int fork_support_enabled;
+
+void grpc_fork_support_init() {
+#ifdef GRPC_ENABLE_FORK_SUPPORT
+ fork_support_enabled = 1;
+#else
+ fork_support_enabled = 0;
+ char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
+ if (env != NULL) {
+ static const char* truthy[] = {"yes", "Yes", "YES", "true",
+ "True", "TRUE", "1"};
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
+ if (0 == strcmp(env, truthy[i])) {
+ fork_support_enabled = 1;
+ }
+ }
+ gpr_free(env);
+ }
+#endif
+ if (override_fork_support_enabled != -1) {
+ fork_support_enabled = override_fork_support_enabled;
+ }
+}
+
+int grpc_fork_support_enabled() { return fork_support_enabled; }
+
+void grpc_enable_fork_support(int enable) {
+ override_fork_support_enabled = enable;
+}
diff --git a/src/core/lib/support/fork.h b/src/core/lib/support/fork.h
new file mode 100644
index 0000000000..215d4214a6
--- /dev/null
+++ b/src/core/lib/support/fork.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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_FORK_H
+#define GRPC_CORE_LIB_SUPPORT_FORK_H
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ * AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_fork_support_init(void);
+
+int grpc_fork_support_enabled(void);
+
+// Test only: Must be called before grpc_init(), and overrides
+// environment variables/compile flags
+void grpc_enable_fork_support(int enable);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_FORK_H */
diff --git a/src/core/lib/support/murmur_hash.cc b/src/core/lib/support/murmur_hash.cc
index 4e08579a1d..2f0e71a53c 100644
--- a/src/core/lib/support/murmur_hash.cc
+++ b/src/core/lib/support/murmur_hash.cc
@@ -30,22 +30,19 @@
(h) ^= (h) >> 16;
uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) {
- const uint8_t* data = (const uint8_t*)key;
- const size_t nblocks = len / 4;
- int i;
-
uint32_t h1 = seed;
uint32_t k1;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
- const uint32_t* blocks = ((const uint32_t*)key) + nblocks;
- const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
+ const uint8_t* keyptr = (const uint8_t*)key;
+ const size_t bsize = sizeof(k1);
+ const size_t nblocks = len / bsize;
/* body */
- for (i = -(int)nblocks; i; i++) {
- memcpy(&k1, blocks + i, sizeof(uint32_t));
+ for (size_t i = 0; i < nblocks; i++, keyptr += bsize) {
+ memcpy(&k1, keyptr, bsize);
k1 *= c1;
k1 = ROTL32(k1, 15);
@@ -61,13 +58,13 @@ uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) {
/* tail */
switch (len & 3) {
case 3:
- k1 ^= ((uint32_t)tail[2]) << 16;
+ k1 ^= ((uint32_t)keyptr[2]) << 16;
/* fallthrough */
case 2:
- k1 ^= ((uint32_t)tail[1]) << 8;
+ k1 ^= ((uint32_t)keyptr[1]) << 8;
/* fallthrough */
case 1:
- k1 ^= tail[0];
+ k1 ^= keyptr[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
diff --git a/src/core/lib/support/ref_counted.h b/src/core/lib/support/ref_counted.h
new file mode 100644
index 0000000000..4c662f9119
--- /dev/null
+++ b/src/core/lib/support/ref_counted.h
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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_REF_COUNTED_H
+#define GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/support/debug_location.h"
+#include "src/core/lib/support/memory.h"
+
+namespace grpc_core {
+
+// A base class for reference-counted objects.
+// New objects should be created via New() and start with a refcount of 1.
+// When the refcount reaches 0, the object will be deleted via Delete().
+class RefCounted {
+ public:
+ void Ref() { gpr_ref(&refs_); }
+
+ void Unref() {
+ if (gpr_unref(&refs_)) {
+ Delete(this);
+ }
+ }
+
+ // Not copyable nor movable.
+ RefCounted(const RefCounted&) = delete;
+ RefCounted& operator=(const RefCounted&) = delete;
+
+ protected:
+ // Allow Delete() to access destructor.
+ template <typename T>
+ friend void Delete(T*);
+
+ RefCounted() { gpr_ref_init(&refs_, 1); }
+
+ virtual ~RefCounted() {}
+
+ private:
+ gpr_refcount refs_;
+};
+
+// An alternative version of the RefCounted 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 RefCountedWithTracing {
+ public:
+ 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();
+ }
+
+ // Not copyable nor movable.
+ RefCountedWithTracing(const RefCountedWithTracing&) = delete;
+ RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete;
+
+ protected:
+ // Allow Delete() to access destructor.
+ template <typename T>
+ friend void Delete(T*);
+
+ RefCountedWithTracing() : RefCountedWithTracing(nullptr) {}
+
+ explicit RefCountedWithTracing(TraceFlag* trace_flag)
+ : trace_flag_(trace_flag) {
+ gpr_ref_init(&refs_, 1);
+ }
+
+ virtual ~RefCountedWithTracing() {}
+
+ private:
+ TraceFlag* trace_flag_ = nullptr;
+ gpr_refcount refs_;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H */
diff --git a/src/core/lib/support/ref_counted_ptr.h b/src/core/lib/support/ref_counted_ptr.h
new file mode 100644
index 0000000000..dc2385e369
--- /dev/null
+++ b/src/core/lib/support/ref_counted_ptr.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * 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_REF_COUNTED_PTR_H
+#define GRPC_CORE_LIB_SUPPORT_REF_COUNTED_PTR_H
+
+#include <utility>
+
+#include "src/core/lib/support/memory.h"
+
+namespace grpc_core {
+
+// A smart pointer class for objects that provide Ref() and Unref() methods,
+// such as those provided by the RefCounted base class.
+template <typename T>
+class RefCountedPtr {
+ public:
+ RefCountedPtr() {}
+
+ // If value is non-null, we take ownership of a ref to it.
+ explicit RefCountedPtr(T* value) { value_ = value; }
+
+ // Move support.
+ RefCountedPtr(RefCountedPtr&& other) {
+ value_ = other.value_;
+ other.value_ = nullptr;
+ }
+ RefCountedPtr& operator=(RefCountedPtr&& other) {
+ if (value_ != nullptr) value_->Unref();
+ value_ = other.value_;
+ other.value_ = nullptr;
+ return *this;
+ }
+
+ // Copy support.
+ RefCountedPtr(const RefCountedPtr& other) {
+ if (other.value_ != nullptr) other.value_->Ref();
+ value_ = other.value_;
+ }
+ RefCountedPtr& operator=(const RefCountedPtr& other) {
+ // Note: Order of reffing and unreffing is important here in case value_
+ // and other.value_ are the same object.
+ if (other.value_ != nullptr) other.value_->Ref();
+ if (value_ != nullptr) value_->Unref();
+ value_ = other.value_;
+ return *this;
+ }
+
+ ~RefCountedPtr() {
+ if (value_ != nullptr) value_->Unref();
+ }
+
+ // If value is non-null, we take ownership of a ref to it.
+ void reset(T* value = nullptr) {
+ if (value_ != nullptr) value_->Unref();
+ value_ = value;
+ }
+
+ T* get() const { return value_; }
+
+ T& operator*() const { return *value_; }
+ T* operator->() const { return value_; }
+
+ private:
+ T* value_ = nullptr;
+};
+
+template <typename T, typename... Args>
+inline RefCountedPtr<T> MakeRefCounted(Args&&... args) {
+ return RefCountedPtr<T>(New<T>(std::forward<Args>(args)...));
+}
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_REF_COUNTED_PTR_H */
diff --git a/src/core/lib/support/stack_lockfree.cc b/src/core/lib/support/stack_lockfree.cc
deleted file mode 100644
index 7a4ede3b92..0000000000
--- a/src/core/lib/support/stack_lockfree.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
-
-#include "src/core/lib/support/stack_lockfree.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-
-/* The lockfree node structure is a single architecture-level
- word that allows for an atomic CAS to set it up. */
-struct lockfree_node_contents {
- /* next thing to look at. Actual index for head, next index otherwise */
- uint16_t index;
-#ifdef GPR_ARCH_64
- uint16_t pad;
- uint32_t aba_ctr;
-#else
-#ifdef GPR_ARCH_32
- uint16_t aba_ctr;
-#else
-#error Unsupported bit width architecture
-#endif
-#endif
-};
-
-/* Use a union to make sure that these are in the same bits as an atm word */
-typedef union lockfree_node {
- gpr_atm atm;
- struct lockfree_node_contents contents;
-} lockfree_node;
-
-/* make sure that entries aligned to 8-bytes */
-#define ENTRY_ALIGNMENT_BITS 3
-/* reserve this entry as invalid */
-#define INVALID_ENTRY_INDEX ((1 << 16) - 1)
-
-struct gpr_stack_lockfree {
- lockfree_node* entries;
- lockfree_node head; /* An atomic entry describing curr head */
-};
-
-gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries) {
- gpr_stack_lockfree* stack;
- stack = (gpr_stack_lockfree*)gpr_malloc(sizeof(*stack));
- /* Since we only allocate 16 bits to represent an entry number,
- * make sure that we are within the desired range */
- /* Reserve the highest entry number as a dummy */
- GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
- stack->entries = (lockfree_node*)gpr_malloc_aligned(
- entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS);
- /* Clear out all entries */
- memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
- memset(&stack->head, 0, sizeof(stack->head));
-
- GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents));
-
- /* Point the head at reserved dummy entry */
- stack->head.contents.index = INVALID_ENTRY_INDEX;
-/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
-#ifdef GPR_ARCH_64
- stack->head.contents.pad = 0;
-#endif
- stack->head.contents.aba_ctr = 0;
- return stack;
-}
-
-void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack) {
- gpr_free_aligned(stack->entries);
- gpr_free(stack);
-}
-
-int gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry) {
- lockfree_node head;
- lockfree_node newhead;
- lockfree_node curent;
- lockfree_node newent;
-
- /* First fill in the entry's index and aba ctr for new head */
- newhead.contents.index = (uint16_t)entry;
-#ifdef GPR_ARCH_64
- /* Fill in the pad to avoid confusing memcheck tools */
- newhead.contents.pad = 0;
-#endif
-
- /* Also post-increment the aba_ctr */
- curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
- newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
- gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm);
-
- do {
- /* Atomically get the existing head value for use */
- head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
- /* Point to it */
- newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
- newent.contents.index = head.contents.index;
- gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm);
- } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
- /* Use rel_cas above to make sure that entry index is set properly */
- return head.contents.index == INVALID_ENTRY_INDEX;
-}
-
-int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack) {
- lockfree_node head;
- lockfree_node newhead;
-
- do {
- head.atm = gpr_atm_acq_load(&(stack->head.atm));
- if (head.contents.index == INVALID_ENTRY_INDEX) {
- return -1;
- }
- newhead.atm =
- gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
-
- } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
-
- return head.contents.index;
-}
diff --git a/src/core/lib/support/stack_lockfree.h b/src/core/lib/support/stack_lockfree.h
deleted file mode 100644
index 337ecc2b17..0000000000
--- a/src/core/lib/support/stack_lockfree.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *
- * Copyright 2015 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_STACK_LOCKFREE_H
-#define GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct gpr_stack_lockfree gpr_stack_lockfree;
-
-/* This stack must specify the maximum number of entries to track.
- The current implementation only allows up to 65534 entries */
-gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries);
-void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
-
-/* Pass in a valid entry number for the next stack entry */
-/* Returns 1 if this is the first element on the stack, 0 otherwise */
-int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry);
-
-/* Returns -1 on empty or the actual entry number */
-int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H */
diff --git a/src/core/lib/support/thd_internal.h b/src/core/lib/support/thd_internal.h
new file mode 100644
index 0000000000..38bffc847d
--- /dev/null
+++ b/src/core/lib/support/thd_internal.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2015 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_THD_INTERNAL_H
+#define GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H
+
+#include <grpc/support/time.h>
+
+/* Internal interfaces between modules within the gpr support library. */
+void gpr_thd_init();
+
+/* Wait for all outstanding threads to finish, up to deadline */
+int gpr_await_threads(gpr_timespec deadline);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/lib/support/thd_posix.cc b/src/core/lib/support/thd_posix.cc
index 02e3846be1..c2a4f4198f 100644
--- a/src/core/lib/support/thd_posix.cc
+++ b/src/core/lib/support/thd_posix.cc
@@ -24,22 +24,34 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
+#include "src/core/lib/support/fork.h"
+
+static gpr_mu g_mu;
+static gpr_cv g_cv;
+static int g_thread_count;
+static int g_awaiting_threads;
+
struct thd_arg {
void (*body)(void* arg); /* body of a thread */
void* arg; /* argument to a thread */
};
+static void inc_thd_count();
+static void dec_thd_count();
+
/* Body of every thread started via gpr_thd_new. */
static void* thread_body(void* v) {
struct thd_arg a = *(struct thd_arg*)v;
free(v);
(*a.body)(a.arg);
+ dec_thd_count();
return nullptr;
}
@@ -54,6 +66,7 @@ int gpr_thd_new(gpr_thd_id* t, void (*thd_body)(void* arg), void* arg,
GPR_ASSERT(a != nullptr);
a->body = thd_body;
a->arg = arg;
+ inc_thd_count();
GPR_ASSERT(pthread_attr_init(&attr) == 0);
if (gpr_thd_options_is_detached(options)) {
@@ -68,6 +81,7 @@ int gpr_thd_new(gpr_thd_id* t, void (*thd_body)(void* arg), void* arg,
if (!thread_started) {
/* don't use gpr_free, as this was allocated using malloc (see above) */
free(a);
+ dec_thd_count();
}
*t = (gpr_thd_id)p;
return thread_started;
@@ -77,4 +91,46 @@ gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); }
+/*****************************************
+ * Only used when fork support is enabled
+ */
+
+static void inc_thd_count() {
+ if (grpc_fork_support_enabled()) {
+ gpr_mu_lock(&g_mu);
+ g_thread_count++;
+ gpr_mu_unlock(&g_mu);
+ }
+}
+
+static void dec_thd_count() {
+ if (grpc_fork_support_enabled()) {
+ gpr_mu_lock(&g_mu);
+ g_thread_count--;
+ if (g_awaiting_threads && g_thread_count == 0) {
+ gpr_cv_signal(&g_cv);
+ }
+ gpr_mu_unlock(&g_mu);
+ }
+}
+
+void gpr_thd_init() {
+ gpr_mu_init(&g_mu);
+ gpr_cv_init(&g_cv);
+ g_thread_count = 0;
+ g_awaiting_threads = 0;
+}
+
+int gpr_await_threads(gpr_timespec deadline) {
+ gpr_mu_lock(&g_mu);
+ g_awaiting_threads = 1;
+ int res = 0;
+ if (g_thread_count > 0) {
+ res = gpr_cv_wait(&g_cv, &g_mu, deadline);
+ }
+ g_awaiting_threads = 0;
+ gpr_mu_unlock(&g_mu);
+ return res == 0;
+}
+
#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/support/thd_windows.cc b/src/core/lib/support/thd_windows.cc
index 5bda7f440c..0875c2f03e 100644
--- a/src/core/lib/support/thd_windows.cc
+++ b/src/core/lib/support/thd_windows.cc
@@ -50,6 +50,8 @@ static void destroy_thread(struct thd_info* t) {
gpr_free(t);
}
+void gpr_thd_init(void) {}
+
/* Body of every thread started via gpr_thd_new. */
static DWORD WINAPI thread_body(void* v) {
g_thd_info = (struct thd_info*)v;
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index f96d8eba6c..5eb5a56ebb 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -21,6 +21,7 @@
#include <limits.h>
#include <memory.h>
+#include <grpc/fork.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@@ -39,6 +40,8 @@
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/support/fork.h"
+#include "src/core/lib/support/thd_internal.h"
#include "src/core/lib/surface/alarm_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -62,10 +65,12 @@ static int g_initializations;
static void do_basic_init(void) {
gpr_log_verbosity_init();
+ grpc_fork_support_init();
gpr_mu_init(&g_init_mu);
grpc_register_built_in_plugins();
grpc_cq_global_init();
g_initializations = 0;
+ grpc_fork_handlers_auto_register();
}
static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
@@ -119,6 +124,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
+ gpr_thd_init();
grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index e9c92b04dc..4f07183180 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -801,7 +801,7 @@ static void channel_connectivity_changed(void* cd, grpc_error* error) {
grpc_server* server = chand->server;
if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
grpc_transport_op* op = grpc_make_transport_op(nullptr);
- op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+ op->on_connectivity_state_change = &chand->channel_connectivity_changed;
op->connectivity_state = &chand->connectivity_state;
grpc_channel_next_op(grpc_channel_stack_element(
grpc_channel_get_channel_stack(chand->channel), 0),
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index f4feadc640..7d36c6c9e1 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -23,4 +23,4 @@
const char* grpc_version_string(void) { return "5.0.0-dev"; }
-const char* grpc_g_stands_for(void) { return "generous"; }
+const char* grpc_g_stands_for(void) { return "glossy"; }
diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc
index 2e878b7f10..08aee04ac9 100644
--- a/src/core/lib/transport/transport.cc
+++ b/src/core/lib/transport/transport.cc
@@ -100,7 +100,7 @@ grpc_slice grpc_slice_from_stream_owned_buffer(grpc_stream_refcount* refcount,
void* buffer, size_t length) {
slice_stream_ref(&refcount->slice_refcount);
grpc_slice res;
- res.refcount = &refcount->slice_refcount,
+ res.refcount = &refcount->slice_refcount;
res.data.refcounted.bytes = (uint8_t*)buffer;
res.data.refcounted.length = length;
return res;