Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/app/svcache.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <vcl/dropcache.hxx>
21
#include <svcache.hxx>
22
#include <svdata.hxx>
23
#if defined SAL_UNX
24
#include <unistd.h>
25
#include <string.h>
26
#include <errno.h>
27
#include <sys/mman.h>
28
#elif defined _WIN32
29
#define WIN32_LEAN_AND_MEAN
30
#include <windows.h>
31
#else
32
#error Unsupported platform
33
#endif
34
35
CacheOwner::CacheOwner()
36
10.6k
{
37
10.6k
    if (ImplSVData* pSVData = ImplGetSVData())
38
10.6k
    {
39
10.6k
        pSVData->registerCacheOwner(*this);
40
10.6k
        return;
41
10.6k
    }
42
0
    SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is useless.");
43
0
}
44
45
CacheOwner::~CacheOwner()
46
10.4k
{
47
10.4k
    if (ImplSVData* pSVData = ImplGetSVData())
48
10.4k
        pSVData->deregisterCacheOwner(*this);
49
10.4k
}
50
51
#if defined __cpp_lib_memory_resource
52
53
0
#define MEMORY_ALIGN(value, align) (((value) + ((align)-1)) & ~((align)-1))
54
55
void* CacheMemory::allocPages(rtl_arena_type* arena, sal_Size* size)
56
0
{
57
0
    CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
58
59
0
    std::size_t n = MEMORY_ALIGN(*size, pCacheMemory->mnPageSize);
60
0
    void* p;
61
0
#if defined SAL_UNX
62
0
    p = mmap(nullptr, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
63
0
    if (p == MAP_FAILED)
64
0
        p = nullptr;
65
#elif defined _WIN32
66
    p = VirtualAlloc(nullptr, n, MEM_COMMIT, PAGE_READWRITE);
67
#endif
68
0
    if (p != nullptr)
69
0
    {
70
0
        pCacheMemory->mnAllocatedPages += (n / pCacheMemory->mnPageSize);
71
0
        pCacheMemory->mnMaxAllocatedPages
72
0
            = std::max(pCacheMemory->mnMaxAllocatedPages, pCacheMemory->mnAllocatedPages);
73
0
        *size = n;
74
0
    }
75
0
    return p;
76
0
}
77
78
void CacheMemory::freePages(rtl_arena_type* arena, void* address, sal_Size size)
79
0
{
80
0
    CacheMemory* pCacheMemory = reinterpret_cast<CacheMemory*>(arena);
81
0
#if defined SAL_UNX
82
0
    munmap(address, size);
83
#elif defined _WIN32
84
    (void)size; // unused
85
    VirtualFree(address, 0, MEM_RELEASE);
86
#endif
87
0
    pCacheMemory->mnAllocatedPages -= (size / pCacheMemory->mnPageSize);
88
0
}
89
90
CacheMemory::CacheMemory()
91
0
    : maCacheArenas{ nullptr }
92
    , mnSmallest(SAL_MAX_SIZE)
93
0
    , mnLargest(0)
94
0
    , mnAllocatedPages(0)
95
0
    , mnMaxAllocatedPages(0)
96
0
{
97
0
#if defined SAL_UNX
98
#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY || defined HAIKU
99
    mnPageSize = getpagesize();
100
#else
101
0
    mnPageSize = sysconf(_SC_PAGESIZE);
102
0
#endif
103
#elif defined _WIN32
104
    SYSTEM_INFO info;
105
    GetSystemInfo(&info);
106
    mnPageSize = info.dwPageSize;
107
#else
108
#error Unsupported platform
109
#endif
110
0
}
111
112
0
size_t CacheMemory::GetAllocatedPages() const { return mnAllocatedPages; }
113
114
CacheMemory::~CacheMemory()
115
0
{
116
0
    SAL_INFO("vcl", "cachememory, smallest/largest are: "
117
0
                        << mnSmallest << ", " << mnLargest << "total pages allocated: "
118
0
                        << mnMaxAllocatedPages << ", current allocated pages" << mnAllocatedPages);
119
0
    for (size_t i = 0; i < maCacheArenas.size(); ++i)
120
0
    {
121
0
        if (!maCacheArenas[i])
122
0
            continue;
123
0
        SAL_INFO("vcl", "cachememory, destroying arena for alignment: " << (1 << i));
124
0
        rtl_arena_destroy(maCacheArenas[i]);
125
0
    }
126
0
}
127
128
void* CacheMemory::do_allocate(std::size_t bytes, std::size_t alignment)
129
0
{
130
0
    alignment = std::max<std::size_t>(alignment, 4);
131
0
    const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
132
0
    if (!maCacheArenas[nSlot])
133
0
    {
134
0
        maCacheArenas[nSlot]
135
0
            = rtl_arena_create("cache_internal_arena", alignment, 0,
136
0
                               reinterpret_cast<rtl_arena_type*>(this), allocPages, freePages, 0);
137
0
    }
138
139
0
    mnSmallest = std::min(mnSmallest, bytes);
140
0
    mnLargest = std::max(mnLargest, bytes);
141
0
    sal_Size size = MEMORY_ALIGN(bytes, alignment);
142
0
    return rtl_arena_alloc(maCacheArenas[nSlot], &size);
143
0
}
144
145
void CacheMemory::do_deallocate(void* p, std::size_t bytes, std::size_t alignment)
146
0
{
147
0
    alignment = std::max<std::size_t>(alignment, 4);
148
0
    const unsigned int nSlot = o3tl::number_of_bits(alignment) - 1;
149
0
    sal_Size size = MEMORY_ALIGN(bytes, alignment);
150
0
    rtl_arena_free(maCacheArenas[nSlot], p, size);
151
0
}
152
153
bool CacheMemory::do_is_equal(const std::pmr::memory_resource& other) const noexcept
154
0
{
155
0
    SAL_WARN("vcl", "CacheMemory::do_is_equal called");
156
0
    return &other == this;
157
0
}
158
159
//static
160
CacheMemory& CacheMemory::GetMemoryResource()
161
0
{
162
0
    static CacheMemory aCacheMemory;
163
0
    return aCacheMemory;
164
0
}
165
166
//static
167
std::pmr::memory_resource& CacheOwner::GetMemoryResource()
168
1.87M
{
169
1.87M
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
170
1.87M
    return *std::pmr::get_default_resource();
171
#else
172
    return CacheMemory::GetMemoryResource();
173
#endif
174
1.87M
}
175
#endif
176
177
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */