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