1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
/* anonymous.h - Anonymous memory pager interface.
Copyright (C) 2007, 2008 Free Software Foundation, Inc.
Written by Neal H. Walfield <neal@gnu.org>.
This file is part of the GNU Hurd.
GNU Hurd is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
GNU Hurd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with GNU Hurd. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef HURD_ANONYMOUS_H
#define HURD_ANONYMOUS_H
#include <hurd/pager.h>
#include <hurd/btree.h>
#include <viengoos/addr.h>
#include <viengoos/thread.h>
/* Forward. */
struct anonymous_pager;
enum
{
/* If set, the address passed to the allocation function is
mandatory. */
ANONYMOUS_FIXED = 1 << 0,
/* If set, allocated memory need not be cleared. */
ANONYMOUS_NO_CLEAR = 1 << 1,
/* If set and there is a fill function, the implementation will
neither allocate memory nor clear the discarded bit before
calling the fill function. (Thus, allocation becomes the fill
function's responsibility.) */
ANONYMOUS_NO_ALLOC = 1 << 2,
/* If set, when a thread raises a fault while while it is in the
fill function, fill is not recursively invoked but instead,
memory is allocated (or the discarded bit cleared) as
required. */
ANONYMOUS_NO_RECURSIVE = 1 << 3,
/* Make access to the region thead-safe by blocking access to
mapped regions while a fill function is executing. The use of
this flag may prevent a mapping that would seem to fit at a
particular address from succeeding as the actual virtual
address space area may be larger than the requested area. */
ANONYMOUS_THREAD_SAFE = 1 << 4,
/* Whether to provide a full staging area. Unless this flag is
specified, the fill function may only reliably access the
indicated pages at the specified locations. If the fill
function needs to access other parts of the region (e.g., it
decompresses an image all at once, filling the whole region),
then it can specify this flag and access the backing store via
a so-called staging area. The use of this flag represents a
slight performance penalty. */
ANONYMOUS_STAGING_AREA = 1 << 5,
};
/* Generate the content for the pager ANON starting at byte OFFSET and
continuing for COUNT pages. This function will not be invoked
recursively or concurrently. The ANONYMOUS_NO_RECURSIVE flag
determines what happens if the fill function causes a fault in the
region it manages. The implementation serializes calls to the fill
function. The function may only touch other pages if it is using a
staging area (the ANONYMOUS_STAGING_AREA was set at creation
time). */
typedef bool (*anonymous_pager_fill_t) (struct anonymous_pager *anon,
uintptr_t offset, uintptr_t count,
void *pages[],
struct vg_activation_fault_info info);
#define ANONYMOUS_MAGIC 0xa707a707
struct anonymous_pager
{
struct pager pager;
uintptr_t magic;
/* The staging area. Only valid if ANONYMOUS_STAGING_AREA is
set. */
void *staging_area;
/* The implementation does not modify this value and assigns it no
specific semantic meaning; the callbacks functions are free to
use it as they see fit. */
void *cookie;
/* The rest of the variables are private to the implementation. */
/* The user's window onto the pager. */
vg_addr_t map_area;
int map_area_count;
ss_mutex_t lock;
/* The storage used by this pager. */
hurd_btree_t storage;
uintptr_t flags;
/* Activity against which storage should be allocated. */
vg_addr_t activity;
/* The policy to use when allocating memory. */
struct vg_object_policy policy;
/* If not NULL, called when a fault is raised due to lack of storage
or when a page that has been discarded is accessed. */
anonymous_pager_fill_t fill;
/* The thread in the fill function. (If none, NULL.) */
vg_thread_id_t fill_thread;
/* Used to serialize the fill function. Also protects FILL_THREAD.
If ANONYMOUS_THREAD_SAFE is set, then this lock protects the
staging area. Must be taken while holding LOCK. */
ss_mutex_t fill_lock;
};
/* Set up an anonymous pager to cover a region LENGTH bytes long.
ADDR_HINT indicates the preferred starting address. Unless
ANONYMOUS_FIXED is included in FLAGS, the implementation may choose
another address. (The region will be allocated using as_alloc.)
Both ADDR_HINT and LENGTH must be a multiple of the base page size. If
the specified region overlaps with an existing pager, EEXIST is
returned. The chosen start address is returned in *ADDR_OUT.
P specifies the policy to apply to all allocated objects in the
region.
If the caller wishes to generate the content of the region
dynamically (a so-called lazily rendered region), the caller may
pass the address of a fill function, F. This function is called
when a fault is raised due to an as-of-yet unallocated page or due
to a discarded page (the latter is only possible if
POLICY.DISCARDABLE is true). A page is first allocated (according
to whether ANONYMOUS_ZEROFILL in supplied in FLAGS) and installed.
F is then invoked with the appropriate parameters. If F itself
causes a fault on the region, F is NOT recursively invoked. The
behavior is defined by the value of the ANONYMOUS_DOUBLE_FAULT flag
in FLAGS.
By default, access to rendered regions is not multi-thread safe.
This is because between the installtion of the page and its filling
by the fill function, a second thread may access the page. To
enable multi-threaded access, the caller may pass
ANONYMOUS_THREAD_SAFE. In this case, a staging area will be set
up. When the fill function is invoked, access to the main region
is disabled; any access is blocked until the fill function
returns. */
extern struct anonymous_pager *anonymous_pager_alloc (vg_addr_t activity,
void *addr_hint,
uintptr_t length,
enum map_access access,
struct vg_object_policy p,
uintptr_t flags,
anonymous_pager_fill_t f,
void **addr_out);
extern void anonymous_pager_destroy (struct anonymous_pager *pager);
#endif /* HURD_ANONYMOUS_H */
|