1 // Copyright 2018 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #include <object/pager_dispatcher.h>
8 #include <trace.h>
9 #include <vm/page_source.h>
10
11 #define LOCAL_TRACE 0
12
Create(fbl::RefPtr<Dispatcher> * dispatcher,zx_rights_t * rights)13 zx_status_t PagerDispatcher::Create(fbl::RefPtr<Dispatcher>* dispatcher, zx_rights_t* rights) {
14 fbl::AllocChecker ac;
15 auto disp = new (&ac) PagerDispatcher();
16 if (!ac.check()) {
17 return ZX_ERR_NO_MEMORY;
18 }
19
20 *rights = default_rights();
21 *dispatcher = fbl::AdoptRef<Dispatcher>(disp);
22 return ZX_OK;
23 }
24
PagerDispatcher()25 PagerDispatcher::PagerDispatcher() : SoloDispatcher() {}
26
~PagerDispatcher()27 PagerDispatcher::~PagerDispatcher() {}
28
CreateSource(fbl::RefPtr<PortDispatcher> port,uint64_t key,fbl::RefPtr<PageSource> * src_out)29 zx_status_t PagerDispatcher::CreateSource(fbl::RefPtr<PortDispatcher> port,
30 uint64_t key, fbl::RefPtr<PageSource>* src_out) {
31 fbl::AllocChecker ac;
32 auto wrapper = fbl::make_unique_checked<PageSourceWrapper>(&ac, this, ktl::move(port), key);
33 if (!ac.check()) {
34 return ZX_ERR_NO_MEMORY;
35 }
36
37 auto src = fbl::AdoptRef(new (&ac) PageSource(wrapper.get(), get_koid()));
38 if (!ac.check()) {
39 return ZX_ERR_NO_MEMORY;
40 }
41
42 fbl::AutoLock lock(&wrapper->mtx_);
43 wrapper->src_ = src;
44
45 fbl::AutoLock lock2(&mtx_);
46 srcs_.push_front(ktl::move(wrapper));
47
48 *src_out = ktl::move(src);
49 return ZX_OK;
50 }
51
ReleaseSource(PageSourceWrapper * src)52 void PagerDispatcher::ReleaseSource(PageSourceWrapper* src) {
53 fbl::AutoLock lock(&mtx_);
54 srcs_.erase(*src);
55 }
56
on_zero_handles()57 void PagerDispatcher::on_zero_handles() {
58 fbl::DoublyLinkedList<fbl::unique_ptr<PageSourceWrapper>> srcs;
59
60 mtx_.Acquire();
61 while (!srcs_.is_empty()) {
62 auto& src = srcs_.front();
63 fbl::RefPtr<PageSource> inner;
64 {
65 fbl::AutoLock lock(&src.mtx_);
66 inner = src.src_;
67 }
68
69 // Call close outside of the lock, since it will call back into ::OnClose.
70 mtx_.Release();
71 if (inner) {
72 inner->Close();
73 }
74 mtx_.Acquire();
75 }
76 mtx_.Release();
77 }
78
PageSourceWrapper(PagerDispatcher * dispatcher,fbl::RefPtr<PortDispatcher> port,uint64_t key)79 PageSourceWrapper::PageSourceWrapper(PagerDispatcher* dispatcher,
80 fbl::RefPtr<PortDispatcher> port, uint64_t key)
81 : pager_(dispatcher), port_(ktl::move(port)), key_(key) {
82 LTRACEF("%p key %lx\n", this, key_);
83 }
84
~PageSourceWrapper()85 PageSourceWrapper::~PageSourceWrapper() {
86 LTRACEF("%p\n", this);
87 DEBUG_ASSERT(closed_);
88 }
89
OnClose()90 void PageSourceWrapper::OnClose() {
91 {
92 fbl::AutoLock lock(&mtx_);
93 closed_ = true;
94 }
95 pager_->ReleaseSource(this);
96 }
97