1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // -------------------------------------------------------------------------------- |
5 | // LazyCOW.h |
6 | // |
7 | |
8 | // |
9 | // Provides support for "lazy copy-on-write" pages. |
10 | // |
11 | // NGEN images contain a large amount of writable data. At runtime, we typically only actually write to a small portion of this data. |
12 | // When we write to a writable page in an image, the OS must create a process-local copy of that page, so that other proceses |
13 | // cannot see the written data. To prevent this copy from failing, the OS pre-commits space in the pagefile for all writable |
14 | // pages when the image is loaded. Thus we get charged for every writable page, even if we only write to a few of them. |
15 | // |
16 | // FEATURE_LAZY_COW_PAGES enables "lazy copy-on-write." We mark the pages in the image file as read-only, and thus the OS |
17 | // does not pre-commit pagefile for these pages. At runtime, prior to writing to any page, we update it to be writable. |
18 | // This may fail, and thus is not appropriate for scenarios where strong reliability guarantees must be met. But for |
19 | // devices with small memory this is still worth it. |
20 | // |
21 | // -------------------------------------------------------------------------------- |
22 | |
23 | #ifndef LAZY_COW_H |
24 | #define LAZY_COW_H |
25 | |
26 | #ifdef FEATURE_LAZY_COW_PAGES |
27 | |
28 | #ifdef _WIN64 // due to the way we track pages, we cannot currently support 64-bit. |
29 | #error FEATURE_LAZY_COW_PAGES is only supported on 32-bit platforms. |
30 | #endif |
31 | |
32 | class PEDecoder; |
33 | |
34 | // If hModule is a native image, establishes copy-on-write tracking for the image. |
35 | // FreeLazyCOWPages must be called immediately before the module is unloaded. |
36 | void AllocateLazyCOWPages(PEDecoder * pImage); |
37 | |
38 | // If hModule is a native image, disestablishes copy-on-write tracking for the image. |
39 | // The image must be immediately unloaded following this call. |
40 | void FreeLazyCOWPages(PEDecoder * pImage); |
41 | |
42 | bool IsInReadOnlyLazyCOWPage(void* p); |
43 | |
44 | |
45 | // Forces the page(s) covered by the given address range to be made writable, |
46 | // if they are being tracked as copy-on-write pages. Otherwise does nothing. |
47 | // Returns false if we could not allocate the necessary memory. |
48 | bool EnsureWritablePagesNoThrow(void* p, size_t len); |
49 | |
50 | // Version for executable pages |
51 | bool EnsureWritableExecutablePagesNoThrow(void* p, size_t len); |
52 | |
53 | // Throwing version of EnsureWritablePagesNoThrow |
54 | void EnsureWritablePages(void* p, size_t len); |
55 | |
56 | // Version for executable pages |
57 | void EnsureWritableExecutablePages(void* p, size_t len); |
58 | |
59 | #else //FEATURE_LAZY_COW_PAGES |
60 | |
61 | inline bool EnsureWritablePagesNoThrow(void* p, size_t len) |
62 | { |
63 | return true; |
64 | } |
65 | |
66 | inline bool EnsureWritableExecutablePagesNoThrow(void* p, size_t len) |
67 | { |
68 | return true; |
69 | } |
70 | |
71 | inline void EnsureWritablePages(void* p, size_t len) |
72 | { |
73 | } |
74 | |
75 | inline void EnsureWritableExecutablePages(void* p, size_t len) |
76 | { |
77 | } |
78 | |
79 | #endif //FEATURE_LAZY_COW_PAGES |
80 | |
81 | // Typed version of EnsureWritable. Returns p, so this can be inserted in expressions. |
82 | // Ignores any failure to allocate. In typical cases this means that the write will AV. |
83 | // In the CLR that's OK; we handle the AV, try EnsureWritable(void*,size_t), and |
84 | // fail-fast when it fails. |
85 | template<typename T> |
86 | inline T* EnsureWritablePages(T* p) |
87 | { |
88 | EnsureWritablePages(p, sizeof(T)); |
89 | return p; |
90 | } |
91 | |
92 | template<typename T> |
93 | inline T* EnsureWritableExecutablePages(T* p) |
94 | { |
95 | EnsureWritableExecutablePages(p, sizeof(T)); |
96 | return p; |
97 | } |
98 | |
99 | #endif // LAZY_COW_H |
100 | |