void Slab_cache::free (void *ptr) { Lock_guard <Spinlock> guard (lock); Slab *slab = reinterpret_cast<Slab *>(reinterpret_cast<mword>(ptr) & ~PAGE_MASK); bool was_full = slab->full(); slab->free (ptr); // Deallocate from slab if (EXPECT_FALSE (was_full)) { // There are full slabs in front of us and we're partial; requeue if (slab->prev && slab->prev->full()) { // Dequeue slab->prev->next = slab->next; if (slab->next) slab->next->prev = slab->prev; // Enqueue after curr if (curr) { slab->prev = curr; slab->next = curr->next; curr->next = curr->next->prev = slab; } // Enqueue as head else { slab->prev = nullptr; slab->next = head; head = head->prev = slab; } } curr = slab; } else if (EXPECT_FALSE (slab->empty())) { // There are partial slabs in front of us and we're empty; requeue if (slab->prev && !slab->prev->empty()) { // Make partial slab in front of us current if we were current if (slab == curr) curr = slab->prev; // Dequeue slab->prev->next = slab->next; if (slab->next) slab->next->prev = slab->prev; // Enqueue as head slab->prev = nullptr; slab->next = head; head = head->prev = slab; } } }
PUBLIC void Slab_cache::free(void *cache_entry) // return initialized member to cache { Slab *to_free = 0; { auto guard = lock_guard(lock); Slab *s = reinterpret_cast<Slab*> ((reinterpret_cast<unsigned long>(cache_entry) & ~(_slab_size - 1)) + _slab_size - sizeof(Slab)); bool was_full = s->is_full(); s->free(cache_entry); if (was_full) { cxx::H_list<Slab>::remove(s); _partial.add(s); } else if (s->is_empty()) { cxx::H_list<Slab>::remove(s); if (_num_empty < 2) { _empty.add(s); ++_num_empty; } else to_free = s; } else { // We weren't either full or empty; we already had free // elements. This changes nothing in the queue, and there // already must have been a _first_available_slab. } } if (to_free) { to_free->~Slab(); block_free(reinterpret_cast<char *>(to_free + 1) - _slab_size, _slab_size); } }