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