Rev 780 | Rev 782 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 780 | Rev 781 | ||
|---|---|---|---|
| Line 305... | Line 305... | ||
| 305 | 305 | ||
| 306 | /**************************************/ |
306 | /**************************************/ |
| 307 | /* CPU-Cache slab functions */ |
307 | /* CPU-Cache slab functions */ |
| 308 | 308 | ||
| 309 | /** |
309 | /** |
| - | 310 | * Finds a full magazine in cache, takes it from list |
|
| - | 311 | * and returns it |
|
| - | 312 | * |
|
| - | 313 | * @param first If true, return first, else last mag |
|
| - | 314 | */ |
|
| - | 315 | static slab_magazine_t * get_mag_from_cache(slab_cache_t *cache, |
|
| - | 316 | int first) |
|
| - | 317 | { |
|
| - | 318 | slab_magazine_t *mag = NULL; |
|
| - | 319 | link_t *cur; |
|
| - | 320 | ||
| - | 321 | spinlock_lock(&cache->maglock); |
|
| - | 322 | if (!list_empty(&cache->magazines)) { |
|
| - | 323 | if (first) |
|
| - | 324 | cur = cache->magazines.next; |
|
| - | 325 | else |
|
| - | 326 | cur = cache->magazines.prev; |
|
| - | 327 | mag = list_get_instance(cur, slab_magazine_t, link); |
|
| - | 328 | list_remove(&mag->link); |
|
| - | 329 | atomic_dec(&cache->magazine_counter); |
|
| - | 330 | } |
|
| - | 331 | spinlock_unlock(&cache->maglock); |
|
| - | 332 | return mag; |
|
| - | 333 | } |
|
| - | 334 | ||
| - | 335 | /** Prepend magazine to magazine list in cache */ |
|
| - | 336 | static void put_mag_to_cache(slab_cache_t *cache, slab_magazine_t *mag) |
|
| - | 337 | { |
|
| - | 338 | spinlock_lock(&cache->maglock); |
|
| - | 339 | ||
| - | 340 | list_prepend(&mag->link, &cache->magazines); |
|
| - | 341 | atomic_inc(&cache->magazine_counter); |
|
| - | 342 | ||
| - | 343 | spinlock_unlock(&cache->maglock); |
|
| - | 344 | } |
|
| - | 345 | ||
| - | 346 | /** |
|
| 310 | * Free all objects in magazine and free memory associated with magazine |
347 | * Free all objects in magazine and free memory associated with magazine |
| 311 | * |
348 | * |
| 312 | * @return Number of freed pages |
349 | * @return Number of freed pages |
| 313 | */ |
350 | */ |
| 314 | static count_t magazine_destroy(slab_cache_t *cache, |
351 | static count_t magazine_destroy(slab_cache_t *cache, |
| Line 347... | Line 384... | ||
| 347 | cache->mag_cache[CPU->id].last = cmag; |
384 | cache->mag_cache[CPU->id].last = cmag; |
| 348 | return lastmag; |
385 | return lastmag; |
| 349 | } |
386 | } |
| 350 | } |
387 | } |
| 351 | /* Local magazines are empty, import one from magazine list */ |
388 | /* Local magazines are empty, import one from magazine list */ |
| 352 | spinlock_lock(&cache->maglock); |
389 | newmag = get_mag_from_cache(cache, 1); |
| 353 | if (list_empty(&cache->magazines)) { |
390 | if (!newmag) |
| 354 | spinlock_unlock(&cache->maglock); |
- | |
| 355 | return NULL; |
391 | return NULL; |
| 356 | } |
- | |
| 357 | newmag = list_get_instance(cache->magazines.next, |
- | |
| 358 | slab_magazine_t, |
- | |
| 359 | link); |
- | |
| 360 | list_remove(&newmag->link); |
- | |
| 361 | spinlock_unlock(&cache->maglock); |
- | |
| 362 | 392 | ||
| 363 | if (lastmag) |
393 | if (lastmag) |
| 364 | slab_free(&mag_cache, lastmag); |
394 | magazine_destroy(cache, lastmag); |
| - | 395 | ||
| 365 | cache->mag_cache[CPU->id].last = cmag; |
396 | cache->mag_cache[CPU->id].last = cmag; |
| 366 | cache->mag_cache[CPU->id].current = newmag; |
397 | cache->mag_cache[CPU->id].current = newmag; |
| 367 | return newmag; |
398 | return newmag; |
| 368 | } |
399 | } |
| 369 | 400 | ||
| Line 432... | Line 463... | ||
| 432 | return NULL; |
463 | return NULL; |
| 433 | newmag->size = SLAB_MAG_SIZE; |
464 | newmag->size = SLAB_MAG_SIZE; |
| 434 | newmag->busy = 0; |
465 | newmag->busy = 0; |
| 435 | 466 | ||
| 436 | /* Flush last to magazine list */ |
467 | /* Flush last to magazine list */ |
| 437 | if (lastmag) { |
468 | if (lastmag) |
| 438 | spinlock_lock(&cache->maglock); |
469 | put_mag_to_cache(cache, lastmag); |
| 439 | list_prepend(&lastmag->link, &cache->magazines); |
- | |
| 440 | spinlock_unlock(&cache->maglock); |
- | |
| 441 | } |
470 | |
| 442 | /* Move current as last, save new as current */ |
471 | /* Move current as last, save new as current */ |
| 443 | cache->mag_cache[CPU->id].last = cmag; |
472 | cache->mag_cache[CPU->id].last = cmag; |
| 444 | cache->mag_cache[CPU->id].current = newmag; |
473 | cache->mag_cache[CPU->id].current = newmag; |
| 445 | 474 | ||
| 446 | return newmag; |
475 | return newmag; |
| Line 586... | Line 615... | ||
| 586 | */ |
615 | */ |
| 587 | static count_t _slab_reclaim(slab_cache_t *cache, int flags) |
616 | static count_t _slab_reclaim(slab_cache_t *cache, int flags) |
| 588 | { |
617 | { |
| 589 | int i; |
618 | int i; |
| 590 | slab_magazine_t *mag; |
619 | slab_magazine_t *mag; |
| 591 | link_t *cur; |
- | |
| 592 | count_t frames = 0; |
620 | count_t frames = 0; |
| - | 621 | int magcount; |
|
| 593 | 622 | ||
| 594 | if (cache->flags & SLAB_CACHE_NOMAGAZINE) |
623 | if (cache->flags & SLAB_CACHE_NOMAGAZINE) |
| 595 | return 0; /* Nothing to do */ |
624 | return 0; /* Nothing to do */ |
| 596 | 625 | ||
| 597 | /* First lock all cpu caches, then the complete cache lock */ |
626 | /* We count up to original magazine count to avoid |
| 598 | if (flags & SLAB_RECLAIM_ALL) { |
627 | * endless loop |
| - | 628 | */ |
|
| 599 | for (i=0; i < config.cpu_count; i++) |
629 | magcount = atomic_get(&cache->magazine_counter); |
| - | 630 | while (magcount-- && (mag=get_mag_from_cache(cache,0))) { |
|
| 600 | spinlock_lock(&cache->mag_cache[i].lock); |
631 | frames += magazine_destroy(cache,mag); |
| - | 632 | if (!(flags & SLAB_RECLAIM_ALL) && frames) |
|
| - | 633 | break; |
|
| 601 | } |
634 | } |
| 602 | spinlock_lock(&cache->maglock); |
- | |
| 603 | 635 | ||
| 604 | if (flags & SLAB_RECLAIM_ALL) { |
636 | if (flags & SLAB_RECLAIM_ALL) { |
| 605 | /* Aggressive memfree */ |
637 | /* Free cpu-bound magazines */ |
| 606 | /* Destroy CPU magazines */ |
638 | /* Destroy CPU magazines */ |
| 607 | for (i=0; i<config.cpu_count; i++) { |
639 | for (i=0; i<config.cpu_count; i++) { |
| - | 640 | spinlock_lock(&cache->mag_cache[i].lock); |
|
| - | 641 | ||
| 608 | mag = cache->mag_cache[i].current; |
642 | mag = cache->mag_cache[i].current; |
| 609 | if (mag) |
643 | if (mag) |
| 610 | frames += magazine_destroy(cache, mag); |
644 | frames += magazine_destroy(cache, mag); |
| 611 | cache->mag_cache[i].current = NULL; |
645 | cache->mag_cache[i].current = NULL; |
| 612 | 646 | ||
| 613 | mag = cache->mag_cache[i].last; |
647 | mag = cache->mag_cache[i].last; |
| 614 | if (mag) |
648 | if (mag) |
| 615 | frames += magazine_destroy(cache, mag); |
649 | frames += magazine_destroy(cache, mag); |
| 616 | cache->mag_cache[i].last = NULL; |
650 | cache->mag_cache[i].last = NULL; |
| 617 | } |
- | |
| 618 | } |
651 | |
| 619 | /* We can release the cache locks now */ |
- | |
| 620 | if (flags & SLAB_RECLAIM_ALL) { |
- | |
| 621 | for (i=0; i < config.cpu_count; i++) |
- | |
| 622 | spinlock_unlock(&cache->mag_cache[i].lock); |
652 | spinlock_unlock(&cache->mag_cache[i].lock); |
| - | 653 | } |
|
| 623 | } |
654 | } |
| 624 | /* Destroy full magazines */ |
- | |
| 625 | cur=cache->magazines.prev; |
- | |
| 626 | 655 | ||
| 627 | while (cur != &cache->magazines) { |
- | |
| 628 | mag = list_get_instance(cur, slab_magazine_t, link); |
- | |
| 629 | - | ||
| 630 | cur = cur->prev; |
- | |
| 631 | list_remove(&mag->link); |
- | |
| 632 | frames += magazine_destroy(cache,mag); |
- | |
| 633 | /* If we do not do full reclaim, break |
- | |
| 634 | * as soon as something is freed */ |
- | |
| 635 | if (!(flags & SLAB_RECLAIM_ALL) && frames) |
- | |
| 636 | break; |
- | |
| 637 | } |
- | |
| 638 | - | ||
| 639 | spinlock_unlock(&cache->maglock); |
- | |
| 640 | - | ||
| 641 | return frames; |
656 | return frames; |
| 642 | } |
657 | } |
| 643 | 658 | ||
| 644 | /** Check that there are no slabs and remove cache from system */ |
659 | /** Check that there are no slabs and remove cache from system */ |
| 645 | void slab_cache_destroy(slab_cache_t *cache) |
660 | void slab_cache_destroy(slab_cache_t *cache) |
| 646 | { |
661 | { |
| - | 662 | ipl_t ipl; |
|
| - | 663 | ||
| - | 664 | /* First remove cache from link, so that we don't need |
|
| - | 665 | * to disable interrupts later |
|
| - | 666 | */ |
|
| - | 667 | ||
| - | 668 | ipl = interrupts_disable(); |
|
| - | 669 | spinlock_lock(&slab_cache_lock); |
|
| - | 670 | ||
| - | 671 | list_remove(&cache->link); |
|
| - | 672 | ||
| - | 673 | spinlock_unlock(&slab_cache_lock); |
|
| - | 674 | interrupts_restore(ipl); |
|
| - | 675 | ||
| 647 | /* Do not lock anything, we assume the software is correct and |
676 | /* Do not lock anything, we assume the software is correct and |
| 648 | * does not touch the cache when it decides to destroy it */ |
677 | * does not touch the cache when it decides to destroy it */ |
| 649 | 678 | ||
| 650 | /* Destroy all magazines */ |
679 | /* Destroy all magazines */ |
| 651 | _slab_reclaim(cache, SLAB_RECLAIM_ALL); |
680 | _slab_reclaim(cache, SLAB_RECLAIM_ALL); |
| Line 653... | Line 682... | ||
| 653 | /* All slabs must be empty */ |
682 | /* All slabs must be empty */ |
| 654 | if (!list_empty(&cache->full_slabs) \ |
683 | if (!list_empty(&cache->full_slabs) \ |
| 655 | || !list_empty(&cache->partial_slabs)) |
684 | || !list_empty(&cache->partial_slabs)) |
| 656 | panic("Destroying cache that is not empty."); |
685 | panic("Destroying cache that is not empty."); |
| 657 | 686 | ||
| 658 | spinlock_lock(&slab_cache_lock); |
- | |
| 659 | list_remove(&cache->link); |
- | |
| 660 | spinlock_unlock(&slab_cache_lock); |
- | |
| 661 | - | ||
| 662 | slab_free(&slab_cache_cache, cache); |
687 | slab_free(&slab_cache_cache, cache); |
| 663 | } |
688 | } |
| 664 | 689 | ||
| 665 | /** Allocate new object from cache - if no flags given, always returns |
690 | /** Allocate new object from cache - if no flags given, always returns |
| 666 | memory */ |
691 | memory */ |
| Line 672... | Line 697... | ||
| 672 | /* Disable interrupts to avoid deadlocks with interrupt handlers */ |
697 | /* Disable interrupts to avoid deadlocks with interrupt handlers */ |
| 673 | ipl = interrupts_disable(); |
698 | ipl = interrupts_disable(); |
| 674 | 699 | ||
| 675 | if (!(cache->flags & SLAB_CACHE_NOMAGAZINE)) |
700 | if (!(cache->flags & SLAB_CACHE_NOMAGAZINE)) |
| 676 | result = magazine_obj_get(cache); |
701 | result = magazine_obj_get(cache); |
| 677 | - | ||
| 678 | if (!result) |
702 | if (!result) |
| 679 | result = slab_obj_create(cache, flags); |
703 | result = slab_obj_create(cache, flags); |
| 680 | 704 | ||
| 681 | interrupts_restore(ipl); |
705 | interrupts_restore(ipl); |
| 682 | 706 | ||
| Line 718... | Line 742... | ||
| 718 | 742 | ||
| 719 | spinlock_lock(&slab_cache_lock); |
743 | spinlock_lock(&slab_cache_lock); |
| 720 | 744 | ||
| 721 | /* TODO: Add assert, that interrupts are disabled, otherwise |
745 | /* TODO: Add assert, that interrupts are disabled, otherwise |
| 722 | * memory allocation from interrupts can deadlock. |
746 | * memory allocation from interrupts can deadlock. |
| - | 747 | * - cache_destroy can call this with interrupts enabled :-/ |
|
| 723 | */ |
748 | */ |
| 724 | 749 | ||
| 725 | for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) { |
750 | for (cur = slab_cache_list.next;cur!=&slab_cache_list; cur=cur->next) { |
| 726 | cache = list_get_instance(cur, slab_cache_t, link); |
751 | cache = list_get_instance(cur, slab_cache_t, link); |
| 727 | frames += _slab_reclaim(cache, flags); |
752 | frames += _slab_reclaim(cache, flags); |
| Line 812... | Line 837... | ||
| 812 | } |
837 | } |
| 813 | 838 | ||
| 814 | 839 | ||
| 815 | void kfree(void *obj) |
840 | void kfree(void *obj) |
| 816 | { |
841 | { |
| 817 | slab_t *slab = obj2slab(obj); |
842 | slab_t *slab; |
| 818 | 843 | ||
| - | 844 | if (!obj) return; |
|
| - | 845 | ||
| - | 846 | slab = obj2slab(obj); |
|
| 819 | _slab_free(slab->cache, obj, slab); |
847 | _slab_free(slab->cache, obj, slab); |
| 820 | } |
848 | } |