1 /*
2  * (c) 2009 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9 /*
10  * Copyright (C) 2015 Kernkonzept GmbH.
11  * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
12  *
13  */
14 #pragma once
15 
16 #include <l4/cxx/exceptions>
17 
18 #include <new>
19 #include <cstddef>
20 #include <cstdio>
21 #include <cassert>
22 
23 #include "malloc.h"
24 #include "page_alloc.h"
25 
26 namespace Moe {
27 
28 /**
29  * A simple quota manager.
30  */
31 class Quota
32 {
33 public:
Quota(size_t limit)34   explicit Quota(size_t limit) : _limit(limit), _used(0) {}
alloc(size_t s)35   bool alloc(size_t s)
36   {
37     if (_limit && (s > _limit || _used > _limit - s))
38       return false;
39 
40     _used += s;
41     //printf("Q: alloc(%zx) -> %zx\n", s, _used);
42     return true;
43   }
44 
free(size_t s)45   void free(size_t s)
46   {
47     assert(s <= _used);
48     _used -= s;
49     //printf("Q: free(%zx) -> %zx\n", s, _used);
50   }
51 
limit()52   size_t limit() const { return _limit; }
used()53   size_t used() const { return _used; }
54 
55 private:
56   size_t _limit;
57   size_t _used;
58 };
59 
60 /**
61  * Quota allocator that cleans up on unexpected exit.
62  */
63 struct Quota_guard
64 {
65   Quota *q;
66   size_t amount;
67 
Quota_guardQuota_guard68   Quota_guard() : q(0) {}
69 
Quota_guardQuota_guard70   Quota_guard(Quota *q, size_t amount) : q(q), amount(amount)
71   {
72     if (!q->alloc(amount))
73       throw L4::Out_of_memory();
74   }
75 
~Quota_guardQuota_guard76   ~Quota_guard()
77   {
78     if (q)
79       q->free(amount);
80   }
81 
releaseQuota_guard82   void release()
83   {
84     q = 0;
85   }
86 
87   Quota_guard &operator = (Quota_guard &&g)
88   {
89     if (this == &g)
90       return *this;
91 
92     if (q)
93       q->free(amount);
94 
95     q = g.q;
96     if (q)
97       amount = g.amount;
98 
99     g.release();
100 
101     return *this;
102   }
103 
104   template< typename T >
releaseQuota_guard105   T release(T t)
106   {
107     q = 0;
108     return t;
109   }
110 };
111 
112 /**
113  * Quota-guarded allocator.
114  */
115 class Q_alloc : public Malloc_container
116 {
117 public:
Q_alloc(size_t limit)118   Q_alloc(size_t limit) : _quota(limit) {}
119 
quota()120   Quota *quota() { return &_quota; }
121 
alloc_pages(unsigned long size,unsigned long align)122   void *alloc_pages(unsigned long size, unsigned long align)
123   {
124     Quota_guard g(quota(), size);
125     return g.release(Single_page_alloc_base::_alloc(size, align));
126   }
127 
free_pages(void * p,unsigned long size)128   void free_pages(void *p, unsigned long size) throw()
129   {
130     Single_page_alloc_base::_free(p, size);
131     quota()->free(size);
132   }
133 
134   void reparent(Malloc_container *new_container) override;
135 
136 protected:
137   void *get_mem() override;
138   void free_mem(void *page) override;
139 
140   Quota _quota;
141 };
142 
143 /**
144  * An object that is saved in quota storage.
145  */
146 
147 class Q_object
148 {
149 public:
qalloc()150   Q_alloc *qalloc() const
151   {
152     return static_cast<Q_alloc *>(Malloc_container::from_ptr(this));
153   }
154 };
155 
156 
157 // The static allocator for global memory
158 struct Moe_alloc : public Q_alloc
159 {
160 public:
161   static Moe_alloc *allocator();
162 
163 private:
Moe_allocMoe_alloc164   Moe_alloc() : Q_alloc(0) {}
165 };
166 
167 
168 /**
169  * An allocator that gets memory from the Q_alloc responsible for
170  * the memory where this allocator is placed.
171  */
172 template <typename T>
173 class Quota_allocator
174 {
175 public:
176   enum { can_free = true };
177 
throw()178   Quota_allocator() throw() {}
throw()179   Quota_allocator(Quota_allocator const &) throw() {}
180   Quota &operator = (Quota const &) = delete;
181 
throw()182   ~Quota_allocator() throw() {}
183 
alloc()184   T *alloc() throw()
185   {
186     auto *mc = Malloc_container::from_ptr(this);
187     return static_cast<T *>(mc->alloc(sizeof (T), alignof(T)));
188   }
189 
free(T * t)190   void free(T *t) throw()
191   {
192     auto *mc = Malloc_container::from_ptr(t);
193     mc->free(t);
194   }
195 };
196 
197 } // namespace
198 
199