Use Baton (again) in EventBase::runInEventBaseThreadAndWait
[folly.git] / folly / io / async / Request.h
index 194305fc3727622cffd736b37d2cdbc9735e05ff..a4b7a23a17d78aadd340ede0b697fa7bf10b7be2 100644 (file)
@@ -1,28 +1,26 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2004-present Facebook, Inc.
  *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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
+ * 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.
+ * 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.
  */
+
 #pragma once
 
 #include <map>
 #include <memory>
-#include <folly/RWSpinLock.h>
+
+#include <folly/SharedMutex.h>
+#include <folly/Synchronized.h>
 
 namespace folly {
 
@@ -32,6 +30,10 @@ namespace folly {
 class RequestData {
  public:
   virtual ~RequestData() = default;
+  // Avoid calling RequestContext::setContextData, setContextDataIfAbsent, or
+  // clearContextData from these callbacks. Doing so will cause deadlock. We
+  // could fix these deadlocks, but only at significant performance penalty, so
+  // just don't do it!
   virtual void onSet() {}
   virtual void onUnset() {}
 };
@@ -47,18 +49,11 @@ class RequestContext {
   // It will be passed between queues / threads (where implemented),
   // so it should be valid for the lifetime of the request.
   static void create() {
-    getStaticContext() = std::make_shared<RequestContext>();
+    setContext(std::make_shared<RequestContext>());
   }
 
   // Get the current context.
-  static RequestContext* get() {
-    auto context = getStaticContext();
-    if (!context) {
-      static RequestContext defaultContext;
-      return std::addressof(defaultContext);
-    }
-    return context.get();
-  }
+  static RequestContext* get();
 
   // The following API may be used to set per-request data in a thread-safe way.
   // This access is still performance sensitive, so please ask if you need help
@@ -103,8 +98,8 @@ class RequestContext {
  private:
   static std::shared_ptr<RequestContext>& getStaticContext();
 
-  mutable folly::RWSpinLock lock;
-  std::map<std::string, std::unique_ptr<RequestData>> data_;
+  using Data = std::map<std::string, std::unique_ptr<RequestData>>;
+  folly::Synchronized<Data, folly::SharedMutex> data_;
 };
 
 class RequestContextScopeGuard {
@@ -112,6 +107,11 @@ class RequestContextScopeGuard {
   std::shared_ptr<RequestContext> prev_;
 
  public:
+  RequestContextScopeGuard(const RequestContextScopeGuard&) = delete;
+  RequestContextScopeGuard& operator=(const RequestContextScopeGuard&) = delete;
+  RequestContextScopeGuard(RequestContextScopeGuard&&) = delete;
+  RequestContextScopeGuard& operator=(RequestContextScopeGuard&&) = delete;
+
   // Create a new RequestContext and reset to the original value when
   // this goes out of scope.
   RequestContextScopeGuard() : prev_(RequestContext::saveContext()) {
@@ -121,7 +121,8 @@ class RequestContextScopeGuard {
   // Set a RequestContext that was previously captured by saveContext(). It will
   // be automatically reset to the original value when this goes out of scope.
   explicit RequestContextScopeGuard(std::shared_ptr<RequestContext> ctx)
-      : prev_(RequestContext::setContext(std::move(ctx))) {}
+      : prev_(RequestContext::setContext(std::move(ctx))) {
+  }
 
   ~RequestContextScopeGuard() {
     RequestContext::setContext(std::move(prev_));