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 #ifndef MOJO_CORE_REQUEST_CONTEXT_H_ 6 #define MOJO_CORE_REQUEST_CONTEXT_H_ 7 8 #include "base/containers/stack_container.h" 9 #include "base/macros.h" 10 #include "mojo/core/handle_signals_state.h" 11 #include "mojo/core/system_impl_export.h" 12 #include "mojo/core/watch.h" 13 14 namespace base { 15 template <typename T> 16 class ThreadLocalPointer; 17 } 18 19 namespace mojo { 20 namespace core { 21 22 // A RequestContext is a thread-local object which exists for the duration of 23 // a single system API call. It is constructed immediately upon EDK entry and 24 // destructed immediately before returning to the caller, after any internal 25 // locks have been released. 26 // 27 // NOTE: It is legal to construct a RequestContext while another one already 28 // exists on the current thread, but it is not safe to use the nested context 29 // for any reason. Therefore it is important to always use 30 // |RequestContext::current()| rather than referring to any local instance 31 // directly. 32 class MOJO_SYSTEM_IMPL_EXPORT RequestContext { 33 public: 34 // Identifies the source of the current stack frame's RequestContext. 35 enum class Source { 36 LOCAL_API_CALL, 37 SYSTEM, 38 }; 39 40 // Constructs a RequestContext with a LOCAL_API_CALL Source. 41 RequestContext(); 42 43 explicit RequestContext(Source source); 44 ~RequestContext(); 45 46 // Returns the current thread-local RequestContext. 47 static RequestContext* current(); 48 source()49 Source source() const { return source_; } 50 51 // Adds a finalizer to this RequestContext corresponding to a watch callback 52 // which should be triggered in response to some handle state change. If 53 // the WatcherDispatcher hasn't been closed by the time this RequestContext is 54 // destroyed, its WatchCallback will be invoked with |result| and |state| 55 // arguments. 56 void AddWatchNotifyFinalizer(scoped_refptr<Watch> watch, 57 MojoResult result, 58 const HandleSignalsState& state); 59 60 // Adds a finalizer to this RequestContext corresponding to a watch callback 61 // which should be triggered to notify of watch cancellation. This appends to 62 // a separate finalizer list from AddWatchNotifyFinalizer, as pending 63 // cancellations must always preempt other pending notifications. 64 void AddWatchCancelFinalizer(scoped_refptr<Watch> watch); 65 66 private: 67 // Is this request context the current one? 68 bool IsCurrent() const; 69 70 struct WatchNotifyFinalizer { 71 WatchNotifyFinalizer(scoped_refptr<Watch> watch, 72 MojoResult result, 73 const HandleSignalsState& state); 74 WatchNotifyFinalizer(const WatchNotifyFinalizer& other); 75 ~WatchNotifyFinalizer(); 76 77 scoped_refptr<Watch> watch; 78 MojoResult result; 79 HandleSignalsState state; 80 }; 81 82 // NOTE: This upper bound was chosen somewhat arbitrarily after observing some 83 // rare worst-case behavior in Chrome. A vast majority of RequestContexts only 84 // ever accumulate 0 or 1 finalizers. 85 static const size_t kStaticWatchFinalizersCapacity = 8; 86 87 using WatchNotifyFinalizerList = 88 base::StackVector<WatchNotifyFinalizer, kStaticWatchFinalizersCapacity>; 89 using WatchCancelFinalizerList = 90 base::StackVector<scoped_refptr<Watch>, kStaticWatchFinalizersCapacity>; 91 92 const Source source_; 93 94 WatchNotifyFinalizerList watch_notify_finalizers_; 95 WatchCancelFinalizerList watch_cancel_finalizers_; 96 97 // Pointer to the TLS context. Although this can easily be accessed via the 98 // global LazyInstance, accessing a LazyInstance has a large cost relative to 99 // the rest of this class and its usages. 100 base::ThreadLocalPointer<RequestContext>* tls_context_; 101 102 DISALLOW_COPY_AND_ASSIGN(RequestContext); 103 }; 104 105 } // namespace core 106 } // namespace mojo 107 108 #endif // MOJO_CORE_REQUEST_CONTEXT_H_ 109