-
Notifications
You must be signed in to change notification settings - Fork 0
/
mmap.c
144 lines (127 loc) · 3.92 KB
/
mmap.c
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
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <math.h>
static size_t page_size;
// align_down - rounds a value down to an alignment
// @x: the value
// @a: the alignment (must be power of 2)
//
// Returns an aligned value.
#define align_down(x, a) ((x) & ~((typeof(x))(a) - 1))
#define AS_LIMIT (1 << 25) // Maximum limit on virtual memory bytes
#define MAX_SQRTS (1 << 27) // Maximum limit on sqrt table entries
static double *sqrts;
// Use this helper function as an oracle for square root values.
static void
calculate_sqrts(double *sqrt_pos, int start, int nr)
{
int i;
for (i = 0; i < nr; i++) {
sqrt_pos[i] = sqrt((double)(start + i));
}
}
static void
handle_sigsegv(int sig, siginfo_t *si, void *ctx)
{
// Your code here.
// replace these three lines with your implementation
// uintptr_t fault_addr = (uintptr_t)si->si_addr;
// printf("oops got SIGSEGV at 0x%lx\n", fault_addr);
// exit(EXIT_FAILURE);
static int ptr[10];
static void* data[10];
int npp = page_size / sizeof(double); // number of doubles per page
int pos = ((uintptr_t)si->si_addr - (uintptr_t)sqrts) / sizeof(double);
int pgnum = pos / npp;
int iter;
for (iter = 0; iter < 10; iter++) {
if (ptr[iter] == 0) {
break; // find that page, already in mem
}
}
if (iter == 10) {
--iter;
munmap(data[iter], page_size);
}
// unmap origin
ptr[iter] = pgnum;
data[iter] = mmap((void*)align_down((uintptr_t)si->si_addr, (uintptr_t)page_size), page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (data[iter] == MAP_FAILED) {
fprintf(stderr, "Couldn't mmap() region in sig; %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
// printf("map %lx on %lx get %lx\n", si->si_addr, (void*)align_down((uintptr_t)si->si_addr, (uintptr_t)page_size), data[iter]);
calculate_sqrts(data[iter], align_down(pos,npp), npp);
}
static void
setup_sqrt_region(void)
{
struct rlimit lim = {AS_LIMIT, AS_LIMIT};
struct sigaction act;
// Only mapping to find a safe location for the table.
sqrts = mmap(NULL, MAX_SQRTS * sizeof(double) + AS_LIMIT, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (sqrts == MAP_FAILED) {
fprintf(stderr, "Couldn't mmap() region for sqrt table; %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
printf("get sqrt addr %lx\n", sqrts);
// Now release the virtual memory to remain under the rlimit.
if (munmap(sqrts, MAX_SQRTS * sizeof(double) + AS_LIMIT) == -1) {
fprintf(stderr, "Couldn't munmap() region for sqrt table; %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
// Set a soft rlimit on virtual address-space bytes.
if (setrlimit(RLIMIT_AS, &lim) == -1) {
fprintf(stderr, "Couldn't set rlimit on RLIMIT_AS; %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// Register a signal handler to capture SIGSEGV.
act.sa_sigaction = handle_sigsegv;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
if (sigaction(SIGSEGV, &act, NULL) == -1) {
fprintf(stderr, "Couldn't set up SIGSEGV handler;, %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
static void
test_sqrt_region(void)
{
int i, pos = rand() % (MAX_SQRTS - 1);
double correct_sqrt;
printf("Validating square root table contents...\n");
srand(0xDEADBEEF);
for (i = 0; i < 500000; i++) {
if (i % 2 == 0)
pos = rand() % (MAX_SQRTS - 1);
else
pos += 1;
calculate_sqrts(&correct_sqrt, pos, 1);
if (sqrts[pos] != correct_sqrt) {
fprintf(stderr, "Square root is incorrect. Expected %f, got %f.\n",
correct_sqrt, sqrts[pos]);
exit(EXIT_FAILURE);
}
}
printf("All tests passed!\n");
}
int
main(int argc, char *argv[])
{
page_size = sysconf(_SC_PAGESIZE);
printf("page_size is %ld\n", page_size);
setup_sqrt_region();
test_sqrt_region();
return 0;
}