Bug Summary

File:home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx
Warning:line 623, column 38
The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'sal_Size'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name alloc_arena.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SAL_DLLIMPLEMENTATION -D RTL_OS="Linux" -D RTL_ARCH="X86_64" -D SRCDIR="/home/maarten/src/libreoffice/core" -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/dtoa/include/ -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/sal/inc -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx

/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
21
22#include "alloc_arena.hxx"
23
24#include "alloc_impl.hxx"
25#include <rtllifecycle.h>
26#include <sal/macros.h>
27
28#include <cassert>
29#include <string.h>
30#include <stdio.h>
31
32namespace {
33
34/**
35 @internal
36*/
37struct rtl_arena_list_st
38{
39 rtl_memory_lock_type m_lock;
40 rtl_arena_type m_arena_head;
41};
42
43}
44
45static rtl_arena_list_st g_arena_list;
46
47/**
48 provided for arena_type allocations, and hash_table resizing.
49
50 @internal
51*/
52static rtl_arena_type * gp_arena_arena = nullptr;
53
54/**
55 Low level virtual memory (pseudo) arena
56 (platform dependent implementation)
57
58 @internal
59 */
60static rtl_arena_type * gp_machdep_arena = nullptr;
61
62rtl_arena_type * gp_default_arena = nullptr;
63
64namespace
65{
66
67void * rtl_machdep_alloc(
68 rtl_arena_type * pArena,
69 sal_Size * pSize
70);
71
72void rtl_machdep_free(
73 rtl_arena_type * pArena,
74 void * pAddr,
75 sal_Size nSize
76);
77
78sal_Size rtl_machdep_pagesize();
79
80void rtl_arena_segment_constructor(void * obj)
81{
82 rtl_arena_segment_type * segment = static_cast<rtl_arena_segment_type*>(obj);
83
84 QUEUE_START_NAMED(segment, s){ (segment)->m_snext = (segment); (segment)->m_sprev = (
segment); }
;
85 QUEUE_START_NAMED(segment, f){ (segment)->m_fnext = (segment); (segment)->m_fprev = (
segment); }
;
86}
87
88void rtl_arena_segment_destructor(void * obj)
89{
90 rtl_arena_segment_type * segment = static_cast< rtl_arena_segment_type * >(
91 obj);
92 assert(QUEUE_STARTED_NAMED(segment, s))(static_cast <bool> ((((segment)->m_snext == (segment
)) && ((segment)->m_sprev == (segment)))) ? void (
0) : __assert_fail ("QUEUE_STARTED_NAMED(segment, s)", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 92, __extension__ __PRETTY_FUNCTION__))
;
93 assert(QUEUE_STARTED_NAMED(segment, f))(static_cast <bool> ((((segment)->m_fnext == (segment
)) && ((segment)->m_fprev == (segment)))) ? void (
0) : __assert_fail ("QUEUE_STARTED_NAMED(segment, f)", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 93, __extension__ __PRETTY_FUNCTION__))
;
94 (void) segment; // avoid warnings
95}
96
97/**
98 @precond arena->m_lock acquired.
99 */
100bool rtl_arena_segment_populate(rtl_arena_type * arena)
101{
102 rtl_arena_segment_type *span;
103 sal_Size size = rtl_machdep_pagesize();
104
105 span = static_cast< rtl_arena_segment_type * >(
106 rtl_machdep_alloc(gp_machdep_arena, &size));
107 if (span)
108 {
109 rtl_arena_segment_type *first, *last, *head;
110 sal_Size count = size / sizeof(rtl_arena_segment_type);
111
112 /* insert onto reserve span list */
113 QUEUE_INSERT_TAIL_NAMED(&(arena->m_segment_reserve_span_head), span, s){ (span)->m_snext = (&(arena->m_segment_reserve_span_head
)); (span)->m_sprev = (&(arena->m_segment_reserve_span_head
))->m_sprev; (&(arena->m_segment_reserve_span_head)
)->m_sprev = (span); (span)->m_sprev->m_snext = (span
); }
;
114 QUEUE_START_NAMED(span, f){ (span)->m_fnext = (span); (span)->m_fprev = (span); };
115 span->m_addr = reinterpret_cast<sal_uIntPtr>(span);
116 span->m_size = size;
117 span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
118
119 /* insert onto reserve list */
120 head = &(arena->m_segment_reserve_head);
121 for (first = span + 1, last = span + count; first < last; ++first)
122 {
123 QUEUE_INSERT_TAIL_NAMED(head, first, s){ (first)->m_snext = (head); (first)->m_sprev = (head)->
m_sprev; (head)->m_sprev = (first); (first)->m_sprev->
m_snext = (first); }
;
124 QUEUE_START_NAMED(first, f){ (first)->m_fnext = (first); (first)->m_fprev = (first
); }
;
125 first->m_addr = 0;
126 first->m_size = 0;
127 first->m_type = 0;
128 }
129 }
130 return (span != nullptr);
131}
132
133/**
134 @precond arena->m_lock acquired.
135 @precond (*ppSegment == 0)
136*/
137void rtl_arena_segment_get(
138 rtl_arena_type * arena,
139 rtl_arena_segment_type ** ppSegment
140)
141{
142 rtl_arena_segment_type * head;
143
144 assert(!*ppSegment)(static_cast <bool> (!*ppSegment) ? void (0) : __assert_fail
("!*ppSegment", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 144, __extension__ __PRETTY_FUNCTION__))
;
145
146 head = &(arena->m_segment_reserve_head);
147 if (head->m_snext != head || rtl_arena_segment_populate (arena))
148 {
149 (*ppSegment) = head->m_snext;
150 QUEUE_REMOVE_NAMED(*ppSegment, s){ (*ppSegment)->m_sprev->m_snext = (*ppSegment)->m_snext
; (*ppSegment)->m_snext->m_sprev = (*ppSegment)->m_sprev
; { (*ppSegment)->m_snext = (*ppSegment); (*ppSegment)->
m_sprev = (*ppSegment); }; }
;
151 }
152}
153
154/**
155 @precond arena->m_lock acquired.
156 @postcond (*ppSegment == 0)
157 */
158void rtl_arena_segment_put(
159 rtl_arena_type * arena,
160 rtl_arena_segment_type ** ppSegment
161)
162{
163 rtl_arena_segment_type * head;
164
165 assert(QUEUE_STARTED_NAMED(*ppSegment, s))(static_cast <bool> ((((*ppSegment)->m_snext == (*ppSegment
)) && ((*ppSegment)->m_sprev == (*ppSegment)))) ? void
(0) : __assert_fail ("QUEUE_STARTED_NAMED(*ppSegment, s)", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 165, __extension__ __PRETTY_FUNCTION__))
;
166 assert(QUEUE_STARTED_NAMED(*ppSegment, f))(static_cast <bool> ((((*ppSegment)->m_fnext == (*ppSegment
)) && ((*ppSegment)->m_fprev == (*ppSegment)))) ? void
(0) : __assert_fail ("QUEUE_STARTED_NAMED(*ppSegment, f)", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 166, __extension__ __PRETTY_FUNCTION__))
;
167
168 (*ppSegment)->m_addr = 0;
169 (*ppSegment)->m_size = 0;
170
171 assert((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD)(static_cast <bool> ((*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD
) ? void (0) : __assert_fail ("(*ppSegment)->m_type != RTL_ARENA_SEGMENT_TYPE_HEAD"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 171, __extension__ __PRETTY_FUNCTION__))
;
172 (*ppSegment)->m_type = 0;
173
174 /* keep as reserve */
175 head = &(arena->m_segment_reserve_head);
176 QUEUE_INSERT_HEAD_NAMED(head, (*ppSegment), s){ ((*ppSegment))->m_sprev = (head); ((*ppSegment))->m_snext
= (head)->m_snext; (head)->m_snext = ((*ppSegment)); (
(*ppSegment))->m_snext->m_sprev = ((*ppSegment)); }
;
177
178 /* clear */
179 (*ppSegment) = nullptr;
180}
181
182/**
183 @precond arena->m_lock acquired.
184*/
185void rtl_arena_freelist_insert (
186 rtl_arena_type * arena,
187 rtl_arena_segment_type * segment
188)
189{
190 rtl_arena_segment_type * head;
191 const auto bit = highbit(segment->m_size);
192 assert(bit > 0)(static_cast <bool> (bit > 0) ? void (0) : __assert_fail
("bit > 0", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 192, __extension__ __PRETTY_FUNCTION__))
;
193 head = &(arena->m_freelist_head[bit - 1]);
194 QUEUE_INSERT_TAIL_NAMED(head, segment, f){ (segment)->m_fnext = (head); (segment)->m_fprev = (head
)->m_fprev; (head)->m_fprev = (segment); (segment)->
m_fprev->m_fnext = (segment); }
;
195
196 arena->m_freelist_bitmap |= head->m_size;
197}
198
199/**
200 @precond arena->m_lock acquired.
201*/
202void rtl_arena_freelist_remove(
203 rtl_arena_type * arena,
204 rtl_arena_segment_type * segment
205)
206{
207 if (segment->m_fnext->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD &&
208 segment->m_fprev->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)
209 {
210 rtl_arena_segment_type * head;
211
212 head = segment->m_fprev;
213 assert(arena->m_freelist_bitmap & head->m_size)(static_cast <bool> (arena->m_freelist_bitmap & head
->m_size) ? void (0) : __assert_fail ("arena->m_freelist_bitmap & head->m_size"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 213, __extension__ __PRETTY_FUNCTION__))
;
214 arena->m_freelist_bitmap ^= head->m_size;
215 }
216 QUEUE_REMOVE_NAMED(segment, f){ (segment)->m_fprev->m_fnext = (segment)->m_fnext; (
segment)->m_fnext->m_fprev = (segment)->m_fprev; { (
segment)->m_fnext = (segment); (segment)->m_fprev = (segment
); }; }
;
217}
218
219#define RTL_ARENA_HASH_INDEX_IMPL(a, s, q, m)((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))
) >> (q)) & (m))
\
220 ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m))
221
222#define RTL_ARENA_HASH_INDEX(arena, addr)(((((addr)) + (((addr)) >> ((arena)->m_hash_shift)) +
(((addr)) >> (((arena)->m_hash_shift) << 1)))
>> ((arena)->m_quantum_shift)) & (((arena)->
m_hash_size - 1)))
\
223 RTL_ARENA_HASH_INDEX_IMPL((addr), (arena)->m_hash_shift, (arena)->m_quantum_shift, ((arena)->m_hash_size - 1))(((((addr)) + (((addr)) >> ((arena)->m_hash_shift)) +
(((addr)) >> (((arena)->m_hash_shift) << 1)))
>> ((arena)->m_quantum_shift)) & (((arena)->
m_hash_size - 1)))
224
225/**
226 @precond arena->m_lock released.
227*/
228void rtl_arena_hash_rescale(
229 rtl_arena_type * arena,
230 sal_Size new_size
231)
232{
233 assert(new_size != 0)(static_cast <bool> (new_size != 0) ? void (0) : __assert_fail
("new_size != 0", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 233, __extension__ __PRETTY_FUNCTION__))
;
234
235 rtl_arena_segment_type ** new_table;
236 sal_Size new_bytes;
237
238 new_bytes = new_size * sizeof(rtl_arena_segment_type*);
239 new_table = static_cast<rtl_arena_segment_type **>(rtl_arena_alloc (gp_arena_arena, &new_bytes));
240
241 if (new_table)
242 {
243 rtl_arena_segment_type ** old_table;
244 sal_Size old_size, i;
245
246 memset (new_table, 0, new_bytes);
247
248 RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock))pthread_mutex_lock((&(arena->m_lock)));
249
250 old_table = arena->m_hash_table;
251 old_size = arena->m_hash_size;
252
253 arena->m_hash_table = new_table;
254 arena->m_hash_size = new_size;
255 arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
256
257 for (i = 0; i < old_size; i++)
258 {
259 rtl_arena_segment_type * curr = old_table[i];
260 while (curr)
261 {
262 rtl_arena_segment_type * next = curr->m_fnext;
263 rtl_arena_segment_type ** head;
264
265 // coverity[negative_shift] - bogus
266 head = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, curr->m_addr)(((((curr->m_addr)) + (((curr->m_addr)) >> ((arena
)->m_hash_shift)) + (((curr->m_addr)) >> (((arena
)->m_hash_shift) << 1))) >> ((arena)->m_quantum_shift
)) & (((arena)->m_hash_size - 1)))
]);
267 curr->m_fnext = (*head);
268 (*head) = curr;
269
270 curr = next;
271 }
272 old_table[i] = nullptr;
273 }
274
275 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
276
277 if (old_table != arena->m_hash_table_0)
278 {
279 sal_Size old_bytes = old_size * sizeof(rtl_arena_segment_type*);
280 rtl_arena_free (gp_arena_arena, old_table, old_bytes);
281 }
282 }
283}
284
285/**
286 Insert arena hash, and update stats.
287*/
288void rtl_arena_hash_insert(
289 rtl_arena_type * arena,
290 rtl_arena_segment_type * segment
291)
292{
293 rtl_arena_segment_type ** ppSegment;
294
295 ppSegment = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, segment->m_addr)(((((segment->m_addr)) + (((segment->m_addr)) >> (
(arena)->m_hash_shift)) + (((segment->m_addr)) >>
(((arena)->m_hash_shift) << 1))) >> ((arena)->
m_quantum_shift)) & (((arena)->m_hash_size - 1)))
]);
296
297 segment->m_fnext = (*ppSegment);
298 (*ppSegment) = segment;
299
300 arena->m_stats.m_alloc += 1;
301 arena->m_stats.m_mem_alloc += segment->m_size;
302}
303
304/**
305 Remove arena hash, and update stats.
306*/
307rtl_arena_segment_type * rtl_arena_hash_remove(
308 rtl_arena_type * arena,
309 sal_uIntPtr addr,
310 sal_Size size
311)
312{
313 rtl_arena_segment_type *segment, **segpp;
314 sal_Size lookups = 0;
315
316 segpp = &(arena->m_hash_table[RTL_ARENA_HASH_INDEX(arena, addr)(((((addr)) + (((addr)) >> ((arena)->m_hash_shift)) +
(((addr)) >> (((arena)->m_hash_shift) << 1)))
>> ((arena)->m_quantum_shift)) & (((arena)->
m_hash_size - 1)))
]);
317 while ((segment = *segpp))
318 {
319 if (segment->m_addr == addr)
320 {
321 *segpp = segment->m_fnext;
322 segment->m_fnext = segment->m_fprev = segment;
323 break;
324 }
325
326 /* update lookup miss stats */
327 lookups += 1;
328 segpp = &(segment->m_fnext);
329 }
330
331 assert(segment)(static_cast <bool> (segment) ? void (0) : __assert_fail
("segment", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 331, __extension__ __PRETTY_FUNCTION__))
; // bad free
332 if (segment)
333 {
334 assert(segment->m_size == size)(static_cast <bool> (segment->m_size == size) ? void
(0) : __assert_fail ("segment->m_size == size", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 334, __extension__ __PRETTY_FUNCTION__))
;
335 (void) size; // avoid warnings
336
337 arena->m_stats.m_free += 1;
338 arena->m_stats.m_mem_alloc -= segment->m_size;
339
340 if (lookups > 1)
341 {
342 sal_Size nseg = static_cast<sal_Size>(arena->m_stats.m_alloc - arena->m_stats.m_free);
343 if (nseg > 4 * arena->m_hash_size)
344 {
345 if (!(arena->m_flags & RTL_ARENA_FLAG_RESCALE))
346 {
347 sal_Size ave = nseg >> arena->m_hash_shift;
348 assert(ave != 0)(static_cast <bool> (ave != 0) ? void (0) : __assert_fail
("ave != 0", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 348, __extension__ __PRETTY_FUNCTION__))
;
349 sal_Size new_size = arena->m_hash_size << (highbit(ave) - 1);
350
351 arena->m_flags |= RTL_ARENA_FLAG_RESCALE;
352 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
353 rtl_arena_hash_rescale (arena, new_size);
354 RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock))pthread_mutex_lock((&(arena->m_lock)));
355 arena->m_flags &= ~RTL_ARENA_FLAG_RESCALE;
356 }
357 }
358 }
359 }
360
361 return segment;
362}
363
364/**
365 allocate (and remove) segment from freelist
366
367 @precond arena->m_lock acquired
368 @precond (*ppSegment == 0)
369*/
370bool rtl_arena_segment_alloc(
371 rtl_arena_type * arena,
372 sal_Size size,
373 rtl_arena_segment_type ** ppSegment
374)
375{
376 int index = 0;
377
378 assert(!*ppSegment)(static_cast <bool> (!*ppSegment) ? void (0) : __assert_fail
("!*ppSegment", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 378, __extension__ __PRETTY_FUNCTION__))
;
379 if (!RTL_MEMORY_ISP2(size)(((size) & ((size) - 1)) == 0))
380 {
381 unsigned int msb = highbit(size);
382 if (RTL_ARENA_FREELIST_SIZE == msb)
383 {
384 /* highest possible freelist: fall back to first fit */
385 rtl_arena_segment_type *head, *segment;
386
387 head = &(arena->m_freelist_head[msb - 1]);
388 for (segment = head->m_fnext; segment != head; segment = segment->m_fnext)
389 {
390 if (segment->m_size >= size)
391 {
392 /* allocate first fit segment */
393 (*ppSegment) = segment;
394 break;
395 }
396 }
397 goto dequeue_and_leave;
398 }
399
400 /* roundup to next power of 2 */
401 size = ((sal_Size(1)) << msb);
402 }
403
404 index = lowbit(RTL_MEMORY_P2ALIGN(arena->m_freelist_bitmap, size)((arena->m_freelist_bitmap) & -static_cast<sal_IntPtr
>(size))
);
405 if (index > 0)
406 {
407 /* instant fit: allocate first free segment */
408 rtl_arena_segment_type *head;
409
410 head = &(arena->m_freelist_head[index - 1]);
411 (*ppSegment) = head->m_fnext;
412 assert((*ppSegment) != head)(static_cast <bool> ((*ppSegment) != head) ? void (0) :
__assert_fail ("(*ppSegment) != head", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 412, __extension__ __PRETTY_FUNCTION__))
;
413 }
414
415dequeue_and_leave:
416 if (*ppSegment)
417 {
418 /* remove from freelist */
419 rtl_arena_freelist_remove (arena, (*ppSegment));
420 }
421 return (*ppSegment != nullptr);
422}
423
424/**
425 import new (span) segment from source arena
426
427 @precond arena->m_lock acquired
428 @precond (*ppSegment == 0)
429*/
430bool rtl_arena_segment_create(
431 rtl_arena_type * arena,
432 sal_Size size,
433 rtl_arena_segment_type ** ppSegment
434)
435{
436 assert(!*ppSegment)(static_cast <bool> (!*ppSegment) ? void (0) : __assert_fail
("!*ppSegment", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 436, __extension__ __PRETTY_FUNCTION__))
;
437 if (arena->m_source_alloc)
438 {
439 rtl_arena_segment_get (arena, ppSegment);
440 if (*ppSegment)
441 {
442 rtl_arena_segment_type * span = nullptr;
443 rtl_arena_segment_get (arena, &span);
444 if (span)
445 {
446 /* import new span from source arena */
447 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
448
449 span->m_size = size;
450 span->m_addr = reinterpret_cast<sal_uIntPtr>(
451 (arena->m_source_alloc)(
452 arena->m_source_arena, &(span->m_size)));
453
454 RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock))pthread_mutex_lock((&(arena->m_lock)));
455 if (span->m_addr != 0)
456 {
457 /* insert onto segment list, update stats */
458 span->m_type = RTL_ARENA_SEGMENT_TYPE_SPAN;
459 QUEUE_INSERT_HEAD_NAMED(&(arena->m_segment_head), span, s){ (span)->m_sprev = (&(arena->m_segment_head)); (span
)->m_snext = (&(arena->m_segment_head))->m_snext
; (&(arena->m_segment_head))->m_snext = (span); (span
)->m_snext->m_sprev = (span); }
;
460 arena->m_stats.m_mem_total += span->m_size;
461
462 (*ppSegment)->m_addr = span->m_addr;
463 (*ppSegment)->m_size = span->m_size;
464 (*ppSegment)->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
465 QUEUE_INSERT_HEAD_NAMED(span, (*ppSegment), s){ ((*ppSegment))->m_sprev = (span); ((*ppSegment))->m_snext
= (span)->m_snext; (span)->m_snext = ((*ppSegment)); (
(*ppSegment))->m_snext->m_sprev = ((*ppSegment)); }
;
466
467 /* report success */
468 return true;
469 }
470 rtl_arena_segment_put (arena, &span);
471 }
472 rtl_arena_segment_put (arena, ppSegment);
473 }
474 }
475 return false; // failure
476}
477
478/**
479 mark as free and join with adjacent free segment(s)
480
481 @precond arena->m_lock acquired
482 @precond segment marked 'used'
483*/
484void rtl_arena_segment_coalesce(
485 rtl_arena_type * arena,
486 rtl_arena_segment_type * segment
487)
488{
489 rtl_arena_segment_type *next, *prev;
490
491 /* mark segment free */
492 assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED)(static_cast <bool> (segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED
) ? void (0) : __assert_fail ("segment->m_type == RTL_ARENA_SEGMENT_TYPE_USED"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 492, __extension__ __PRETTY_FUNCTION__))
;
493 segment->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
494
495 /* try to merge w/ next segment */
496 next = segment->m_snext;
497 if (next->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
498 {
499 assert(segment->m_addr + segment->m_size == next->m_addr)(static_cast <bool> (segment->m_addr + segment->m_size
== next->m_addr) ? void (0) : __assert_fail ("segment->m_addr + segment->m_size == next->m_addr"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 499, __extension__ __PRETTY_FUNCTION__))
;
500 segment->m_size += next->m_size;
501
502 /* remove from freelist */
503 rtl_arena_freelist_remove (arena, next);
504
505 /* remove from segment list */
506 QUEUE_REMOVE_NAMED(next, s){ (next)->m_sprev->m_snext = (next)->m_snext; (next)
->m_snext->m_sprev = (next)->m_sprev; { (next)->m_snext
= (next); (next)->m_sprev = (next); }; }
;
507
508 /* release segment descriptor */
509 rtl_arena_segment_put (arena, &next);
510 }
511
512 /* try to merge w/ prev segment */
513 prev = segment->m_sprev;
514 if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
515 {
516 assert(prev->m_addr + prev->m_size == segment->m_addr)(static_cast <bool> (prev->m_addr + prev->m_size ==
segment->m_addr) ? void (0) : __assert_fail ("prev->m_addr + prev->m_size == segment->m_addr"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 516, __extension__ __PRETTY_FUNCTION__))
;
517 segment->m_addr = prev->m_addr;
518 segment->m_size += prev->m_size;
519
520 /* remove from freelist */
521 rtl_arena_freelist_remove (arena, prev);
522
523 /* remove from segment list */
524 QUEUE_REMOVE_NAMED(prev, s){ (prev)->m_sprev->m_snext = (prev)->m_snext; (prev)
->m_snext->m_sprev = (prev)->m_sprev; { (prev)->m_snext
= (prev); (prev)->m_sprev = (prev); }; }
;
525
526 /* release segment descriptor */
527 rtl_arena_segment_put (arena, &prev);
528 }
529}
530
531void rtl_arena_constructor(void * obj)
532{
533 rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj);
534 rtl_arena_segment_type * head;
535 size_t i;
536
537 memset (arena, 0, sizeof(rtl_arena_type));
538
539 QUEUE_START_NAMED(arena, arena_){ (arena)->m_arena_next = (arena); (arena)->m_arena_prev
= (arena); }
;
540
541 RTL_MEMORY_LOCK_INIT(&(arena->m_lock))pthread_mutex_init((&(arena->m_lock)), nullptr);
542
543 head = &(arena->m_segment_reserve_span_head);
544 rtl_arena_segment_constructor (head);
545 head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
546
547 head = &(arena->m_segment_reserve_head);
548 rtl_arena_segment_constructor (head);
549 head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
550
551 head = &(arena->m_segment_head);
552 rtl_arena_segment_constructor (head);
553 head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
554
555 for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
556 {
557 head = &(arena->m_freelist_head[i]);
558 rtl_arena_segment_constructor (head);
559
560 head->m_size = ((sal_Size(1)) << i);
561 head->m_type = RTL_ARENA_SEGMENT_TYPE_HEAD;
562 }
563
564 arena->m_hash_table = arena->m_hash_table_0;
565 arena->m_hash_size = RTL_ARENA_HASH_SIZE;
566 arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
567}
568
569void rtl_arena_destructor(void * obj)
570{
571 rtl_arena_type * arena = static_cast<rtl_arena_type*>(obj);
572 rtl_arena_segment_type * head;
573 size_t i;
574
575 assert(QUEUE_STARTED_NAMED(arena, arena_))(static_cast <bool> ((((arena)->m_arena_next == (arena
)) && ((arena)->m_arena_prev == (arena)))) ? void (
0) : __assert_fail ("QUEUE_STARTED_NAMED(arena, arena_)", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 575, __extension__ __PRETTY_FUNCTION__))
;
576
577 RTL_MEMORY_LOCK_DESTROY(&(arena->m_lock))pthread_mutex_destroy((&(arena->m_lock)));
578
579 head = &(arena->m_segment_reserve_span_head);
580 assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)(static_cast <bool> (head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD
) ? void (0) : __assert_fail ("head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 580, __extension__ __PRETTY_FUNCTION__))
;
581 rtl_arena_segment_destructor (head);
582
583 head = &(arena->m_segment_reserve_head);
584 assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)(static_cast <bool> (head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD
) ? void (0) : __assert_fail ("head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 584, __extension__ __PRETTY_FUNCTION__))
;
585 rtl_arena_segment_destructor (head);
586
587 head = &(arena->m_segment_head);
588 assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)(static_cast <bool> (head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD
) ? void (0) : __assert_fail ("head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 588, __extension__ __PRETTY_FUNCTION__))
;
589 rtl_arena_segment_destructor (head);
590
591 for (i = 0; i < RTL_ARENA_FREELIST_SIZE; i++)
592 {
593 head = &(arena->m_freelist_head[i]);
594
595 assert(head->m_size == ((sal_Size(1)) << i))(static_cast <bool> (head->m_size == ((sal_Size(1)) <<
i)) ? void (0) : __assert_fail ("head->m_size == ((sal_Size(1)) << i)"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 595, __extension__ __PRETTY_FUNCTION__))
;
596 assert(head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)(static_cast <bool> (head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD
) ? void (0) : __assert_fail ("head->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 596, __extension__ __PRETTY_FUNCTION__))
;
597
598 rtl_arena_segment_destructor (head);
599 }
600
601 assert(arena->m_hash_table == arena->m_hash_table_0)(static_cast <bool> (arena->m_hash_table == arena->
m_hash_table_0) ? void (0) : __assert_fail ("arena->m_hash_table == arena->m_hash_table_0"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 601, __extension__ __PRETTY_FUNCTION__))
;
602 assert(arena->m_hash_size == RTL_ARENA_HASH_SIZE)(static_cast <bool> (arena->m_hash_size == RTL_ARENA_HASH_SIZE
) ? void (0) : __assert_fail ("arena->m_hash_size == RTL_ARENA_HASH_SIZE"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 602, __extension__ __PRETTY_FUNCTION__))
;
603 assert(arena->m_hash_shift == highbit(arena->m_hash_size) - 1)(static_cast <bool> (arena->m_hash_shift == highbit(
arena->m_hash_size) - 1) ? void (0) : __assert_fail ("arena->m_hash_shift == highbit(arena->m_hash_size) - 1"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 603, __extension__ __PRETTY_FUNCTION__))
;
604}
605
606rtl_arena_type * rtl_arena_activate(
607 rtl_arena_type * arena,
608 const char * name,
609 sal_Size quantum,
610 rtl_arena_type * source_arena,
611 void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
612 void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size)
613)
614{
615 assert(arena)(static_cast <bool> (arena) ? void (0) : __assert_fail (
"arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 615, __extension__ __PRETTY_FUNCTION__))
;
4
'?' condition is true
616 if (arena
4.1
'arena' is non-null
4.1
'arena' is non-null
)
5
Taking true branch
617 {
618 (void) snprintf (arena->m_name, sizeof(arena->m_name), "%s", name);
619
620 if (!RTL_MEMORY_ISP2(quantum)(((quantum) & ((quantum) - 1)) == 0))
6
Assuming the condition is false
7
Taking true branch
621 {
622 /* roundup to next power of 2 */
623 quantum = ((sal_Size(1)) << highbit(quantum));
8
Calling 'highbit'
25
Returning from 'highbit'
26
The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'sal_Size'
624 }
625
626 arena->m_quantum = quantum;
627 arena->m_quantum_shift = highbit(arena->m_quantum) - 1;
628
629 arena->m_source_arena = source_arena;
630 arena->m_source_alloc = source_alloc;
631 arena->m_source_free = source_free;
632
633 /* insert into arena list */
634 RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock))pthread_mutex_lock((&(g_arena_list.m_lock)));
635 QUEUE_INSERT_TAIL_NAMED(&(g_arena_list.m_arena_head), arena, arena_){ (arena)->m_arena_next = (&(g_arena_list.m_arena_head
)); (arena)->m_arena_prev = (&(g_arena_list.m_arena_head
))->m_arena_prev; (&(g_arena_list.m_arena_head))->m_arena_prev
= (arena); (arena)->m_arena_prev->m_arena_next = (arena
); }
;
636 RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock))pthread_mutex_unlock((&(g_arena_list.m_lock)));
637 }
638 return arena;
639}
640
641void rtl_arena_deactivate(rtl_arena_type * arena)
642{
643 rtl_arena_segment_type * head, * segment;
644
645 /* remove from arena list */
646 RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock))pthread_mutex_lock((&(g_arena_list.m_lock)));
647 QUEUE_REMOVE_NAMED(arena, arena_){ (arena)->m_arena_prev->m_arena_next = (arena)->m_arena_next
; (arena)->m_arena_next->m_arena_prev = (arena)->m_arena_prev
; { (arena)->m_arena_next = (arena); (arena)->m_arena_prev
= (arena); }; }
;
648 RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock))pthread_mutex_unlock((&(g_arena_list.m_lock)));
649
650 /* check for leaked segments */
651 if (arena->m_stats.m_alloc > arena->m_stats.m_free)
652 {
653 sal_Size i, n;
654
655 /* cleanup still used segment(s) */
656 for (i = 0, n = arena->m_hash_size; i < n; i++)
657 {
658 while ((segment = arena->m_hash_table[i]))
659 {
660 /* pop from hash table */
661 arena->m_hash_table[i] = segment->m_fnext;
662 segment->m_fnext = segment->m_fprev = segment;
663
664 /* coalesce w/ adjacent free segment(s) */
665 rtl_arena_segment_coalesce (arena, segment);
666
667 /* insert onto freelist */
668 rtl_arena_freelist_insert (arena, segment);
669 }
670 }
671 }
672
673 /* cleanup hash table */
674 if (arena->m_hash_table != arena->m_hash_table_0)
675 {
676 rtl_arena_free(
677 gp_arena_arena,
678 arena->m_hash_table,
679 arena->m_hash_size * sizeof(rtl_arena_segment_type*));
680
681 arena->m_hash_table = arena->m_hash_table_0;
682 arena->m_hash_size = RTL_ARENA_HASH_SIZE;
683 arena->m_hash_shift = highbit(arena->m_hash_size) - 1;
684 }
685
686 /* cleanup segment list */
687 head = &(arena->m_segment_head);
688 for (segment = head->m_snext; segment != head; segment = head->m_snext)
689 {
690 if (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)
691 {
692 /* remove from freelist */
693 rtl_arena_freelist_remove (arena, segment);
694 }
695 else
696 {
697 /* can have only free and span segments here */
698 assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)(static_cast <bool> (segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN
) ? void (0) : __assert_fail ("segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 698, __extension__ __PRETTY_FUNCTION__))
;
699 }
700
701 /* remove from segment list */
702 QUEUE_REMOVE_NAMED(segment, s){ (segment)->m_sprev->m_snext = (segment)->m_snext; (
segment)->m_snext->m_sprev = (segment)->m_sprev; { (
segment)->m_snext = (segment); (segment)->m_sprev = (segment
); }; }
;
703
704 /* release segment descriptor */
705 rtl_arena_segment_put (arena, &segment);
706 }
707
708 /* cleanup segment reserve list */
709 head = &(arena->m_segment_reserve_head);
710 for (segment = head->m_snext; segment != head; segment = head->m_snext)
711 {
712 /* remove from segment list */
713 QUEUE_REMOVE_NAMED(segment, s){ (segment)->m_sprev->m_snext = (segment)->m_snext; (
segment)->m_snext->m_sprev = (segment)->m_sprev; { (
segment)->m_snext = (segment); (segment)->m_sprev = (segment
); }; }
;
714 }
715
716 /* cleanup segment reserve span(s) */
717 head = &(arena->m_segment_reserve_span_head);
718 for (segment = head->m_snext; segment != head; segment = head->m_snext)
719 {
720 /* can have only span segments here */
721 assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN)(static_cast <bool> (segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN
) ? void (0) : __assert_fail ("segment->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 721, __extension__ __PRETTY_FUNCTION__))
;
722
723 /* remove from segment list */
724 QUEUE_REMOVE_NAMED(segment, s){ (segment)->m_sprev->m_snext = (segment)->m_snext; (
segment)->m_snext->m_sprev = (segment)->m_sprev; { (
segment)->m_snext = (segment); (segment)->m_sprev = (segment
); }; }
;
725
726 /* return span to g_machdep_arena */
727 rtl_machdep_free (gp_machdep_arena, reinterpret_cast<void*>(segment->m_addr), segment->m_size);
728 }
729}
730
731} // namespace
732
733rtl_arena_type * SAL_CALL rtl_arena_create(
734 const char * name,
735 sal_Size quantum,
736 sal_Size,
737 rtl_arena_type * source_arena,
738 void * (SAL_CALL * source_alloc)(rtl_arena_type *, sal_Size *),
739 void (SAL_CALL * source_free) (rtl_arena_type *, void *, sal_Size),
740 SAL_UNUSED_PARAMETER__attribute__ ((unused)) int
741) SAL_THROW_EXTERN_C()throw ()
742{
743 rtl_arena_type * result = nullptr;
744 sal_Size size = sizeof(rtl_arena_type);
745
746try_alloc:
747 result = static_cast<rtl_arena_type*>(rtl_arena_alloc (gp_arena_arena, &size));
748 if (result)
749 {
750 rtl_arena_type * arena = result;
751 rtl_arena_constructor (arena);
752
753 if (!source_arena)
754 {
755 assert(gp_default_arena)(static_cast <bool> (gp_default_arena) ? void (0) : __assert_fail
("gp_default_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 755, __extension__ __PRETTY_FUNCTION__))
;
756 source_arena = gp_default_arena;
757 }
758
759 result = rtl_arena_activate (
760 arena,
761 name,
762 quantum,
763 source_arena,
764 source_alloc,
765 source_free
766 );
767
768 if (!result)
769 {
770 rtl_arena_deactivate (arena);
771 rtl_arena_destructor (arena);
772 rtl_arena_free (gp_arena_arena, arena, size);
773 }
774 }
775 else if (!gp_arena_arena)
776 {
777 ensureArenaSingleton();
778 if (gp_arena_arena)
779 {
780 /* try again */
781 goto try_alloc;
782 }
783 }
784 return result;
785}
786
787void SAL_CALL rtl_arena_destroy(rtl_arena_type * arena) SAL_THROW_EXTERN_C()throw ()
788{
789 if (arena)
790 {
791 rtl_arena_deactivate (arena);
792 rtl_arena_destructor (arena);
793 rtl_arena_free (gp_arena_arena, arena, sizeof(rtl_arena_type));
794 }
795}
796
797void * SAL_CALL rtl_arena_alloc(
798 rtl_arena_type * arena,
799 sal_Size * pSize
800) SAL_THROW_EXTERN_C()throw ()
801{
802 void * addr = nullptr;
803
804 if (arena && pSize)
805 {
806 sal_Size size;
807
808 size = RTL_MEMORY_ALIGN(*pSize, arena->m_quantum)(((*pSize) + ((arena->m_quantum) - 1)) & ~((arena->
m_quantum) - 1))
;
809 if (size > 0)
810 {
811 /* allocate from segment list */
812 rtl_arena_segment_type *segment = nullptr;
813
814 RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock))pthread_mutex_lock((&(arena->m_lock)));
815 if (rtl_arena_segment_alloc (arena, size, &segment) ||
816 rtl_arena_segment_create(arena, size, &segment) )
817 {
818 /* shrink to fit */
819 sal_Size oversize;
820
821 /* mark segment used */
822 assert(segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE)(static_cast <bool> (segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE
) ? void (0) : __assert_fail ("segment->m_type == RTL_ARENA_SEGMENT_TYPE_FREE"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 822, __extension__ __PRETTY_FUNCTION__))
;
823 segment->m_type = RTL_ARENA_SEGMENT_TYPE_USED;
824
825 /* resize */
826 assert(segment->m_size >= size)(static_cast <bool> (segment->m_size >= size) ? void
(0) : __assert_fail ("segment->m_size >= size", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 826, __extension__ __PRETTY_FUNCTION__))
;
827 oversize = segment->m_size - size;
828 if (oversize >= arena->m_quantum)
829 {
830 rtl_arena_segment_type * remainder = nullptr;
831 rtl_arena_segment_get (arena, &remainder);
832 if (remainder)
833 {
834 segment->m_size = size;
835
836 remainder->m_addr = segment->m_addr + segment->m_size;
837 remainder->m_size = oversize;
838 remainder->m_type = RTL_ARENA_SEGMENT_TYPE_FREE;
839 QUEUE_INSERT_HEAD_NAMED(segment, remainder, s){ (remainder)->m_sprev = (segment); (remainder)->m_snext
= (segment)->m_snext; (segment)->m_snext = (remainder)
; (remainder)->m_snext->m_sprev = (remainder); }
;
840
841 rtl_arena_freelist_insert (arena, remainder);
842 }
843 }
844
845 rtl_arena_hash_insert (arena, segment);
846
847 (*pSize) = segment->m_size;
848 addr = reinterpret_cast<void*>(segment->m_addr);
849 }
850 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
851 }
852 }
853 return addr;
854}
855
856void SAL_CALL rtl_arena_free (
857 rtl_arena_type * arena,
858 void * addr,
859 sal_Size size
860) SAL_THROW_EXTERN_C()throw ()
861{
862 if (arena)
863 {
864 size = RTL_MEMORY_ALIGN(size, arena->m_quantum)(((size) + ((arena->m_quantum) - 1)) & ~((arena->m_quantum
) - 1))
;
865 if (size > 0)
866 {
867 /* free to segment list */
868 rtl_arena_segment_type * segment;
869
870 RTL_MEMORY_LOCK_ACQUIRE(&(arena->m_lock))pthread_mutex_lock((&(arena->m_lock)));
871
872 segment = rtl_arena_hash_remove (arena, reinterpret_cast<sal_uIntPtr>(addr), size);
873 if (segment)
874 {
875 rtl_arena_segment_type *next, *prev;
876
877 /* coalesce w/ adjacent free segment(s) */
878 rtl_arena_segment_coalesce (arena, segment);
879
880 /* determine (new) next and prev segment */
881 next = segment->m_snext;
882 prev = segment->m_sprev;
883
884 /* entire span free when prev is a span, and next is either a span or a list head */
885 if (prev->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN &&
886 ((next->m_type == RTL_ARENA_SEGMENT_TYPE_SPAN) ||
887 (next->m_type == RTL_ARENA_SEGMENT_TYPE_HEAD)))
888 {
889 assert((static_cast <bool> (prev->m_addr == segment->m_addr
&& prev->m_size == segment->m_size) ? void (0)
: __assert_fail ("prev->m_addr == segment->m_addr && prev->m_size == segment->m_size"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 891, __extension__ __PRETTY_FUNCTION__))
890 prev->m_addr == segment->m_addr(static_cast <bool> (prev->m_addr == segment->m_addr
&& prev->m_size == segment->m_size) ? void (0)
: __assert_fail ("prev->m_addr == segment->m_addr && prev->m_size == segment->m_size"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 891, __extension__ __PRETTY_FUNCTION__))
891 && prev->m_size == segment->m_size)(static_cast <bool> (prev->m_addr == segment->m_addr
&& prev->m_size == segment->m_size) ? void (0)
: __assert_fail ("prev->m_addr == segment->m_addr && prev->m_size == segment->m_size"
, "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 891, __extension__ __PRETTY_FUNCTION__))
;
892
893 if (arena->m_source_free)
894 {
895 addr = reinterpret_cast<void*>(prev->m_addr);
896 size = prev->m_size;
897
898 /* remove from segment list */
899 QUEUE_REMOVE_NAMED(segment, s){ (segment)->m_sprev->m_snext = (segment)->m_snext; (
segment)->m_snext->m_sprev = (segment)->m_sprev; { (
segment)->m_snext = (segment); (segment)->m_sprev = (segment
); }; }
;
900
901 /* release segment descriptor */
902 rtl_arena_segment_put (arena, &segment);
903
904 /* remove from segment list */
905 QUEUE_REMOVE_NAMED(prev, s){ (prev)->m_sprev->m_snext = (prev)->m_snext; (prev)
->m_snext->m_sprev = (prev)->m_sprev; { (prev)->m_snext
= (prev); (prev)->m_sprev = (prev); }; }
;
906
907 /* release (span) segment descriptor */
908 rtl_arena_segment_put (arena, &prev);
909
910 /* update stats, return span to source arena */
911 arena->m_stats.m_mem_total -= size;
912 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
913
914 (arena->m_source_free)(arena->m_source_arena, addr, size);
915 return;
916 }
917 }
918
919 /* insert onto freelist */
920 rtl_arena_freelist_insert (arena, segment);
921 }
922
923 RTL_MEMORY_LOCK_RELEASE(&(arena->m_lock))pthread_mutex_unlock((&(arena->m_lock)));
924 }
925 }
926}
927
928void rtl_arena_foreach (rtl_arena_type *arena, ArenaForeachFn foreachFn)
929{
930 /* used segments */
931 for (int i = 0, n = arena->m_hash_size; i < n; i++)
932 {
933 for (rtl_arena_segment_type *segment = arena->m_hash_table[i];
934 segment != nullptr; segment = segment->m_fnext)
935 {
936 foreachFn(reinterpret_cast<void *>(segment->m_addr),
937 segment->m_size);
938 }
939 }
940}
941
942#if defined(SAL_UNX)
943#include <sys/mman.h>
944#elif defined(_WIN32)
945#define MAP_FAILED((void *) -1) nullptr
946#endif /* SAL_UNX || _WIN32 */
947
948namespace
949{
950
951void * rtl_machdep_alloc(
952 rtl_arena_type * pArena,
953 sal_Size * pSize
954)
955{
956 void * addr;
957 sal_Size size = *pSize;
958
959 assert(pArena == gp_machdep_arena)(static_cast <bool> (pArena == gp_machdep_arena) ? void
(0) : __assert_fail ("pArena == gp_machdep_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 959, __extension__ __PRETTY_FUNCTION__))
;
960
961#if defined(__sun) && defined(SPARC)
962 /* see @ mmap(2) man pages */
963 size += (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
964 if (size > (4 << 20))
965 size = RTL_MEMORY_P2ROUNDUP(size, (4 << 20))(-(-static_cast<sal_IntPtr>(size) & -static_cast<
sal_IntPtr>((4 << 20))))
;
966 else if (size > (512 << 10))
967 size = RTL_MEMORY_P2ROUNDUP(size, (512 << 10))(-(-static_cast<sal_IntPtr>(size) & -static_cast<
sal_IntPtr>((512 << 10))))
;
968 else
969 size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10))(-(-static_cast<sal_IntPtr>(size) & -static_cast<
sal_IntPtr>((64 << 10))))
;
970 size -= (pArena->m_quantum + pArena->m_quantum); /* "red-zone" pages */
971#else
972 /* default allocation granularity */
973 if (pArena->m_quantum < (64 << 10))
974 {
975 size = RTL_MEMORY_P2ROUNDUP(size, (64 << 10))(-(-static_cast<sal_IntPtr>(size) & -static_cast<
sal_IntPtr>((64 << 10))))
;
976 }
977 else
978 {
979 size = RTL_MEMORY_P2ROUNDUP(size, pArena->m_quantum)(-(-static_cast<sal_IntPtr>(size) & -static_cast<
sal_IntPtr>(pArena->m_quantum)))
;
980 }
981#endif
982
983#if defined(SAL_UNX)
984 addr = mmap (nullptr, static_cast<size_t>(size), PROT_READ0x1 | PROT_WRITE0x2, MAP_PRIVATE0x02 | MAP_ANON0x20, -1, 0);
985#elif defined(_WIN32)
986 addr = VirtualAlloc (nullptr, static_cast<SIZE_T>(size), MEM_COMMIT, PAGE_READWRITE);
987#endif /* (SAL_UNX || _WIN32) */
988
989 if (addr != MAP_FAILED((void *) -1))
990 {
991 pArena->m_stats.m_alloc += 1;
992 pArena->m_stats.m_mem_total += size;
993 pArena->m_stats.m_mem_alloc += size;
994
995 (*pSize) = size;
996 return addr;
997 }
998 return nullptr;
999}
1000
1001void rtl_machdep_free(
1002 rtl_arena_type * pArena,
1003 void * pAddr,
1004 sal_Size nSize
1005)
1006{
1007 assert(pArena == gp_machdep_arena)(static_cast <bool> (pArena == gp_machdep_arena) ? void
(0) : __assert_fail ("pArena == gp_machdep_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1007, __extension__ __PRETTY_FUNCTION__))
;
1008
1009 pArena->m_stats.m_free += 1;
1010 pArena->m_stats.m_mem_total -= nSize;
1011 pArena->m_stats.m_mem_alloc -= nSize;
1012
1013#if defined(SAL_UNX)
1014 (void) munmap(pAddr, nSize);
1015#elif defined(_WIN32)
1016 (void) VirtualFree (pAddr, SIZE_T(0), MEM_RELEASE);
1017#endif /* (SAL_UNX || _WIN32) */
1018}
1019
1020sal_Size rtl_machdep_pagesize()
1021{
1022#if defined(SAL_UNX)
1023#if defined(FREEBSD) || defined(NETBSD) || defined(DRAGONFLY)
1024 return (sal_Size)getpagesize();
1025#else /* POSIX */
1026 return static_cast<sal_Size>(sysconf(_SC_PAGESIZE_SC_PAGESIZE));
1027#endif /* xBSD || POSIX */
1028#elif defined(_WIN32)
1029 SYSTEM_INFO info;
1030 GetSystemInfo (&info);
1031 return static_cast<sal_Size>(info.dwPageSize);
1032#endif /* (SAL_UNX || _WIN32) */
1033}
1034
1035} //namespace
1036
1037void rtl_arena_init()
1038{
1039 {
1040 /* list of arenas */
1041 RTL_MEMORY_LOCK_INIT(&(g_arena_list.m_lock))pthread_mutex_init((&(g_arena_list.m_lock)), nullptr);
1042 rtl_arena_constructor (&(g_arena_list.m_arena_head));
1043 }
1044 {
1045 /* machdep (pseudo) arena */
1046 static rtl_arena_type g_machdep_arena;
1047
1048 assert(!gp_machdep_arena)(static_cast <bool> (!gp_machdep_arena) ? void (0) : __assert_fail
("!gp_machdep_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1048, __extension__ __PRETTY_FUNCTION__))
;
1
Assuming 'gp_machdep_arena' is null
2
'?' condition is true
1049 rtl_arena_constructor (&g_machdep_arena);
1050
1051 gp_machdep_arena = rtl_arena_activate (
3
Calling 'rtl_arena_activate'
1052 &g_machdep_arena,
1053 "rtl_machdep_arena",
1054 rtl_machdep_pagesize(),
1055 nullptr, nullptr, nullptr /* no source */
1056 );
1057 assert(gp_machdep_arena)(static_cast <bool> (gp_machdep_arena) ? void (0) : __assert_fail
("gp_machdep_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1057, __extension__ __PRETTY_FUNCTION__))
;
1058 }
1059 {
1060 /* default arena */
1061 static rtl_arena_type g_default_arena;
1062
1063 assert(!gp_default_arena)(static_cast <bool> (!gp_default_arena) ? void (0) : __assert_fail
("!gp_default_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1063, __extension__ __PRETTY_FUNCTION__))
;
1064 rtl_arena_constructor (&g_default_arena);
1065
1066 gp_default_arena = rtl_arena_activate (
1067 &g_default_arena,
1068 "rtl_default_arena",
1069 rtl_machdep_pagesize(),
1070 gp_machdep_arena, /* source */
1071 rtl_machdep_alloc,
1072 rtl_machdep_free
1073 );
1074 assert(gp_default_arena)(static_cast <bool> (gp_default_arena) ? void (0) : __assert_fail
("gp_default_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1074, __extension__ __PRETTY_FUNCTION__))
;
1075 }
1076 {
1077 /* arena internal arena */
1078 static rtl_arena_type g_arena_arena;
1079
1080 assert(!gp_arena_arena)(static_cast <bool> (!gp_arena_arena) ? void (0) : __assert_fail
("!gp_arena_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1080, __extension__ __PRETTY_FUNCTION__))
;
1081 rtl_arena_constructor (&g_arena_arena);
1082
1083 gp_arena_arena = rtl_arena_activate(
1084 &g_arena_arena,
1085 "rtl_arena_internal_arena",
1086 64, /* quantum */
1087 gp_default_arena, /* source */
1088 rtl_arena_alloc,
1089 rtl_arena_free
1090 );
1091 assert(gp_arena_arena)(static_cast <bool> (gp_arena_arena) ? void (0) : __assert_fail
("gp_arena_arena", "/home/maarten/src/libreoffice/core/sal/rtl/alloc_arena.cxx"
, 1091, __extension__ __PRETTY_FUNCTION__))
;
1092 }
1093}
1094
1095void rtl_arena_fini()
1096{
1097 if (gp_arena_arena)
1098 {
1099 rtl_arena_type * arena, * head;
1100
1101 RTL_MEMORY_LOCK_ACQUIRE(&(g_arena_list.m_lock))pthread_mutex_lock((&(g_arena_list.m_lock)));
1102 head = &(g_arena_list.m_arena_head);
1103
1104 for (arena = head->m_arena_next; arena != head; arena = arena->m_arena_next)
1105 {
1106 // noop
1107 }
1108 RTL_MEMORY_LOCK_RELEASE(&(g_arena_list.m_lock))pthread_mutex_unlock((&(g_arena_list.m_lock)));
1109 }
1110}
1111
1112/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sal/rtl/alloc_impl.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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#ifndef INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
21#define INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
22
23#include <sal/types.h>
24
25/** Alignment macros
26 */
27#if SAL_TYPES_ALIGNMENT44 > 1
28#define RTL_MEMORY_ALIGNMENT_44 SAL_TYPES_ALIGNMENT44
29#else
30#define RTL_MEMORY_ALIGNMENT_44 sizeof(int)
31#endif /* SAL_TYPES_ALIGNMENT4 */
32
33#if SAL_TYPES_ALIGNMENT88 > 1
34#define RTL_MEMORY_ALIGNMENT_88 SAL_TYPES_ALIGNMENT88
35#else
36#define RTL_MEMORY_ALIGNMENT_88 sizeof(void*)
37#endif /* SAL_TYPES_ALIGNMENT8 */
38
39#if 0 /* @@@ */
40#define RTL_MEMORY_ALIGNMENT_1 8
41#define RTL_MEMORY_ALIGNMENT_2 (sizeof(void*) * 2)
42#endif /* @@@ */
43
44#define RTL_MEMORY_ALIGN(value, align)(((value) + ((align) - 1)) & ~((align) - 1)) (((value) + ((align) - 1)) & ~((align) - 1))
45
46#define RTL_MEMORY_ISP2(value)(((value) & ((value) - 1)) == 0) (((value) & ((value) - 1)) == 0)
47#define RTL_MEMORY_P2ALIGN(value, align)((value) & -static_cast<sal_IntPtr>(align)) ((value) & -static_cast<sal_IntPtr>(align))
48
49#define RTL_MEMORY_P2ROUNDUP(value, align)(-(-static_cast<sal_IntPtr>(value) & -static_cast<
sal_IntPtr>(align)))
\
50 (-(-static_cast<sal_IntPtr>(value) & -static_cast<sal_IntPtr>(align)))
51#define RTL_MEMORY_P2END(value, align)(-(~static_cast<sal_IntPtr>(value) & -static_cast<
sal_IntPtr>(align)))
\
52 (-(~static_cast<sal_IntPtr>(value) & -static_cast<sal_IntPtr>(align)))
53
54/** highbit(): log2() + 1
55 (complexity O(1))
56*/
57static inline unsigned int highbit(sal_Size n)
58{
59 unsigned int k = 1;
60
61 if (n == 0)
9
Assuming 'n' is not equal to 0
10
Taking false branch
62 return 0;
63#if SAL_TYPES_SIZEOFLONG8 == 8
64 if (n & 0xffffffff00000000ul)
11
Assuming the condition is true
12
Taking true branch
65 {
66 k |= 32;
67 n >>= 32;
68 }
69#endif
70 if (n & 0xffff0000)
13
Assuming the condition is true
14
Taking true branch
71 {
72 k |= 16;
73 n >>= 16;
74 }
75 if (n & 0xff00)
15
Assuming the condition is true
16
Taking true branch
76 {
77 k |= 8;
78 n >>= 8;
79 }
80 if (n & 0xf0)
17
Assuming the condition is true
18
Taking true branch
81 {
82 k |= 4;
83 n >>= 4;
84 }
85 if (n & 0x0c)
19
Assuming the condition is true
20
Taking true branch
86 {
87 k |= 2;
88 n >>= 2;
89 }
90 if (n & 0x02)
21
Assuming the condition is true
22
Taking true branch
91 k++;
23
The value 64 is assigned to 'k'
92
93 return k;
24
Returning the value 64 (loaded from 'k')
94}
95
96/** find first bit set
97 (complexity O(1))
98*/
99static inline unsigned int lowbit(sal_Size n)
100{
101 unsigned int k = 1;
102
103 if (n == 0)
104 return 0;
105
106#if SAL_TYPES_SIZEOFLONG8 == 8
107 if (!(n & 0xffffffff))
108 {
109 k |= 32;
110 n >>= 32;
111 }
112#endif
113
114 if (!(n & 0xffff))
115 {
116 k |= 16;
117 n >>= 16;
118 }
119
120 if (!(n & 0xff))
121 {
122 k |= 8;
123 n >>= 8;
124 }
125
126 if (!(n & 0xf))
127 {
128 k |= 4;
129 n >>= 4;
130 }
131
132 if (!(n & 0x3))
133 {
134 k |= 2;
135 n >>= 2;
136 }
137
138 if (!(n & 0x1))
139 k++;
140
141 return k;
142}
143
144/** Queue manipulation macros
145 (doubly linked circular list)
146 (complexity O(1))
147*/
148#define QUEUE_STARTED_NAMED(entry, name)(((entry)->m_namenext == (entry)) && ((entry)->
m_nameprev == (entry)))
\
149 (((entry)->m_##name##next == (entry)) && ((entry)->m_##name##prev == (entry)))
150
151#define QUEUE_START_NAMED(entry, name){ (entry)->m_namenext = (entry); (entry)->m_nameprev = (
entry); }
\
152{ \
153 (entry)->m_##name##next = (entry); \
154 (entry)->m_##name##prev = (entry); \
155}
156
157#define QUEUE_REMOVE_NAMED(entry, name){ (entry)->m_nameprev->m_namenext = (entry)->m_namenext
; (entry)->m_namenext->m_nameprev = (entry)->m_nameprev
; { (entry)->m_namenext = (entry); (entry)->m_nameprev =
(entry); }; }
\
158{ \
159 (entry)->m_##name##prev->m_##name##next = (entry)->m_##name##next; \
160 (entry)->m_##name##next->m_##name##prev = (entry)->m_##name##prev; \
161 QUEUE_START_NAMED(entry, name){ (entry)->m_namenext = (entry); (entry)->m_nameprev = (
entry); }
; \
162}
163
164#define QUEUE_INSERT_HEAD_NAMED(head, entry, name){ (entry)->m_nameprev = (head); (entry)->m_namenext = (
head)->m_namenext; (head)->m_namenext = (entry); (entry
)->m_namenext->m_nameprev = (entry); }
\
165{ \
166 (entry)->m_##name##prev = (head); \
167 (entry)->m_##name##next = (head)->m_##name##next; \
168 (head)->m_##name##next = (entry); \
169 (entry)->m_##name##next->m_##name##prev = (entry); \
170}
171
172#define QUEUE_INSERT_TAIL_NAMED(head, entry, name){ (entry)->m_namenext = (head); (entry)->m_nameprev = (
head)->m_nameprev; (head)->m_nameprev = (entry); (entry
)->m_nameprev->m_namenext = (entry); }
\
173{ \
174 (entry)->m_##name##next = (head); \
175 (entry)->m_##name##prev = (head)->m_##name##prev; \
176 (head)->m_##name##prev = (entry); \
177 (entry)->m_##name##prev->m_##name##next = (entry); \
178}
179
180#if defined(SAL_UNX)
181
182#include <unistd.h>
183#include <pthread.h>
184
185typedef pthread_mutex_t rtl_memory_lock_type;
186
187#define RTL_MEMORY_LOCK_INIT(lock)pthread_mutex_init((lock), nullptr) pthread_mutex_init((lock), nullptr)
188#define RTL_MEMORY_LOCK_DESTROY(lock)pthread_mutex_destroy((lock)) pthread_mutex_destroy((lock))
189
190#define RTL_MEMORY_LOCK_ACQUIRE(lock)pthread_mutex_lock((lock)) pthread_mutex_lock((lock))
191#define RTL_MEMORY_LOCK_RELEASE(lock)pthread_mutex_unlock((lock)) pthread_mutex_unlock((lock))
192
193#elif defined(_WIN32)
194
195#define WIN32_LEAN_AND_MEAN
196#include <windows.h>
197
198typedef CRITICAL_SECTION rtl_memory_lock_type;
199
200#define RTL_MEMORY_LOCK_INIT(lock)pthread_mutex_init((lock), nullptr) InitializeCriticalSection((lock))
201#define RTL_MEMORY_LOCK_DESTROY(lock)pthread_mutex_destroy((lock)) DeleteCriticalSection((lock))
202
203#define RTL_MEMORY_LOCK_ACQUIRE(lock)pthread_mutex_lock((lock)) EnterCriticalSection((lock))
204#define RTL_MEMORY_LOCK_RELEASE(lock)pthread_mutex_unlock((lock)) LeaveCriticalSection((lock))
205
206#else
207#error Unknown platform
208#endif /* SAL_UNX | _WIN32 */
209
210/** Cache creation flags.
211 @internal
212*/
213#define RTL_CACHE_FLAG_NOMAGAZINE(1 << 13) (1 << 13) /* w/o magazine layer */
214
215#endif // INCLUDED_SAL_RTL_ALLOC_IMPL_HXX
216
217/* vim:set shiftwidth=4 softtabstop=4 expandtab: */