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