Home | History | Annotate | Download | only in system
      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/edk/system/request_context.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "base/logging.h"
      9 #include "base/threading/thread_local.h"
     10 
     11 namespace mojo {
     12 namespace edk {
     13 
     14 namespace {
     15 
     16 base::LazyInstance<base::ThreadLocalPointer<RequestContext>>::Leaky
     17     g_current_context = LAZY_INSTANCE_INITIALIZER;
     18 
     19 }  // namespace
     20 
     21 RequestContext::RequestContext() : RequestContext(Source::LOCAL_API_CALL) {}
     22 
     23 RequestContext::RequestContext(Source source)
     24     : source_(source), tls_context_(g_current_context.Pointer()) {
     25   // We allow nested RequestContexts to exist as long as they aren't actually
     26   // used for anything.
     27   if (!tls_context_->Get())
     28     tls_context_->Set(this);
     29 }
     30 
     31 RequestContext::~RequestContext() {
     32   if (IsCurrent()) {
     33     // NOTE: Callbacks invoked by this destructor are allowed to initiate new
     34     // EDK requests on this thread, so we need to reset the thread-local context
     35     // pointer before calling them. We persist the original notification source
     36     // since we're starting over at the bottom of the stack.
     37     tls_context_->Set(nullptr);
     38 
     39     MojoWatchNotificationFlags flags = MOJO_WATCH_NOTIFICATION_FLAG_NONE;
     40     if (source_ == Source::SYSTEM)
     41       flags |= MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM;
     42 
     43     // We run all cancellation finalizers first. This is necessary because it's
     44     // possible that one of the cancelled watchers has other pending finalizers
     45     // attached to this RequestContext.
     46     //
     47     // From the application's perspective the watch has already been cancelled,
     48     // so we have to honor our contract which guarantees no more notifications.
     49     for (const scoped_refptr<Watcher>& watcher :
     50             watch_cancel_finalizers_.container())
     51       watcher->Cancel();
     52 
     53     for (const WatchNotifyFinalizer& watch :
     54         watch_notify_finalizers_.container()) {
     55       // Establish a new request context for the extent of each callback to
     56       // ensure that they don't themselves invoke callbacks while holding a
     57       // watcher lock.
     58       RequestContext request_context(source_);
     59       watch.watcher->MaybeInvokeCallback(watch.result, watch.state, flags);
     60     }
     61   } else {
     62     // It should be impossible for nested contexts to have finalizers.
     63     DCHECK(watch_notify_finalizers_.container().empty());
     64     DCHECK(watch_cancel_finalizers_.container().empty());
     65   }
     66 }
     67 
     68 // static
     69 RequestContext* RequestContext::current() {
     70   DCHECK(g_current_context.Pointer()->Get());
     71   return g_current_context.Pointer()->Get();
     72 }
     73 
     74 void RequestContext::AddWatchNotifyFinalizer(
     75     scoped_refptr<Watcher> watcher,
     76     MojoResult result,
     77     const HandleSignalsState& state) {
     78   DCHECK(IsCurrent());
     79   watch_notify_finalizers_->push_back(
     80       WatchNotifyFinalizer(watcher, result, state));
     81 }
     82 
     83 void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watcher> watcher) {
     84   DCHECK(IsCurrent());
     85   watch_cancel_finalizers_->push_back(watcher);
     86 }
     87 
     88 bool RequestContext::IsCurrent() const {
     89   return tls_context_->Get() == this;
     90 }
     91 
     92 RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
     93     scoped_refptr<Watcher> watcher,
     94     MojoResult result,
     95     const HandleSignalsState& state)
     96     : watcher(watcher), result(result), state(state) {
     97 }
     98 
     99 RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
    100     const WatchNotifyFinalizer& other) = default;
    101 
    102 RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() {}
    103 
    104 }  // namespace edk
    105 }  // namespace mojo
    106