Line data Source code
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 "alloc_cache.hxx"
21 : #include "alloc_impl.hxx"
22 : #include "alloc_arena.hxx"
23 : #include "internal/rtllifecycle.h"
24 : #include "sal/macros.h"
25 : #include "osl/diagnose.h"
26 : #include <osl/thread.hxx>
27 :
28 : #include <cassert>
29 : #include <string.h>
30 : #include <stdio.h>
31 :
32 : extern AllocMode alloc_mode;
33 :
34 : /* ================================================================= *
35 : *
36 : * cache internals.
37 : *
38 : * ================================================================= */
39 :
40 : /** g_cache_list
41 : * @internal
42 : */
43 : struct rtl_cache_list_st
44 : {
45 : rtl_memory_lock_type m_lock;
46 : rtl_cache_type m_cache_head;
47 :
48 : #if defined(SAL_UNX)
49 : pthread_t m_update_thread;
50 : pthread_cond_t m_update_cond;
51 : #elif defined(SAL_W32)
52 : HANDLE m_update_thread;
53 : HANDLE m_update_cond;
54 : #endif /* SAL_UNX || SAL_W32 */
55 : int m_update_done;
56 : };
57 :
58 : static rtl_cache_list_st g_cache_list;
59 :
60 : /** gp_cache_arena
61 : * provided for cache_type allocations, and hash_table resizing.
62 : *
63 : * @internal
64 : */
65 : static rtl_arena_type * gp_cache_arena = 0;
66 :
67 : /** gp_cache_magazine_cache
68 : * @internal
69 : */
70 : static rtl_cache_type * gp_cache_magazine_cache = 0;
71 :
72 : /** gp_cache_slab_cache
73 : * @internal
74 : */
75 : static rtl_cache_type * gp_cache_slab_cache = 0;
76 :
77 : /** gp_cache_bufctl_cache
78 : * @internal
79 : */
80 : static rtl_cache_type * gp_cache_bufctl_cache = 0;
81 :
82 : /* ================================================================= */
83 :
84 : /** RTL_CACHE_HASH_INDEX()
85 : */
86 : #define RTL_CACHE_HASH_INDEX_IMPL(a, s, q, m) \
87 : ((((a) + ((a) >> (s)) + ((a) >> ((s) << 1))) >> (q)) & (m))
88 :
89 : #define RTL_CACHE_HASH_INDEX(cache, addr) \
90 : RTL_CACHE_HASH_INDEX_IMPL((addr), (cache)->m_hash_shift, (cache)->m_type_shift, ((cache)->m_hash_size - 1))
91 :
92 : namespace
93 : {
94 :
95 : void
96 330 : rtl_cache_hash_rescale (
97 : rtl_cache_type * cache,
98 : sal_Size new_size
99 : )
100 : {
101 : rtl_cache_bufctl_type ** new_table;
102 : sal_Size new_bytes;
103 :
104 330 : new_bytes = new_size * sizeof(rtl_cache_bufctl_type*);
105 330 : new_table = static_cast<rtl_cache_bufctl_type**>(rtl_arena_alloc(gp_cache_arena, &new_bytes));
106 :
107 330 : if (new_table != 0)
108 : {
109 : rtl_cache_bufctl_type ** old_table;
110 : sal_Size old_size, i;
111 :
112 330 : memset (new_table, 0, new_bytes);
113 :
114 330 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
115 :
116 330 : old_table = cache->m_hash_table;
117 330 : old_size = cache->m_hash_size;
118 :
119 : // SAL_INFO(
120 : // "sal.rtl",
121 : // "rtl_cache_hash_rescale(" << cache->m_name << "): nbuf: "
122 : // << (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
123 : // << " (ave: "
124 : // << ((cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
125 : // >> cache->m_hash_shift)
126 : // << "), frees: " << cache->m_slab_stats.m_free << " [old_size: "
127 : // << old_size << ", new_size: " << new_size << ']');
128 :
129 330 : cache->m_hash_table = new_table;
130 330 : cache->m_hash_size = new_size;
131 330 : cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
132 :
133 2970 : for (i = 0; i < old_size; i++)
134 : {
135 2640 : rtl_cache_bufctl_type * curr = old_table[i];
136 84370 : while (curr != 0)
137 : {
138 79090 : rtl_cache_bufctl_type * next = curr->m_next;
139 : rtl_cache_bufctl_type ** head;
140 :
141 : // coverity[negative_shift]
142 79090 : head = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, curr->m_addr)]);
143 79090 : curr->m_next = (*head);
144 79090 : (*head) = curr;
145 :
146 79090 : curr = next;
147 : }
148 2640 : old_table[i] = 0;
149 : }
150 :
151 330 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
152 :
153 330 : if (old_table != cache->m_hash_table_0)
154 : {
155 0 : sal_Size old_bytes = old_size * sizeof(rtl_cache_bufctl_type*);
156 0 : rtl_arena_free (gp_cache_arena, old_table, old_bytes);
157 : }
158 : }
159 330 : }
160 :
161 : inline sal_uIntPtr
162 120239 : rtl_cache_hash_insert (
163 : rtl_cache_type * cache,
164 : rtl_cache_bufctl_type * bufctl
165 : )
166 : {
167 : rtl_cache_bufctl_type ** ppHead;
168 :
169 120239 : ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, bufctl->m_addr)]);
170 :
171 120239 : bufctl->m_next = (*ppHead);
172 120239 : (*ppHead) = bufctl;
173 :
174 120239 : return bufctl->m_addr;
175 : }
176 :
177 : /** rtl_cache_hash_remove()
178 : */
179 : rtl_cache_bufctl_type *
180 107092 : rtl_cache_hash_remove (
181 : rtl_cache_type * cache,
182 : sal_uIntPtr addr
183 : )
184 : {
185 : rtl_cache_bufctl_type ** ppHead;
186 : rtl_cache_bufctl_type * bufctl;
187 107092 : sal_Size lookups = 0;
188 :
189 107092 : ppHead = &(cache->m_hash_table[RTL_CACHE_HASH_INDEX(cache, addr)]);
190 246765 : while ((bufctl = *ppHead) != 0)
191 : {
192 139673 : if (bufctl->m_addr == addr)
193 : {
194 107092 : *ppHead = bufctl->m_next, bufctl->m_next = 0;
195 107092 : break;
196 : }
197 :
198 32581 : lookups += 1;
199 32581 : ppHead = &(bufctl->m_next);
200 : }
201 :
202 : assert(bufctl != 0); // bad free
203 :
204 107092 : if (lookups > 1)
205 : {
206 4561 : sal_Size nbuf = (sal_Size)(cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free);
207 4561 : if (nbuf > 4 * cache->m_hash_size)
208 : {
209 330 : if (!(cache->m_features & RTL_CACHE_FEATURE_RESCALE))
210 : {
211 330 : sal_Size ave = nbuf >> cache->m_hash_shift;
212 : // coverity[negative_shift]
213 330 : sal_Size new_size = cache->m_hash_size << (highbit(ave) - 1);
214 :
215 330 : cache->m_features |= RTL_CACHE_FEATURE_RESCALE;
216 330 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
217 330 : rtl_cache_hash_rescale (cache, new_size);
218 330 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
219 330 : cache->m_features &= ~RTL_CACHE_FEATURE_RESCALE;
220 : }
221 : }
222 : }
223 :
224 107092 : return bufctl;
225 : }
226 :
227 : /* ================================================================= */
228 :
229 : /** RTL_CACHE_SLAB()
230 : */
231 : #define RTL_CACHE_SLAB(addr, size) \
232 : ((reinterpret_cast<rtl_cache_slab_type*>(RTL_MEMORY_P2END(reinterpret_cast<sal_uIntPtr>(addr), (size)))) - 1)
233 :
234 : /** rtl_cache_slab_constructor()
235 : */
236 : int
237 233605 : rtl_cache_slab_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
238 : {
239 233605 : rtl_cache_slab_type * slab = static_cast<rtl_cache_slab_type*>(obj);
240 :
241 233605 : QUEUE_START_NAMED(slab, slab_);
242 233605 : slab->m_ntypes = 0;
243 :
244 233605 : return 1;
245 : }
246 :
247 : /** rtl_cache_slab_destructor()
248 : */
249 : void
250 233605 : rtl_cache_slab_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
251 : {
252 233605 : rtl_cache_slab_type * slab = static_cast< rtl_cache_slab_type * >(obj);
253 : assert(QUEUE_STARTED_NAMED(slab, slab_)); // assure removed from queue(s)
254 : assert(slab->m_ntypes == 0); // assure no longer referenced
255 : (void) slab; // avoid warnings
256 233605 : }
257 :
258 : /** rtl_cache_slab_create()
259 : *
260 : * @precond cache->m_slab_lock released.
261 : */
262 : rtl_cache_slab_type *
263 234070 : rtl_cache_slab_create (
264 : rtl_cache_type * cache
265 : )
266 : {
267 234070 : rtl_cache_slab_type * slab = 0;
268 : void * addr;
269 : sal_Size size;
270 :
271 234070 : size = cache->m_slab_size;
272 234070 : addr = rtl_arena_alloc (cache->m_source, &size);
273 234070 : if (addr != 0)
274 : {
275 : assert(size >= cache->m_slab_size);
276 :
277 234070 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
278 : {
279 : /* allocate slab struct from slab cache */
280 : assert(cache != gp_cache_slab_cache);
281 20671 : slab = static_cast<rtl_cache_slab_type*>(rtl_cache_alloc (gp_cache_slab_cache));
282 : }
283 : else
284 : {
285 : /* construct embedded slab struct */
286 213399 : slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
287 213399 : (void) rtl_cache_slab_constructor (slab, 0);
288 : }
289 234070 : if (slab != 0)
290 : {
291 234070 : slab->m_data = reinterpret_cast<sal_uIntPtr>(addr);
292 :
293 : /* dynamic freelist initialization */
294 234070 : slab->m_bp = slab->m_data;
295 234070 : slab->m_sp = 0;
296 : }
297 : else
298 : {
299 0 : rtl_arena_free (cache->m_source, addr, size);
300 : }
301 : }
302 234070 : return slab;
303 : }
304 :
305 : /** rtl_cache_slab_destroy()
306 : *
307 : * @precond cache->m_slab_lock released.
308 : */
309 : void
310 234070 : rtl_cache_slab_destroy (
311 : rtl_cache_type * cache,
312 : rtl_cache_slab_type * slab
313 : )
314 : {
315 234070 : void * addr = reinterpret_cast<void*>(slab->m_data);
316 234070 : sal_Size refcnt = slab->m_ntypes; slab->m_ntypes = 0;
317 :
318 234070 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
319 : {
320 : /* cleanup bufctl(s) for free buffer(s) */
321 20671 : sal_Size ntypes = (slab->m_bp - slab->m_data) / cache->m_type_size;
322 126848 : for (ntypes -= refcnt; slab->m_sp != 0; ntypes--)
323 : {
324 106177 : rtl_cache_bufctl_type * bufctl = slab->m_sp;
325 :
326 : /* pop from freelist */
327 106177 : slab->m_sp = bufctl->m_next, bufctl->m_next = 0;
328 :
329 : /* return bufctl struct to bufctl cache */
330 106177 : rtl_cache_free (gp_cache_bufctl_cache, bufctl);
331 : }
332 : assert(ntypes == 0);
333 :
334 : /* return slab struct to slab cache */
335 20671 : rtl_cache_free (gp_cache_slab_cache, slab);
336 : }
337 : else
338 : {
339 : /* destruct embedded slab struct */
340 213399 : rtl_cache_slab_destructor (slab, 0);
341 : }
342 :
343 234070 : if ((refcnt == 0) || (cache->m_features & RTL_CACHE_FEATURE_BULKDESTROY))
344 : {
345 : /* free memory */
346 162916 : rtl_arena_free (cache->m_source, addr, cache->m_slab_size);
347 : }
348 234070 : }
349 :
350 : /** rtl_cache_slab_populate()
351 : *
352 : * @precond cache->m_slab_lock acquired.
353 : */
354 : bool
355 234070 : rtl_cache_slab_populate (
356 : rtl_cache_type * cache
357 : )
358 : {
359 : rtl_cache_slab_type * slab;
360 :
361 234070 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
362 234070 : slab = rtl_cache_slab_create (cache);
363 234070 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
364 234070 : if (slab != 0)
365 : {
366 : /* update buffer start addr w/ current color */
367 234070 : slab->m_bp += cache->m_ncolor;
368 :
369 : /* update color for next slab */
370 234070 : cache->m_ncolor += cache->m_type_align;
371 234070 : if (cache->m_ncolor > cache->m_ncolor_max)
372 49560 : cache->m_ncolor = 0;
373 :
374 : /* update stats */
375 234070 : cache->m_slab_stats.m_mem_total += cache->m_slab_size;
376 :
377 : /* insert onto 'free' queue */
378 234070 : QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
379 : }
380 234070 : return (slab != 0);
381 : }
382 :
383 : /* ================================================================= */
384 :
385 : /** rtl_cache_slab_alloc()
386 : *
387 : * Allocate a buffer from slab layer; used by magazine layer.
388 : */
389 : void *
390 11534772 : rtl_cache_slab_alloc (
391 : rtl_cache_type * cache
392 : )
393 : {
394 11534772 : void * addr = 0;
395 : rtl_cache_slab_type * head;
396 :
397 11534772 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
398 :
399 11534773 : head = &(cache->m_free_head);
400 11534773 : if ((head->m_slab_next != head) || rtl_cache_slab_populate (cache))
401 : {
402 : rtl_cache_slab_type * slab;
403 : rtl_cache_bufctl_type * bufctl;
404 :
405 11534775 : slab = head->m_slab_next;
406 : assert(slab->m_ntypes < cache->m_ntypes);
407 :
408 11534775 : if (slab->m_sp == 0)
409 : {
410 : /* initialize bufctl w/ current 'slab->m_bp' */
411 : assert(slab->m_bp < slab->m_data + cache->m_ntypes * cache->m_type_size + cache->m_ncolor_max);
412 11385081 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
413 : {
414 : /* allocate bufctl */
415 : assert(cache != gp_cache_bufctl_cache);
416 119324 : bufctl = static_cast<rtl_cache_bufctl_type*>(rtl_cache_alloc (gp_cache_bufctl_cache));
417 119324 : if (bufctl == 0)
418 : {
419 : /* out of memory */
420 0 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
421 0 : return 0;
422 : }
423 :
424 119324 : bufctl->m_addr = slab->m_bp;
425 119324 : bufctl->m_slab = reinterpret_cast<sal_uIntPtr>(slab);
426 : }
427 : else
428 : {
429 : /* embedded bufctl */
430 11265757 : bufctl = reinterpret_cast<rtl_cache_bufctl_type*>(slab->m_bp);
431 : }
432 11385081 : bufctl->m_next = 0;
433 :
434 : /* update 'slab->m_bp' to next free buffer */
435 11385081 : slab->m_bp += cache->m_type_size;
436 :
437 : /* assign bufctl to freelist */
438 11385081 : slab->m_sp = bufctl;
439 : }
440 :
441 : /* pop front */
442 11534775 : bufctl = slab->m_sp;
443 11534775 : slab->m_sp = bufctl->m_next;
444 :
445 : /* increment usage, check for full slab */
446 11534775 : if ((slab->m_ntypes += 1) == cache->m_ntypes)
447 : {
448 : /* remove from 'free' queue */
449 199369 : QUEUE_REMOVE_NAMED(slab, slab_);
450 :
451 : /* insert onto 'used' queue (tail) */
452 199369 : QUEUE_INSERT_TAIL_NAMED(&(cache->m_used_head), slab, slab_);
453 : }
454 :
455 : /* update stats */
456 11534775 : cache->m_slab_stats.m_alloc += 1;
457 11534775 : cache->m_slab_stats.m_mem_alloc += cache->m_type_size;
458 :
459 11534775 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
460 120239 : addr = reinterpret_cast<void*>(rtl_cache_hash_insert (cache, bufctl));
461 : else
462 11414536 : addr = bufctl;
463 : }
464 :
465 11534773 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
466 11534774 : return addr;
467 : }
468 :
469 : /** rtl_cache_slab_free()
470 : *
471 : * Return a buffer to slab layer; used by magazine layer.
472 : */
473 : void
474 10581163 : rtl_cache_slab_free (
475 : rtl_cache_type * cache,
476 : void * addr
477 : )
478 : {
479 : rtl_cache_bufctl_type * bufctl;
480 : rtl_cache_slab_type * slab;
481 :
482 10581163 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_slab_lock));
483 :
484 : /* determine slab from addr */
485 10581163 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
486 : {
487 107092 : bufctl = rtl_cache_hash_remove (cache, reinterpret_cast<sal_uIntPtr>(addr));
488 107092 : slab = (bufctl != 0) ? reinterpret_cast<rtl_cache_slab_type*>(bufctl->m_slab) : 0;
489 : }
490 : else
491 : {
492 : /* embedded slab struct */
493 10474071 : bufctl = static_cast<rtl_cache_bufctl_type*>(addr);
494 10474071 : slab = RTL_CACHE_SLAB(addr, cache->m_slab_size);
495 : }
496 :
497 10581163 : if (slab != 0)
498 : {
499 : /* check for full slab */
500 10581163 : if (slab->m_ntypes == cache->m_ntypes)
501 : {
502 : /* remove from 'used' queue */
503 197203 : QUEUE_REMOVE_NAMED(slab, slab_);
504 :
505 : /* insert onto 'free' queue (head) */
506 197203 : QUEUE_INSERT_HEAD_NAMED(&(cache->m_free_head), slab, slab_);
507 : }
508 :
509 : /* push front */
510 10581163 : bufctl->m_next = slab->m_sp;
511 10581163 : slab->m_sp = bufctl;
512 :
513 : /* update stats */
514 10581163 : cache->m_slab_stats.m_free += 1;
515 10581163 : cache->m_slab_stats.m_mem_alloc -= cache->m_type_size;
516 :
517 : /* decrement usage, check for empty slab */
518 10581163 : if ((slab->m_ntypes -= 1) == 0)
519 : {
520 : /* remove from 'free' queue */
521 162916 : QUEUE_REMOVE_NAMED(slab, slab_);
522 :
523 : /* update stats */
524 162916 : cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
525 :
526 : /* free 'empty' slab */
527 162916 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
528 162916 : rtl_cache_slab_destroy (cache, slab);
529 10744079 : return;
530 : }
531 : }
532 :
533 10418247 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_slab_lock));
534 : }
535 :
536 : /* ================================================================= */
537 :
538 : /** rtl_cache_magazine_constructor()
539 : */
540 : int
541 199221 : rtl_cache_magazine_constructor (void * obj, SAL_UNUSED_PARAMETER void *)
542 : {
543 199221 : rtl_cache_magazine_type * mag = static_cast<rtl_cache_magazine_type*>(obj);
544 : /* @@@ sal_Size size = (sal_Size)(arg); @@@ */
545 :
546 199221 : mag->m_mag_next = 0;
547 199221 : mag->m_mag_size = RTL_CACHE_MAGAZINE_SIZE;
548 199221 : mag->m_mag_used = 0;
549 :
550 199221 : return 1;
551 : }
552 :
553 : /** rtl_cache_magazine_destructor()
554 : */
555 : void
556 199180 : rtl_cache_magazine_destructor (void * obj, SAL_UNUSED_PARAMETER void *)
557 : {
558 : rtl_cache_magazine_type * mag = static_cast< rtl_cache_magazine_type * >(
559 199180 : obj);
560 : assert(mag->m_mag_next == 0); // assure removed from queue(s)
561 : assert(mag->m_mag_used == 0); // assure no longer referenced
562 : (void) mag; // avoid warnings
563 199180 : }
564 :
565 : /** rtl_cache_magazine_clear()
566 : */
567 : void
568 213404 : rtl_cache_magazine_clear (
569 : rtl_cache_type * cache,
570 : rtl_cache_magazine_type * mag
571 : )
572 : {
573 10790525 : for (; mag->m_mag_used > 0; --mag->m_mag_used)
574 : {
575 10577121 : void * obj = mag->m_objects[mag->m_mag_used - 1];
576 10577121 : mag->m_objects[mag->m_mag_used - 1] = 0;
577 :
578 10577121 : if (cache->m_destructor != 0)
579 : {
580 : /* destruct object */
581 215344 : (cache->m_destructor)(obj, cache->m_userarg);
582 : }
583 :
584 : /* return buffer to slab layer */
585 10577121 : rtl_cache_slab_free (cache, obj);
586 : }
587 213404 : }
588 :
589 : /* ================================================================= */
590 :
591 : /** rtl_cache_depot_enqueue()
592 : *
593 : * @precond cache->m_depot_lock acquired.
594 : */
595 : inline void
596 801641 : rtl_cache_depot_enqueue (
597 : rtl_cache_depot_type * depot,
598 : rtl_cache_magazine_type * mag
599 : )
600 : {
601 : /* enqueue empty magazine */
602 801641 : mag->m_mag_next = depot->m_mag_next;
603 801641 : depot->m_mag_next = mag;
604 :
605 : /* update depot stats */
606 801641 : depot->m_mag_count++;
607 801641 : }
608 :
609 : /** rtl_cache_depot_dequeue()
610 : *
611 : * @precond cache->m_depot_lock acquired.
612 : */
613 : inline rtl_cache_magazine_type *
614 12287208 : rtl_cache_depot_dequeue (
615 : rtl_cache_depot_type * depot
616 : )
617 : {
618 12287208 : rtl_cache_magazine_type * mag = 0;
619 12287208 : if (depot->m_mag_count > 0)
620 : {
621 : /* dequeue magazine */
622 : assert(depot->m_mag_next != 0);
623 :
624 801641 : mag = depot->m_mag_next;
625 801641 : depot->m_mag_next = mag->m_mag_next;
626 801641 : mag->m_mag_next = 0;
627 :
628 : /* update depot stats */
629 801641 : depot->m_mag_count--;
630 801641 : if(depot->m_curr_min > depot->m_mag_count)
631 : {
632 36839 : depot->m_curr_min = depot->m_mag_count;
633 : }
634 : }
635 12287208 : return mag;
636 : }
637 :
638 : /** rtl_cache_depot_exchange_alloc()
639 : *
640 : * @precond cache->m_depot_lock acquired.
641 : */
642 : inline rtl_cache_magazine_type *
643 11331758 : rtl_cache_depot_exchange_alloc (
644 : rtl_cache_type * cache,
645 : rtl_cache_magazine_type * empty
646 : )
647 : {
648 : rtl_cache_magazine_type * full;
649 :
650 : assert((empty == 0) || (empty->m_mag_used == 0));
651 :
652 : /* dequeue full magazine */
653 11331758 : full = rtl_cache_depot_dequeue (&(cache->m_depot_full));
654 11331757 : if ((full != 0) && (empty != 0))
655 : {
656 : /* enqueue empty magazine */
657 214922 : rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
658 : }
659 :
660 : assert((full == 0) || (full->m_mag_used > 0));
661 :
662 11331757 : return full;
663 : }
664 :
665 : /** rtl_cache_depot_exchange_free()
666 : *
667 : * @precond cache->m_depot_lock acquired.
668 : */
669 : inline rtl_cache_magazine_type *
670 642859 : rtl_cache_depot_exchange_free (
671 : rtl_cache_type * cache,
672 : rtl_cache_magazine_type * full
673 : )
674 : {
675 : rtl_cache_magazine_type * empty;
676 :
677 : assert((full == 0) || (full->m_mag_used > 0));
678 :
679 : /* dequeue empty magazine */
680 642859 : empty = rtl_cache_depot_dequeue (&(cache->m_depot_empty));
681 642859 : if ((empty != 0) && (full != 0))
682 : {
683 : /* enqueue full magazine */
684 373309 : rtl_cache_depot_enqueue (&(cache->m_depot_full), full);
685 : }
686 :
687 : assert((empty == 0) || (empty->m_mag_used == 0));
688 :
689 642859 : return empty;
690 : }
691 :
692 : /** rtl_cache_depot_populate()
693 : *
694 : * @precond cache->m_depot_lock acquired.
695 : */
696 : bool
697 217452 : rtl_cache_depot_populate (
698 : rtl_cache_type * cache
699 : )
700 : {
701 217452 : rtl_cache_magazine_type * empty = 0;
702 :
703 217452 : if (cache->m_magazine_cache != 0)
704 : {
705 : /* allocate new empty magazine */
706 213410 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
707 213410 : empty = static_cast<rtl_cache_magazine_type*>(rtl_cache_alloc (cache->m_magazine_cache));
708 213410 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
709 213410 : if (empty != 0)
710 : {
711 : /* enqueue (new) empty magazine */
712 213410 : rtl_cache_depot_enqueue (&(cache->m_depot_empty), empty);
713 : }
714 : }
715 217452 : return (empty != 0);
716 : }
717 :
718 : /* ================================================================= */
719 :
720 : /** rtl_cache_constructor()
721 : */
722 : int
723 77552 : rtl_cache_constructor (void * obj)
724 : {
725 77552 : rtl_cache_type * cache = static_cast<rtl_cache_type*>(obj);
726 :
727 77552 : memset (cache, 0, sizeof(rtl_cache_type));
728 :
729 : /* linkage */
730 77552 : QUEUE_START_NAMED(cache, cache_);
731 :
732 : /* slab layer */
733 77552 : (void)RTL_MEMORY_LOCK_INIT(&(cache->m_slab_lock));
734 :
735 77552 : QUEUE_START_NAMED(&(cache->m_free_head), slab_);
736 77552 : QUEUE_START_NAMED(&(cache->m_used_head), slab_);
737 :
738 77552 : cache->m_hash_table = cache->m_hash_table_0;
739 77552 : cache->m_hash_size = RTL_CACHE_HASH_SIZE;
740 77552 : cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
741 :
742 : /* depot layer */
743 77552 : (void)RTL_MEMORY_LOCK_INIT(&(cache->m_depot_lock));
744 :
745 77552 : return 1;
746 : }
747 :
748 : /** rtl_cache_destructor()
749 : */
750 : void
751 75640 : rtl_cache_destructor (void * obj)
752 : {
753 75640 : rtl_cache_type * cache = static_cast<rtl_cache_type*>(obj);
754 :
755 : /* linkage */
756 : assert(QUEUE_STARTED_NAMED(cache, cache_));
757 :
758 : /* slab layer */
759 75640 : (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_slab_lock));
760 :
761 : assert(QUEUE_STARTED_NAMED(&(cache->m_free_head), slab_));
762 : assert(QUEUE_STARTED_NAMED(&(cache->m_used_head), slab_));
763 :
764 : assert(cache->m_hash_table == cache->m_hash_table_0);
765 : assert(cache->m_hash_size == RTL_CACHE_HASH_SIZE);
766 : assert(cache->m_hash_shift == (sal_Size)(highbit(cache->m_hash_size) - 1));
767 :
768 : /* depot layer */
769 75640 : (void)RTL_MEMORY_LOCK_DESTROY(&(cache->m_depot_lock));
770 75640 : }
771 :
772 : /* ================================================================= */
773 :
774 : /** rtl_cache_activate()
775 : */
776 : rtl_cache_type *
777 75642 : rtl_cache_activate (
778 : rtl_cache_type * cache,
779 : const char * name,
780 : size_t objsize,
781 : size_t objalign,
782 : int (SAL_CALL * constructor)(void * obj, void * userarg),
783 : void (SAL_CALL * destructor) (void * obj, void * userarg),
784 : void (SAL_CALL * reclaim) (void * userarg),
785 : void * userarg,
786 : rtl_arena_type * source,
787 : int flags
788 : )
789 : {
790 : assert(cache != 0);
791 75642 : if (cache != 0)
792 : {
793 : sal_Size slabsize;
794 :
795 75642 : snprintf (cache->m_name, sizeof(cache->m_name), "%s", name);
796 :
797 : /* ensure minimum size (embedded bufctl linkage) */
798 75642 : if(objsize < sizeof(rtl_cache_bufctl_type*))
799 : {
800 0 : objsize = sizeof(rtl_cache_bufctl_type*);
801 : }
802 :
803 75642 : if (objalign == 0)
804 : {
805 : /* determine default alignment */
806 75642 : if (objsize >= RTL_MEMORY_ALIGNMENT_8)
807 75642 : objalign = RTL_MEMORY_ALIGNMENT_8;
808 : else
809 0 : objalign = RTL_MEMORY_ALIGNMENT_4;
810 : }
811 : else
812 : {
813 : /* ensure minimum alignment */
814 0 : if(objalign < RTL_MEMORY_ALIGNMENT_4)
815 : {
816 0 : objalign = RTL_MEMORY_ALIGNMENT_4;
817 : }
818 : }
819 : assert(RTL_MEMORY_ISP2(objalign));
820 :
821 75642 : cache->m_type_size = objsize = RTL_MEMORY_P2ROUNDUP(objsize, objalign);
822 75642 : cache->m_type_align = objalign;
823 75642 : cache->m_type_shift = highbit(cache->m_type_size) - 1;
824 :
825 75642 : cache->m_constructor = constructor;
826 75642 : cache->m_destructor = destructor;
827 75642 : cache->m_reclaim = reclaim;
828 75642 : cache->m_userarg = userarg;
829 :
830 : /* slab layer */
831 75642 : cache->m_source = source;
832 :
833 75642 : slabsize = source->m_quantum; /* minimum slab size */
834 75642 : if (flags & RTL_CACHE_FLAG_QUANTUMCACHE)
835 : {
836 : /* next power of 2 above 3 * qcache_max */
837 0 : if(slabsize < (((sal_Size)1) << highbit(3 * source->m_qcache_max)))
838 : {
839 0 : slabsize = (((sal_Size)1) << highbit(3 * source->m_qcache_max));
840 : }
841 : }
842 : else
843 : {
844 : /* waste at most 1/8 of slab */
845 75642 : if(slabsize < cache->m_type_size * 8)
846 : {
847 34992 : slabsize = cache->m_type_size * 8;
848 : }
849 : }
850 :
851 75642 : slabsize = RTL_MEMORY_P2ROUNDUP(slabsize, source->m_quantum);
852 75642 : if (!RTL_MEMORY_ISP2(slabsize))
853 18371 : slabsize = (((sal_Size)1) << highbit(slabsize));
854 75642 : cache->m_slab_size = slabsize;
855 :
856 75642 : if (cache->m_slab_size > source->m_quantum)
857 : {
858 : assert(gp_cache_slab_cache != 0);
859 : assert(gp_cache_bufctl_cache != 0);
860 :
861 34992 : cache->m_features |= RTL_CACHE_FEATURE_HASH;
862 34992 : cache->m_ntypes = cache->m_slab_size / cache->m_type_size;
863 34992 : cache->m_ncolor_max = cache->m_slab_size % cache->m_type_size;
864 : }
865 : else
866 : {
867 : /* embedded slab struct */
868 40650 : cache->m_ntypes = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) / cache->m_type_size;
869 40650 : cache->m_ncolor_max = (cache->m_slab_size - sizeof(rtl_cache_slab_type)) % cache->m_type_size;
870 : }
871 :
872 : assert(cache->m_ntypes > 0);
873 75642 : cache->m_ncolor = 0;
874 :
875 75642 : if (flags & RTL_CACHE_FLAG_BULKDESTROY)
876 : {
877 : /* allow bulk slab delete upon cache deactivation */
878 0 : cache->m_features |= RTL_CACHE_FEATURE_BULKDESTROY;
879 : }
880 :
881 : /* magazine layer */
882 75642 : if (!(flags & RTL_CACHE_FLAG_NOMAGAZINE))
883 : {
884 : assert(gp_cache_magazine_cache != 0);
885 73732 : cache->m_magazine_cache = gp_cache_magazine_cache;
886 : }
887 :
888 : /* insert into cache list */
889 75642 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
890 75642 : QUEUE_INSERT_TAIL_NAMED(&(g_cache_list.m_cache_head), cache, cache_);
891 75642 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
892 : }
893 75642 : return (cache);
894 : }
895 :
896 : /** rtl_cache_deactivate()
897 : */
898 : void
899 75640 : rtl_cache_deactivate (
900 : rtl_cache_type * cache
901 : )
902 : {
903 : /* remove from cache list */
904 75640 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
905 75640 : bool active = !QUEUE_STARTED_NAMED(cache, cache_);
906 75640 : QUEUE_REMOVE_NAMED(cache, cache_);
907 75640 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
908 :
909 : assert(active); // orphaned cache
910 : (void)active;
911 :
912 : /* cleanup magazine layer */
913 75640 : if (cache->m_magazine_cache != 0)
914 : {
915 : rtl_cache_type * mag_cache;
916 : rtl_cache_magazine_type * mag;
917 :
918 : /* prevent recursion */
919 75640 : mag_cache = cache->m_magazine_cache, cache->m_magazine_cache = 0;
920 :
921 : /* cleanup cpu layer */
922 75640 : if ((mag = cache->m_cpu_curr) != 0)
923 : {
924 : // coverity[missing_lock]
925 44869 : cache->m_cpu_curr = 0;
926 44869 : rtl_cache_magazine_clear (cache, mag);
927 44869 : rtl_cache_free (mag_cache, mag);
928 : }
929 75640 : if ((mag = cache->m_cpu_prev) != 0)
930 : {
931 : // coverity[missing_lock]
932 7223 : cache->m_cpu_prev = 0;
933 7223 : rtl_cache_magazine_clear (cache, mag);
934 7223 : rtl_cache_free (mag_cache, mag);
935 : }
936 :
937 : /* cleanup depot layer */
938 302204 : while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_full))) != 0)
939 : {
940 150924 : rtl_cache_magazine_clear (cache, mag);
941 150924 : rtl_cache_free (mag_cache, mag);
942 : }
943 151287 : while ((mag = rtl_cache_depot_dequeue(&(cache->m_depot_empty))) != 0)
944 : {
945 7 : rtl_cache_magazine_clear (cache, mag);
946 7 : rtl_cache_free (mag_cache, mag);
947 : }
948 : }
949 :
950 : // SAL_INFO(
951 : // "sal.rtl",
952 : // "rtl_cache_deactivate(" << cache->m_name << "): [slab]: allocs: "
953 : // << cache->m_slab_stats.m_alloc << ", frees: "
954 : // << cache->m_slab_stats.m_free << "; total: "
955 : // << cache->m_slab_stats.m_mem_total << ", used: "
956 : // << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
957 : // << cache->m_cpu_stats.m_alloc << ", frees: "
958 : // << cache->m_cpu_stats.m_free << "; [total]: allocs: "
959 : // << (cache->m_slab_stats.m_alloc + cache->m_cpu_stats.m_alloc)
960 : // << ", frees: "
961 : // << (cache->m_slab_stats.m_free + cache->m_cpu_stats.m_free));
962 :
963 : /* cleanup slab layer */
964 75640 : if (cache->m_slab_stats.m_alloc > cache->m_slab_stats.m_free)
965 : {
966 : // SAL_INFO(
967 : // "sal.rtl",
968 : // "rtl_cache_deactivate(" << cache->m_name << "): cleaning up "
969 : // << (cache->m_slab_stats.m_alloc - cache->m_slab_stats.m_free)
970 : // << " leaked buffer(s) [" << cache->m_slab_stats.m_mem_alloc
971 : // << " bytes] [" << cache->m_slab_stats.m_mem_total << " total]");
972 :
973 18198 : if (cache->m_features & RTL_CACHE_FEATURE_HASH)
974 : {
975 : /* cleanup bufctl(s) for leaking buffer(s) */
976 1645 : sal_Size i, n = cache->m_hash_size;
977 47653 : for (i = 0; i < n; i++)
978 : {
979 : rtl_cache_bufctl_type * bufctl;
980 105163 : while ((bufctl = cache->m_hash_table[i]) != 0)
981 : {
982 : /* pop from hash table */
983 13147 : cache->m_hash_table[i] = bufctl->m_next, bufctl->m_next = 0;
984 :
985 : /* return to bufctl cache */
986 13147 : rtl_cache_free (gp_cache_bufctl_cache, bufctl);
987 : }
988 : }
989 : }
990 : {
991 : /* force cleanup of remaining slabs */
992 : rtl_cache_slab_type *head, *slab;
993 :
994 18198 : head = &(cache->m_used_head);
995 20364 : for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
996 : {
997 : /* remove from 'used' queue */
998 2166 : QUEUE_REMOVE_NAMED(slab, slab_);
999 :
1000 : /* update stats */
1001 2166 : cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
1002 :
1003 : /* free slab */
1004 2166 : rtl_cache_slab_destroy (cache, slab);
1005 : }
1006 :
1007 18198 : head = &(cache->m_free_head);
1008 87186 : for (slab = head->m_slab_next; slab != head; slab = head->m_slab_next)
1009 : {
1010 : /* remove from 'free' queue */
1011 68988 : QUEUE_REMOVE_NAMED(slab, slab_);
1012 :
1013 : /* update stats */
1014 68988 : cache->m_slab_stats.m_mem_total -= cache->m_slab_size;
1015 :
1016 : /* free slab */
1017 68988 : rtl_cache_slab_destroy (cache, slab);
1018 : }
1019 : }
1020 : }
1021 :
1022 75640 : if (cache->m_hash_table != cache->m_hash_table_0)
1023 : {
1024 : rtl_arena_free (
1025 : gp_cache_arena,
1026 : cache->m_hash_table,
1027 330 : cache->m_hash_size * sizeof(rtl_cache_bufctl_type*));
1028 :
1029 330 : cache->m_hash_table = cache->m_hash_table_0;
1030 330 : cache->m_hash_size = RTL_CACHE_HASH_SIZE;
1031 330 : cache->m_hash_shift = highbit(cache->m_hash_size) - 1;
1032 : }
1033 75640 : }
1034 :
1035 : } //namespace
1036 :
1037 : /* ================================================================= *
1038 : *
1039 : * cache implementation.
1040 : *
1041 : * ================================================================= */
1042 :
1043 : /** rtl_cache_create()
1044 : */
1045 : rtl_cache_type *
1046 69912 : SAL_CALL rtl_cache_create (
1047 : const char * name,
1048 : sal_Size objsize,
1049 : sal_Size objalign,
1050 : int (SAL_CALL * constructor)(void * obj, void * userarg),
1051 : void (SAL_CALL * destructor) (void * obj, void * userarg),
1052 : void (SAL_CALL * reclaim) (void * userarg),
1053 : void * userarg,
1054 : rtl_arena_type * source,
1055 : int flags
1056 : ) SAL_THROW_EXTERN_C()
1057 : {
1058 69912 : rtl_cache_type * result = 0;
1059 69912 : sal_Size size = sizeof(rtl_cache_type);
1060 :
1061 : try_alloc:
1062 71822 : result = static_cast<rtl_cache_type*>(rtl_arena_alloc (gp_cache_arena, &size));
1063 71822 : if (result != 0)
1064 : {
1065 69912 : rtl_cache_type * cache = result;
1066 69912 : (void) rtl_cache_constructor (cache);
1067 :
1068 69912 : if (!source)
1069 : {
1070 : /* use default arena */
1071 : assert(gp_default_arena != 0);
1072 69912 : source = gp_default_arena;
1073 : }
1074 :
1075 : result = rtl_cache_activate (
1076 : cache,
1077 : name,
1078 : objsize,
1079 : objalign,
1080 : constructor,
1081 : destructor,
1082 : reclaim,
1083 : userarg,
1084 : source,
1085 : flags
1086 69912 : );
1087 :
1088 69912 : if (result == 0)
1089 : {
1090 : /* activation failed */
1091 0 : rtl_cache_deactivate (cache);
1092 0 : rtl_cache_destructor (cache);
1093 0 : rtl_arena_free (gp_cache_arena, cache, size);
1094 : }
1095 : }
1096 1910 : else if (gp_cache_arena == 0)
1097 : {
1098 1910 : ensureCacheSingleton();
1099 1910 : if (gp_cache_arena)
1100 : {
1101 : /* try again */
1102 1910 : goto try_alloc;
1103 : }
1104 : }
1105 69912 : return result;
1106 : }
1107 :
1108 : /** rtl_cache_destroy()
1109 : */
1110 69910 : void SAL_CALL rtl_cache_destroy (
1111 : rtl_cache_type * cache
1112 : ) SAL_THROW_EXTERN_C()
1113 : {
1114 69910 : if (cache != 0)
1115 : {
1116 69910 : rtl_cache_deactivate (cache);
1117 69910 : rtl_cache_destructor (cache);
1118 69910 : rtl_arena_free (gp_cache_arena, cache, sizeof(rtl_cache_type));
1119 : }
1120 69910 : }
1121 :
1122 : /** rtl_cache_alloc()
1123 : */
1124 : void *
1125 199048252 : SAL_CALL rtl_cache_alloc (
1126 : rtl_cache_type * cache
1127 : ) SAL_THROW_EXTERN_C()
1128 : {
1129 199048252 : void * obj = 0;
1130 :
1131 199048252 : if (cache == 0)
1132 1660 : return 0;
1133 :
1134 199046592 : if (alloc_mode == AMode_SYSTEM)
1135 : {
1136 166968 : obj = rtl_allocateMemory(cache->m_type_size);
1137 166968 : if ((obj != 0) && (cache->m_constructor != 0))
1138 : {
1139 135 : if (!((cache->m_constructor)(obj, cache->m_userarg)))
1140 : {
1141 : /* construction failure */
1142 0 : rtl_freeMemory(obj), obj = 0;
1143 : }
1144 : }
1145 166968 : return obj;
1146 : }
1147 :
1148 198879624 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
1149 198879595 : if (cache->m_cpu_curr != 0)
1150 : {
1151 : for (;;)
1152 : {
1153 : /* take object from magazine layer */
1154 : rtl_cache_magazine_type *curr, *prev, *temp;
1155 :
1156 199378262 : curr = cache->m_cpu_curr;
1157 199378262 : if ((curr != 0) && (curr->m_mag_used > 0))
1158 : {
1159 187344990 : obj = curr->m_objects[--curr->m_mag_used];
1160 187344990 : cache->m_cpu_stats.m_alloc += 1;
1161 187344990 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1162 :
1163 187344952 : return (obj);
1164 : }
1165 :
1166 12033272 : prev = cache->m_cpu_prev;
1167 12033272 : if ((prev != 0) && (prev->m_mag_used > 0))
1168 : {
1169 701517 : temp = cache->m_cpu_curr;
1170 701517 : cache->m_cpu_curr = cache->m_cpu_prev;
1171 701517 : cache->m_cpu_prev = temp;
1172 :
1173 701517 : continue;
1174 : }
1175 :
1176 11331755 : temp = rtl_cache_depot_exchange_alloc (cache, prev);
1177 11331758 : if (temp != 0)
1178 : {
1179 214922 : cache->m_cpu_prev = cache->m_cpu_curr;
1180 214922 : cache->m_cpu_curr = temp;
1181 :
1182 214922 : continue;
1183 : }
1184 :
1185 : /* no full magazine: fall through to slab layer */
1186 11116836 : break;
1187 916439 : }
1188 : }
1189 11534608 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1190 :
1191 : /* alloc buffer from slab layer */
1192 11534775 : obj = rtl_cache_slab_alloc (cache);
1193 11534774 : if ((obj != 0) && (cache->m_constructor != 0))
1194 : {
1195 : /* construct object */
1196 219571 : if (!((cache->m_constructor)(obj, cache->m_userarg)))
1197 : {
1198 : /* construction failure */
1199 0 : rtl_cache_slab_free (cache, obj), obj = 0;
1200 : }
1201 : }
1202 11534774 : return (obj);
1203 : }
1204 :
1205 : /** rtl_cache_free()
1206 : */
1207 : void
1208 198406999 : SAL_CALL rtl_cache_free (
1209 : rtl_cache_type * cache,
1210 : void * obj
1211 : ) SAL_THROW_EXTERN_C()
1212 : {
1213 198406999 : if ((obj != 0) && (cache != 0))
1214 : {
1215 198093122 : if (alloc_mode == AMode_SYSTEM)
1216 : {
1217 166858 : if (cache->m_destructor != 0)
1218 : {
1219 : /* destruct object */
1220 0 : (cache->m_destructor)(obj, cache->m_userarg);
1221 : }
1222 166858 : rtl_freeMemory(obj);
1223 166858 : return;
1224 : }
1225 :
1226 197926264 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
1227 :
1228 : for (;;)
1229 : {
1230 : /* return object to magazine layer */
1231 : rtl_cache_magazine_type *curr, *prev, *temp;
1232 :
1233 199266558 : curr = cache->m_cpu_curr;
1234 199266558 : if ((curr != 0) && (curr->m_mag_used < curr->m_mag_size))
1235 : {
1236 197922185 : curr->m_objects[curr->m_mag_used++] = obj;
1237 197922185 : cache->m_cpu_stats.m_free += 1;
1238 197922185 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1239 :
1240 197922210 : return;
1241 : }
1242 :
1243 1344373 : prev = cache->m_cpu_prev;
1244 1344373 : if ((prev != 0) && (prev->m_mag_used == 0))
1245 : {
1246 701514 : temp = cache->m_cpu_curr;
1247 701514 : cache->m_cpu_curr = cache->m_cpu_prev;
1248 701514 : cache->m_cpu_prev = temp;
1249 :
1250 701514 : continue;
1251 : }
1252 :
1253 642859 : temp = rtl_cache_depot_exchange_free (cache, prev);
1254 642859 : if (temp != 0)
1255 : {
1256 425407 : cache->m_cpu_prev = cache->m_cpu_curr;
1257 425407 : cache->m_cpu_curr = temp;
1258 :
1259 425407 : continue;
1260 : }
1261 :
1262 217452 : if (rtl_cache_depot_populate(cache))
1263 : {
1264 213410 : continue;
1265 : }
1266 :
1267 : /* no empty magazine: fall through to slab layer */
1268 4042 : break;
1269 1340331 : }
1270 :
1271 4042 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1272 :
1273 : /* no space for constructed object in magazine layer */
1274 4042 : if (cache->m_destructor != 0)
1275 : {
1276 : /* destruct object */
1277 4042 : (cache->m_destructor)(obj, cache->m_userarg);
1278 : }
1279 :
1280 : /* return buffer to slab layer */
1281 4042 : rtl_cache_slab_free (cache, obj);
1282 : }
1283 : }
1284 :
1285 : /* ================================================================= *
1286 : *
1287 : * cache wsupdate (machdep) internals.
1288 : *
1289 : * ================================================================= */
1290 :
1291 : /** rtl_cache_wsupdate_init()
1292 : *
1293 : * @precond g_cache_list.m_lock initialized
1294 : */
1295 : static void
1296 : rtl_cache_wsupdate_init();
1297 :
1298 : /** rtl_cache_wsupdate_wait()
1299 : *
1300 : * @precond g_cache_list.m_lock acquired
1301 : */
1302 : static void
1303 : rtl_cache_wsupdate_wait (
1304 : unsigned int seconds
1305 : );
1306 :
1307 : /** rtl_cache_wsupdate_fini()
1308 : *
1309 : */
1310 : static void
1311 : rtl_cache_wsupdate_fini();
1312 :
1313 : /* ================================================================= */
1314 :
1315 : #if defined(SAL_UNX)
1316 :
1317 : void SAL_CALL
1318 2535 : rtl_secureZeroMemory (void *Ptr, sal_Size Bytes) SAL_THROW_EXTERN_C()
1319 : {
1320 : //currently glibc doesn't implement memset_s
1321 2535 : volatile char *p = static_cast<volatile char*>(Ptr);
1322 54135630 : while (Bytes--)
1323 54130560 : *p++ = 0;
1324 2535 : }
1325 :
1326 : #include <sys/time.h>
1327 :
1328 : static void *
1329 : rtl_cache_wsupdate_all (void * arg);
1330 :
1331 : static void
1332 1910 : rtl_cache_wsupdate_init()
1333 : {
1334 1910 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1335 1910 : g_cache_list.m_update_done = 0;
1336 1910 : (void) pthread_cond_init (&(g_cache_list.m_update_cond), NULL);
1337 1910 : if (pthread_create (
1338 1910 : &(g_cache_list.m_update_thread), NULL, rtl_cache_wsupdate_all, reinterpret_cast<void*>(10)) != 0)
1339 : {
1340 : /* failure */
1341 0 : g_cache_list.m_update_thread = pthread_t();
1342 : }
1343 1910 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1344 1910 : }
1345 :
1346 : static void
1347 12256 : rtl_cache_wsupdate_wait (unsigned int seconds)
1348 : {
1349 12256 : if (seconds > 0)
1350 : {
1351 : timeval now;
1352 : timespec wakeup;
1353 :
1354 12256 : gettimeofday(&now, 0);
1355 12256 : wakeup.tv_sec = now.tv_sec + (seconds);
1356 12256 : wakeup.tv_nsec = now.tv_usec * 1000;
1357 :
1358 : (void) pthread_cond_timedwait (
1359 : &(g_cache_list.m_update_cond),
1360 : &(g_cache_list.m_lock),
1361 12256 : &wakeup);
1362 : }
1363 12256 : }
1364 :
1365 : static void
1366 1910 : rtl_cache_wsupdate_fini()
1367 : {
1368 1910 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1369 1910 : g_cache_list.m_update_done = 1;
1370 1910 : pthread_cond_signal (&(g_cache_list.m_update_cond));
1371 1910 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1372 :
1373 1910 : if (g_cache_list.m_update_thread != pthread_t())
1374 1910 : pthread_join (g_cache_list.m_update_thread, NULL);
1375 1910 : }
1376 :
1377 : /* ================================================================= */
1378 :
1379 : #elif defined(SAL_W32)
1380 :
1381 : void SAL_CALL
1382 : rtl_secureZeroMemory (void *Ptr, sal_Size Bytes) SAL_THROW_EXTERN_C()
1383 : {
1384 : RtlSecureZeroMemory(Ptr, Bytes);
1385 : }
1386 :
1387 : static DWORD WINAPI
1388 : rtl_cache_wsupdate_all (void * arg);
1389 :
1390 : static void
1391 : rtl_cache_wsupdate_init()
1392 : {
1393 : DWORD dwThreadId;
1394 :
1395 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1396 : g_cache_list.m_update_done = 0;
1397 : g_cache_list.m_update_cond = CreateEvent (0, TRUE, FALSE, 0);
1398 :
1399 : g_cache_list.m_update_thread =
1400 : CreateThread (NULL, 0, rtl_cache_wsupdate_all, (LPVOID)(10), 0, &dwThreadId);
1401 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1402 : }
1403 :
1404 : static void
1405 : rtl_cache_wsupdate_wait (unsigned int seconds)
1406 : {
1407 : if (seconds > 0)
1408 : {
1409 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1410 : WaitForSingleObject (g_cache_list.m_update_cond, (DWORD)(seconds * 1000));
1411 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1412 : }
1413 : }
1414 :
1415 : static void
1416 : rtl_cache_wsupdate_fini()
1417 : {
1418 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1419 : g_cache_list.m_update_done = 1;
1420 : SetEvent (g_cache_list.m_update_cond);
1421 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1422 :
1423 : WaitForSingleObject (g_cache_list.m_update_thread, INFINITE);
1424 : }
1425 :
1426 : #endif /* SAL_UNX || SAL_W32 */
1427 :
1428 : /* ================================================================= */
1429 :
1430 : /** rtl_cache_depot_wsupdate()
1431 : * update depot stats and purge excess magazines.
1432 : *
1433 : * @precond cache->m_depot_lock acquired
1434 : */
1435 : static void
1436 729886 : rtl_cache_depot_wsupdate (
1437 : rtl_cache_type * cache,
1438 : rtl_cache_depot_type * depot
1439 : )
1440 : {
1441 : sal_Size npurge;
1442 :
1443 729886 : depot->m_prev_min = depot->m_curr_min;
1444 729886 : depot->m_curr_min = depot->m_mag_count;
1445 :
1446 729886 : npurge = depot->m_curr_min < depot->m_prev_min ? depot->m_curr_min : depot->m_prev_min;
1447 740267 : for (; npurge > 0; npurge--)
1448 : {
1449 10381 : rtl_cache_magazine_type * mag = rtl_cache_depot_dequeue (depot);
1450 10381 : if (mag != 0)
1451 : {
1452 10381 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1453 10381 : rtl_cache_magazine_clear (cache, mag);
1454 10381 : rtl_cache_free (cache->m_magazine_cache, mag);
1455 10381 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
1456 : }
1457 : }
1458 : // coverity[missing_unlock]
1459 729886 : }
1460 :
1461 : /** rtl_cache_wsupdate()
1462 : *
1463 : * @precond cache->m_depot_lock released
1464 : */
1465 : static void
1466 364943 : rtl_cache_wsupdate (
1467 : rtl_cache_type * cache
1468 : )
1469 : {
1470 364943 : if (cache->m_magazine_cache != 0)
1471 : {
1472 364943 : RTL_MEMORY_LOCK_ACQUIRE(&(cache->m_depot_lock));
1473 :
1474 : // SAL_INFO(
1475 : // "sal.rtl",
1476 : // "rtl_cache_wsupdate(" << cache->m_name
1477 : // << ") [depot: count, curr_min, prev_min] full: "
1478 : // << cache->m_depot_full.m_mag_count << ", "
1479 : // << cache->m_depot_full.m_curr_min << ", "
1480 : // << cache->m_depot_full.m_prev_min << "; empty: "
1481 : // << cache->m_depot_empty.m_mag_count << ", "
1482 : // << cache->m_depot_empty.m_curr_min << ", "
1483 : // << cache->m_depot_empty.m_prev_min);
1484 :
1485 364943 : rtl_cache_depot_wsupdate (cache, &(cache->m_depot_full));
1486 364943 : rtl_cache_depot_wsupdate (cache, &(cache->m_depot_empty));
1487 :
1488 364943 : RTL_MEMORY_LOCK_RELEASE(&(cache->m_depot_lock));
1489 : }
1490 364943 : }
1491 :
1492 : /** rtl_cache_wsupdate_all()
1493 : *
1494 : */
1495 : #if defined(SAL_UNX)
1496 : static void *
1497 : #elif defined(SAL_W32)
1498 : static DWORD WINAPI
1499 : #endif /* SAL_UNX || SAL_W32 */
1500 1910 : rtl_cache_wsupdate_all (void * arg)
1501 : {
1502 1910 : osl::Thread::setName("rtl_cache_wsupdate_all");
1503 : unsigned int seconds = sal::static_int_cast< unsigned int >(
1504 1910 : reinterpret_cast< sal_uIntPtr >(arg));
1505 :
1506 1910 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1507 16076 : while (!g_cache_list.m_update_done)
1508 : {
1509 12256 : rtl_cache_wsupdate_wait (seconds);
1510 12256 : if (!g_cache_list.m_update_done)
1511 : {
1512 : rtl_cache_type * head, * cache;
1513 :
1514 10685 : head = &(g_cache_list.m_cache_head);
1515 375628 : for (cache = head->m_cache_next;
1516 : cache != head;
1517 : cache = cache->m_cache_next)
1518 : {
1519 364943 : rtl_cache_wsupdate (cache);
1520 : }
1521 : }
1522 : }
1523 1910 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1524 :
1525 1910 : return 0;
1526 : }
1527 :
1528 : /* ================================================================= *
1529 : *
1530 : * cache initialization.
1531 : *
1532 : * ================================================================= */
1533 :
1534 : void
1535 1910 : rtl_cache_init()
1536 : {
1537 : {
1538 : /* list of caches */
1539 1910 : RTL_MEMORY_LOCK_INIT(&(g_cache_list.m_lock));
1540 1910 : (void) rtl_cache_constructor (&(g_cache_list.m_cache_head));
1541 : }
1542 : {
1543 : /* cache: internal arena */
1544 : assert(gp_cache_arena == 0);
1545 :
1546 : gp_cache_arena = rtl_arena_create (
1547 : "rtl_cache_internal_arena",
1548 : 64, /* quantum */
1549 : 0, /* no quantum caching */
1550 : NULL, /* default source */
1551 : rtl_arena_alloc,
1552 : rtl_arena_free,
1553 : 0 /* flags */
1554 1910 : );
1555 : assert(gp_cache_arena != 0);
1556 :
1557 : /* check 'gp_default_arena' initialization */
1558 : assert(gp_default_arena != 0);
1559 : }
1560 : {
1561 : /* cache: magazine cache */
1562 : static rtl_cache_type g_cache_magazine_cache;
1563 :
1564 : assert(gp_cache_magazine_cache == 0);
1565 1910 : (void) rtl_cache_constructor (&g_cache_magazine_cache);
1566 :
1567 : gp_cache_magazine_cache = rtl_cache_activate (
1568 : &g_cache_magazine_cache,
1569 : "rtl_cache_magazine_cache",
1570 : sizeof(rtl_cache_magazine_type), /* objsize */
1571 : 0, /* objalign */
1572 : rtl_cache_magazine_constructor,
1573 : rtl_cache_magazine_destructor,
1574 : 0, /* reclaim */
1575 : 0, /* userarg: NYI */
1576 : gp_default_arena, /* source */
1577 : RTL_CACHE_FLAG_NOMAGAZINE /* during bootstrap; activated below */
1578 1910 : );
1579 : assert(gp_cache_magazine_cache != 0);
1580 :
1581 : /* activate magazine layer */
1582 1910 : g_cache_magazine_cache.m_magazine_cache = gp_cache_magazine_cache;
1583 : }
1584 : {
1585 : /* cache: slab (struct) cache */
1586 : static rtl_cache_type g_cache_slab_cache;
1587 :
1588 : assert(gp_cache_slab_cache == 0);
1589 1910 : (void) rtl_cache_constructor (&g_cache_slab_cache);
1590 :
1591 : gp_cache_slab_cache = rtl_cache_activate (
1592 : &g_cache_slab_cache,
1593 : "rtl_cache_slab_cache",
1594 : sizeof(rtl_cache_slab_type), /* objsize */
1595 : 0, /* objalign */
1596 : rtl_cache_slab_constructor,
1597 : rtl_cache_slab_destructor,
1598 : 0, /* reclaim */
1599 : 0, /* userarg: none */
1600 : gp_default_arena, /* source */
1601 : 0 /* flags: none */
1602 1910 : );
1603 : assert(gp_cache_slab_cache != 0);
1604 : }
1605 : {
1606 : /* cache: bufctl cache */
1607 : static rtl_cache_type g_cache_bufctl_cache;
1608 :
1609 : assert(gp_cache_bufctl_cache == 0);
1610 1910 : (void) rtl_cache_constructor (&g_cache_bufctl_cache);
1611 :
1612 : gp_cache_bufctl_cache = rtl_cache_activate (
1613 : &g_cache_bufctl_cache,
1614 : "rtl_cache_bufctl_cache",
1615 : sizeof(rtl_cache_bufctl_type), /* objsize */
1616 : 0, /* objalign */
1617 : 0, /* constructor */
1618 : 0, /* destructor */
1619 : 0, /* reclaim */
1620 : 0, /* userarg */
1621 : gp_default_arena, /* source */
1622 : 0 /* flags: none */
1623 1910 : );
1624 : assert(gp_cache_bufctl_cache != 0);
1625 : }
1626 :
1627 1910 : rtl_cache_wsupdate_init();
1628 : // SAL_INFO("sal.rtl", "rtl_cache_init completed");
1629 1910 : }
1630 :
1631 : /* ================================================================= */
1632 :
1633 : void
1634 1910 : rtl_cache_fini()
1635 : {
1636 1910 : if (gp_cache_arena != 0)
1637 : {
1638 : rtl_cache_type * cache, * head;
1639 :
1640 1910 : rtl_cache_wsupdate_fini();
1641 :
1642 1910 : if (gp_cache_bufctl_cache != 0)
1643 : {
1644 1910 : cache = gp_cache_bufctl_cache, gp_cache_bufctl_cache = 0;
1645 1910 : rtl_cache_deactivate (cache);
1646 1910 : rtl_cache_destructor (cache);
1647 : }
1648 1910 : if (gp_cache_slab_cache != 0)
1649 : {
1650 1910 : cache = gp_cache_slab_cache, gp_cache_slab_cache = 0;
1651 1910 : rtl_cache_deactivate (cache);
1652 1910 : rtl_cache_destructor (cache);
1653 : }
1654 1910 : if (gp_cache_magazine_cache != 0)
1655 : {
1656 1910 : cache = gp_cache_magazine_cache, gp_cache_magazine_cache = 0;
1657 1910 : rtl_cache_deactivate (cache);
1658 1910 : rtl_cache_destructor (cache);
1659 : }
1660 1910 : if (gp_cache_arena != 0)
1661 : {
1662 1910 : rtl_arena_destroy (gp_cache_arena);
1663 1910 : gp_cache_arena = 0;
1664 : }
1665 :
1666 1910 : RTL_MEMORY_LOCK_ACQUIRE(&(g_cache_list.m_lock));
1667 1910 : head = &(g_cache_list.m_cache_head);
1668 1910 : for (cache = head->m_cache_next; cache != head; cache = cache->m_cache_next)
1669 : {
1670 : // SAL_INFO(
1671 : // "sal.rtl",
1672 : // "rtl_cache_fini(" << cache->m_name << ") [slab]: allocs: "
1673 : // << cache->m_slab_stats.m_alloc << ", frees: "
1674 : // << cache->m_slab_stats.m_free << "; total: "
1675 : // << cache->m_slab_stats.m_mem_total << ", used: "
1676 : // << cache->m_slab_stats.m_mem_alloc << "; [cpu]: allocs: "
1677 : // << cache->m_cpu_stats.m_alloc << ", frees: "
1678 : // << cache->m_cpu_stats.m_free << "; [total]: allocs: "
1679 : // << (cache->m_slab_stats.m_alloc
1680 : // + cache->m_cpu_stats.m_alloc)
1681 : // << ", frees: "
1682 : // << (cache->m_slab_stats.m_free
1683 : // + cache->m_cpu_stats.m_free));
1684 : }
1685 1910 : RTL_MEMORY_LOCK_RELEASE(&(g_cache_list.m_lock));
1686 : }
1687 : // SAL_INFO("sal.rtl", "rtl_cache_fini completed");
1688 1910 : }
1689 :
1690 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|