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/core/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 core { 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 MojoTrapEventFlags flags = MOJO_TRAP_EVENT_FLAG_NONE; 40 if (source_ == Source::LOCAL_API_CALL) 41 flags |= MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL; 42 43 // We send all cancellation notifications first. This is necessary because 44 // it's possible that cancelled watches have other pending notifications 45 // attached to this RequestContext. 46 // 47 // From the application's perspective the watch is cancelled as soon as this 48 // notification is received, and dispatching the cancellation notification 49 // updates some internal Watch state to ensure no further notifications 50 // fire. Because notifications on a single Watch are mutually exclusive, 51 // this is sufficient to guarantee that MOJO_RESULT_CANCELLED is the last 52 // notification received; which is the guarantee the API makes. 53 for (const scoped_refptr<Watch>& watch : 54 watch_cancel_finalizers_.container()) { 55 static const HandleSignalsState closed_state = {0, 0}; 56 57 // Establish a new RequestContext to capture and run any new notifications 58 // triggered by the callback invocation. Note that while it would be safe 59 // to inherit |source_| from the perspective of Mojo core re-entrancy, 60 // upper application layers may use the flag as a signal to allow 61 // synchronous event dispatch and in turn shoot themselves in the foot 62 // with e.g. mutually recursive event handlers. We avoid that by 63 // treating all nested trap events as if they originated from a local API 64 // call even if this is a system RequestContext. 65 RequestContext inner_context(Source::LOCAL_API_CALL); 66 watch->InvokeCallback(MOJO_RESULT_CANCELLED, closed_state, flags); 67 } 68 69 for (const WatchNotifyFinalizer& watch : 70 watch_notify_finalizers_.container()) { 71 RequestContext inner_context(source_); 72 watch.watch->InvokeCallback(watch.result, watch.state, flags); 73 } 74 } else { 75 // It should be impossible for nested contexts to have finalizers. 76 DCHECK(watch_notify_finalizers_.container().empty()); 77 DCHECK(watch_cancel_finalizers_.container().empty()); 78 } 79 } 80 81 // static 82 RequestContext* RequestContext::current() { 83 DCHECK(g_current_context.Pointer()->Get()); 84 return g_current_context.Pointer()->Get(); 85 } 86 87 void RequestContext::AddWatchNotifyFinalizer(scoped_refptr<Watch> watch, 88 MojoResult result, 89 const HandleSignalsState& state) { 90 DCHECK(IsCurrent()); 91 watch_notify_finalizers_->push_back( 92 WatchNotifyFinalizer(std::move(watch), result, state)); 93 } 94 95 void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watch> watch) { 96 DCHECK(IsCurrent()); 97 watch_cancel_finalizers_->push_back(std::move(watch)); 98 } 99 100 bool RequestContext::IsCurrent() const { 101 return tls_context_->Get() == this; 102 } 103 104 RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer( 105 scoped_refptr<Watch> watch, 106 MojoResult result, 107 const HandleSignalsState& state) 108 : watch(std::move(watch)), result(result), state(state) {} 109 110 RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer( 111 const WatchNotifyFinalizer& other) = default; 112 113 RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() {} 114 115 } // namespace core 116 } // namespace mojo 117