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/lazy_instance.h"
     10 #include "base/logging.h"
     11 #include "base/threading/thread_local.h"
     12 #include "mojo/public/c/system/core.h"
     13 
     14 namespace mojo {
     15 
     16 namespace {
     17 
     18 class SyncCallSettings {
     19  public:
     20   static SyncCallSettings* current();
     21 
     22   bool allowed() const {
     23     return scoped_allow_count_ > 0 || system_defined_value_;
     24   }
     25 
     26   void IncreaseScopedAllowCount() { scoped_allow_count_++; }
     27   void DecreaseScopedAllowCount() {
     28     DCHECK_LT(0u, scoped_allow_count_);
     29     scoped_allow_count_--;
     30   }
     31 
     32  private:
     33   SyncCallSettings();
     34   ~SyncCallSettings();
     35 
     36   bool system_defined_value_ = true;
     37   size_t scoped_allow_count_ = 0;
     38 };
     39 
     40 base::LazyInstance<base::ThreadLocalPointer<SyncCallSettings>>
     41     g_sync_call_settings = LAZY_INSTANCE_INITIALIZER;
     42 
     43 // static
     44 SyncCallSettings* SyncCallSettings::current() {
     45   SyncCallSettings* result = g_sync_call_settings.Pointer()->Get();
     46   if (!result) {
     47     result = new SyncCallSettings();
     48     DCHECK_EQ(result, g_sync_call_settings.Pointer()->Get());
     49   }
     50   return result;
     51 }
     52 
     53 SyncCallSettings::SyncCallSettings() {
     54   MojoResult result = MojoGetProperty(MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED,
     55                                       &system_defined_value_);
     56   DCHECK_EQ(MOJO_RESULT_OK, result);
     57 
     58   DCHECK(!g_sync_call_settings.Pointer()->Get());
     59   g_sync_call_settings.Pointer()->Set(this);
     60 }
     61 
     62 SyncCallSettings::~SyncCallSettings() {
     63   g_sync_call_settings.Pointer()->Set(nullptr);
     64 }
     65 
     66 }  // namespace
     67 
     68 // static
     69 void SyncCallRestrictions::AssertSyncCallAllowed() {
     70   if (!SyncCallSettings::current()->allowed()) {
     71       LOG(FATAL) << "Mojo sync calls are not allowed in this process because "
     72                  << "they can lead to jank and deadlock. If you must make an "
     73                  << "exception, please see "
     74                  << "SyncCallRestrictions::ScopedAllowSyncCall and consult "
     75                  << "mojo/OWNERS.";
     76   }
     77 }
     78 
     79 // static
     80 void SyncCallRestrictions::IncreaseScopedAllowCount() {
     81   SyncCallSettings::current()->IncreaseScopedAllowCount();
     82 }
     83 
     84 // static
     85 void SyncCallRestrictions::DecreaseScopedAllowCount() {
     86   SyncCallSettings::current()->DecreaseScopedAllowCount();
     87 }
     88 
     89 }  // namespace mojo
     90 
     91 #endif  // ENABLE_SYNC_CALL_RESTRICTIONS
     92