Commit | Line | Data |
---|---|---|
f7a2be83 MD |
1 | #ifndef _BABELTRACE_MMAP_ALIGN_H |
2 | #define _BABELTRACE_MMAP_ALIGN_H | |
3 | ||
4 | /* | |
5 | * BabelTrace mmap-align.h - mmap alignment header | |
6 | * | |
7 | * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
10 | * of this software and associated documentation files (the "Software"), to deal | |
11 | * in the Software without restriction, including without limitation the rights | |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
13 | * copies of the Software, and to permit persons to whom the Software is | |
14 | * furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice shall be included in | |
17 | * all copies or substantial portions of the Software. | |
18 | */ | |
19 | ||
20 | #include <babeltrace/align.h> | |
21 | #include <stdlib.h> | |
22 | #include <sys/mman.h> | |
23 | ||
24 | /* | |
25 | * This header implements a wrapper over mmap (mmap_align) that memory | |
26 | * maps a file region that is not necessarily multiple of the page size. | |
27 | * It returns a structure (instead of a pointer) that contains the mmap | |
28 | * pointer (page-aligned) and a pointer to the offset requested within | |
29 | * that page. Note: in the current implementation, the "addr" parameter | |
30 | * cannot be forced, so we allocate at an address chosen by the OS. | |
31 | */ | |
32 | ||
33 | struct mmap_align { | |
34 | void *page_aligned_addr; /* mmap address, aligned to floor */ | |
35 | size_t page_aligned_length; /* mmap length, containing range */ | |
36 | ||
37 | void *addr; /* virtual mmap address */ | |
38 | size_t length; /* virtual mmap length */ | |
39 | }; | |
40 | ||
41 | static inline | |
42 | struct mmap_align *mmap_align(size_t length, int prot, | |
43 | int flags, int fd, off_t offset) | |
44 | { | |
45 | struct mmap_align *mma; | |
46 | off_t page_aligned_offset; /* mmap offset, aligned to floor */ | |
47 | ||
48 | mma = malloc(sizeof(*mma)); | |
49 | if (!mma) | |
50 | return MAP_FAILED; | |
51 | mma->length = length; | |
52 | page_aligned_offset = ALIGN_FLOOR(offset, PAGE_SIZE); | |
53 | /* | |
54 | * Page aligned length needs to contain the requested range. | |
55 | * E.g., for a small range that fits within a single page, we might | |
56 | * require a 2 pages page_aligned_length if the range crosses a page | |
57 | * boundary. | |
58 | */ | |
59 | mma->page_aligned_length = ALIGN(length + offset - page_aligned_offset, PAGE_SIZE); | |
60 | mma->page_aligned_addr = mmap(NULL, mma->page_aligned_length, | |
61 | prot, flags, fd, page_aligned_offset); | |
62 | if (mma->page_aligned_addr == (void *) -1UL) { | |
63 | free(mma); | |
64 | return MAP_FAILED; | |
65 | } | |
66 | mma->addr = mma->page_aligned_addr + (offset - page_aligned_offset); | |
67 | return mma; | |
68 | } | |
69 | ||
70 | static inline | |
71 | int munmap_align(struct mmap_align *mma) | |
72 | { | |
73 | void *page_aligned_addr; | |
74 | size_t page_aligned_length; | |
75 | ||
76 | page_aligned_addr = mma->page_aligned_addr; | |
77 | page_aligned_length = mma->page_aligned_length; | |
78 | free(mma); | |
79 | return munmap(page_aligned_addr, page_aligned_length); | |
80 | } | |
81 | ||
82 | static inline | |
83 | void *mmap_align_addr(struct mmap_align *mma) | |
84 | { | |
85 | return mma->addr; | |
86 | } | |
87 | ||
88 | /* | |
89 | * Helper for special-cases, normally unused. | |
90 | */ | |
91 | static inline | |
92 | void mmap_align_set_addr(struct mmap_align *mma, void *addr) | |
93 | { | |
94 | mma->addr = addr; | |
95 | } | |
96 | ||
97 | #endif /* _BABELTRACE_MMAP_ALIGN_H */ |