| 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 | |