request_context.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. #include "mojo/core/request_context.h"
  5. #include "base/check.h"
  6. #include "base/lazy_instance.h"
  7. #include "base/threading/thread_local.h"
  8. namespace mojo {
  9. namespace core {
  10. namespace {
  11. base::LazyInstance<base::ThreadLocalPointer<RequestContext>>::Leaky
  12. g_current_context = LAZY_INSTANCE_INITIALIZER;
  13. } // namespace
  14. RequestContext::RequestContext() : RequestContext(Source::LOCAL_API_CALL) {}
  15. RequestContext::RequestContext(Source source)
  16. : source_(source), tls_context_(g_current_context.Pointer()) {
  17. // We allow nested RequestContexts to exist as long as they aren't actually
  18. // used for anything.
  19. if (!tls_context_->Get())
  20. tls_context_->Set(this);
  21. }
  22. RequestContext::~RequestContext() {
  23. if (IsCurrent()) {
  24. // NOTE: Callbacks invoked by this destructor are allowed to initiate new
  25. // EDK requests on this thread, so we need to reset the thread-local context
  26. // pointer before calling them. We persist the original notification source
  27. // since we're starting over at the bottom of the stack.
  28. tls_context_->Set(nullptr);
  29. MojoTrapEventFlags flags = MOJO_TRAP_EVENT_FLAG_NONE;
  30. if (source_ == Source::LOCAL_API_CALL)
  31. flags |= MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL;
  32. // We send all cancellation notifications first. This is necessary because
  33. // it's possible that cancelled watches have other pending notifications
  34. // attached to this RequestContext.
  35. //
  36. // From the application's perspective the watch is cancelled as soon as this
  37. // notification is received, and dispatching the cancellation notification
  38. // updates some internal Watch state to ensure no further notifications
  39. // fire. Because notifications on a single Watch are mutually exclusive,
  40. // this is sufficient to guarantee that MOJO_RESULT_CANCELLED is the last
  41. // notification received; which is the guarantee the API makes.
  42. for (const scoped_refptr<Watch>& watch :
  43. watch_cancel_finalizers_.container()) {
  44. static const HandleSignalsState closed_state = {0, 0};
  45. // Establish a new RequestContext to capture and run any new notifications
  46. // triggered by the callback invocation. Note that while it would be safe
  47. // to inherit |source_| from the perspective of Mojo core re-entrancy,
  48. // upper application layers may use the flag as a signal to allow
  49. // synchronous event dispatch and in turn shoot themselves in the foot
  50. // with e.g. mutually recursive event handlers. We avoid that by
  51. // treating all nested trap events as if they originated from a local API
  52. // call even if this is a system RequestContext.
  53. RequestContext inner_context(Source::LOCAL_API_CALL);
  54. watch->InvokeCallback(MOJO_RESULT_CANCELLED, closed_state, flags);
  55. }
  56. for (const WatchNotifyFinalizer& watch :
  57. watch_notify_finalizers_.container()) {
  58. RequestContext inner_context(source_);
  59. watch.watch->InvokeCallback(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. // static
  68. RequestContext* RequestContext::current() {
  69. DCHECK(g_current_context.Pointer()->Get());
  70. return g_current_context.Pointer()->Get();
  71. }
  72. void RequestContext::AddWatchNotifyFinalizer(scoped_refptr<Watch> watch,
  73. MojoResult result,
  74. const HandleSignalsState& state) {
  75. DCHECK(IsCurrent());
  76. watch_notify_finalizers_->push_back(
  77. WatchNotifyFinalizer(std::move(watch), result, state));
  78. }
  79. void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watch> watch) {
  80. DCHECK(IsCurrent());
  81. watch_cancel_finalizers_->push_back(std::move(watch));
  82. }
  83. bool RequestContext::IsCurrent() const {
  84. return tls_context_->Get() == this;
  85. }
  86. RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
  87. scoped_refptr<Watch> watch,
  88. MojoResult result,
  89. const HandleSignalsState& state)
  90. : watch(std::move(watch)), result(result), state(state) {}
  91. RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
  92. const WatchNotifyFinalizer& other) = default;
  93. RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() = default;
  94. } // namespace core
  95. } // namespace mojo