Home | History | Annotate | Download | only in lib
      1 // Copyright 2016 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
      6 
      7 #if ENABLE_SYNC_CALL_RESTRICTIONS
      8 
      9 #include "base/debug/leak_annotations.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/logging.h"
     12 #include "base/threading/thread_local.h"
     13 #include "mojo/public/c/system/core.h"
     14 
     15 namespace mojo {
     16 
     17 namespace {
     18 
     19 class SyncCallSettings {
     20  public:
     21   static SyncCallSettings* current();
     22 
     23   bool allowed() const {
     24     return scoped_allow_count_ > 0 || system_defined_value_;
     25   }
     26 
     27   void IncreaseScopedAllowCount() { scoped_allow_count_++; }
     28   void DecreaseScopedAllowCount() {
     29     DCHECK_LT(0u, scoped_allow_count_);
     30     scoped_allow_count_--;
     31   }
     32 
     33  private:
     34   SyncCallSettings();
     35   ~SyncCallSettings();
     36 
     37   bool system_defined_value_ = true;
     38   size_t scoped_allow_count_ = 0;
     39 };
     40 
     41 base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>::DestructorAtExit
     42     g_sync_call_settings = LAZY_INSTANCE_INITIALIZER;
     43 
     44 // static
     45 SyncCallSettings* SyncCallSettings::current() {
     46   SyncCallSettings* result = g_sync_call_settings.Pointer()->Get();
     47   if (!result) {
     48     result = new SyncCallSettings();
     49     ANNOTATE_LEAKING_OBJECT_PTR(result);
     50     DCHECK_EQ(result, g_sync_call_settings.Pointer()->Get());
     51   }
     52   return result;
     53 }
     54 
     55 SyncCallSettings::SyncCallSettings() {
     56   MojoResult result = MojoGetProperty(MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED,
     57                                       &system_defined_value_);
     58   DCHECK_EQ(MOJO_RESULT_OK, result);
     59 
     60   DCHECK(!g_sync_call_settings.Pointer()->Get());
     61   g_sync_call_settings.Pointer()->Set(this);
     62 }
     63 
     64 SyncCallSettings::~SyncCallSettings() {
     65   g_sync_call_settings.Pointer()->Set(nullptr);
     66 }
     67 
     68 }  // namespace
     69 
     70 // static
     71 void SyncCallRestrictions::AssertSyncCallAllowed() {
     72   if (!SyncCallSettings::current()->allowed()) {
     73       LOG(FATAL) << "Mojo sync calls are not allowed in this process because "
     74                  << "they can lead to jank and deadlock. If you must make an "
     75                  << "exception, please see "
     76                  << "SyncCallRestrictions::ScopedAllowSyncCall and consult "
     77                  << "mojo/OWNERS.";
     78   }
     79 }
     80 
     81 // static
     82 void SyncCallRestrictions::IncreaseScopedAllowCount() {
     83   SyncCallSettings::current()->IncreaseScopedAllowCount();
     84 }
     85 
     86 // static
     87 void SyncCallRestrictions::DecreaseScopedAllowCount() {
     88   SyncCallSettings::current()->DecreaseScopedAllowCount();
     89 }
     90 
     91 }  // namespace mojo
     92 
     93 #endif  // ENABLE_SYNC_CALL_RESTRICTIONS
     94