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