/*! Called by UnmapPage() after performing the architecture specific part. Looks up the page, updates its flags, removes the page-area mapping, and requeues the page, if necessary. */ void VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber, bool accessed, bool modified, bool updatePageQueue) { if (area->cache_type == CACHE_TYPE_DEVICE) { recursive_lock_unlock(&fLock); return; } // get the page vm_page* page = vm_lookup_page(pageNumber); ASSERT_PRINT(page != NULL, "page number: %#" B_PRIxPHYSADDR ", accessed: %d, modified: %d", pageNumber, accessed, modified); // transfer the accessed/dirty flags to the page page->accessed |= accessed; page->modified |= modified; // remove the mapping object/decrement the wired_count of the page vm_page_mapping* mapping = NULL; if (area->wiring == B_NO_LOCK) { vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) { area->mappings.Remove(mapping); page->mappings.Remove(mapping); break; } } ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#" B_PRIxPHYSADDR ", accessed: %d, modified: %d", page, pageNumber, accessed, modified); } else page->DecrementWiredCount(); recursive_lock_unlock(&fLock); if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); if (updatePageQueue) { if (page->Cache()->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); } } if (mapping != NULL) { bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0)); } }
static void run_main_loop (void) { int k; g_timeout_add_full (G_PRIORITY_LOW, 10000, run_cleanup_tasks, NULL, NULL); gtk_main (); object_cache_free (>k_main_tile_set_cache); object_cache_free (>k_sgf_markup_tile_set_cache); #if THREADS_SUPPORTED g_source_destroy (thread_events); g_async_queue_unref (thread_events_queue); #endif if (objects_to_finalize) { /* FIXME: Use g_ptr_array_foreach() when we drop support for * pre-2.4 GTK+. */ for (k = 0; k < objects_to_finalize->len; k++) g_object_unref (g_ptr_array_index (objects_to_finalize, k)); g_ptr_array_free (objects_to_finalize, TRUE); } if (pointers_to_free) { /* FIXME: Likewise. */ for (k = 0; k < pointers_to_free->len; k++) g_free (g_ptr_array_index (pointers_to_free, k)); g_ptr_array_free (pointers_to_free, TRUE); } configuration_write_to_file (gtk_configuration_sections, NUM_GTK_CONFIGURATION_SECTIONS, configuration_file); g_free (configuration_file); configuration_dispose (gtk_configuration_sections, NUM_GTK_CONFIGURATION_SECTIONS); }
void test5() { object_cache_t cache = object_cache_create("foobar", 16, 0, NULL, NULL, NULL); static const int N = 1024; void *buf[N]; for (int i = 0; i < N; i++) buf[i] = object_cache_alloc(cache); for (int i = 0; i < N; i++) object_cache_free(cache, buf[i]); object_cache_destroy(cache); }
/*! Called by ClearAccessedAndModified() after performing the architecture specific part. Looks up the page and removes the page-area mapping. */ void VMTranslationMap::UnaccessedPageUnmapped(VMArea* area, page_num_t pageNumber) { if (area->cache_type == CACHE_TYPE_DEVICE) { recursive_lock_unlock(&fLock); return; } // get the page vm_page* page = vm_lookup_page(pageNumber); ASSERT_PRINT(page != NULL, "page number: %#" B_PRIxPHYSADDR, pageNumber); // remove the mapping object/decrement the wired_count of the page vm_page_mapping* mapping = NULL; if (area->wiring == B_NO_LOCK) { vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) { area->mappings.Remove(mapping); page->mappings.Remove(mapping); break; } } ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#" B_PRIxPHYSADDR, page, pageNumber); } else page->DecrementWiredCount(); recursive_lock_unlock(&fLock); if (!page->IsMapped()) atomic_add(&gMappedPagesCount, -1); if (mapping != NULL) { object_cache_free(gPageMappingsObjectCache, mapping, CACHE_DONT_WAIT_FOR_MEMORY | CACHE_DONT_LOCK_KERNEL_SPACE); // Since this is called by the page daemon, we never want to lock // the kernel address space. } }
void ARMVMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace, bool ignoreTopCachePageFlags) { if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { ARMVMTranslationMap32Bit::UnmapPages(area, area->Base(), area->Size(), true); return; } bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; page_directory_entry* pd = fPagingStructures->pgdir_virt; RecursiveLocker locker(fLock); VMAreaMappings mappings; mappings.MoveFrom(&area->mappings); for (VMAreaMappings::Iterator it = mappings.GetIterator(); vm_page_mapping* mapping = it.Next();) { vm_page* page = mapping->page; page->mappings.Remove(mapping); VMCache* cache = page->Cache(); bool pageFullyUnmapped = false; if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); pageFullyUnmapped = true; } if (unmapPages || cache != area->cache) { addr_t address = area->Base() + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); int index = VADDR_TO_PDENT(address); if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page dir entry", page, area, address); continue; } ThreadCPUPinner pinner(thread_get_current_thread()); page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( pd[index] & ARM_PDE_ADDRESS_MASK); page_table_entry oldEntry = ARMPagingMethod32Bit::ClearPageTableEntry( &pt[VADDR_TO_PTENT(address)]); pinner.Unlock(); if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table entry", page, area, address); continue; } // transfer the accessed/dirty flags to the page and invalidate // the mapping, if necessary if (true /*(oldEntry & ARM_PTE_ACCESSED) != 0*/) { // XXX IRA page->accessed = true; if (!deletingAddressSpace) InvalidatePage(address); } if (true /*(oldEntry & ARM_PTE_DIRTY) != 0*/) page->modified = true; if (pageFullyUnmapped) { DEBUG_PAGE_ACCESS_START(page); if (cache->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); DEBUG_PAGE_ACCESS_END(page); } } fMapCount--; } Flush(); // flush explicitely, since we directly use the lock locker.Unlock(); bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = mappings.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }
void ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size, bool updatePageQueue) { if (size == 0) return; addr_t start = base; addr_t end = base + size - 1; TRACE("ARMVMTranslationMap32Bit::UnmapPages(%p, %#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", area, start, end); page_directory_entry* pd = fPagingStructures->pgdir_virt; VMAreaMappings queue; RecursiveLocker locker(fLock); do { int index = VADDR_TO_PDENT(start); if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) { // no page table here, move the start up to access the next page // table start = ROUNDUP(start + 1, kPageTableAlignment); continue; } Thread* thread = thread_get_current_thread(); ThreadCPUPinner pinner(thread); page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( pd[index] & ARM_PDE_ADDRESS_MASK); for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); index++, start += B_PAGE_SIZE) { page_table_entry oldEntry = ARMPagingMethod32Bit::ClearPageTableEntry(&pt[index]); if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) continue; fMapCount--; if (true /*(oldEntry & ARM_PTE_ACCESSED) != 0*/) { // XXX IRA // Note, that we only need to invalidate the address, if the // accessed flags was set, since only then the entry could have // been in any TLB. InvalidatePage(start); } if (area->cache_type != CACHE_TYPE_DEVICE) { // get the page vm_page* page = vm_lookup_page( (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE); ASSERT(page != NULL); DEBUG_PAGE_ACCESS_START(page); // transfer the accessed/dirty flags to the page if (/*(oldEntry & ARM_PTE_ACCESSED) != 0*/ true) // XXX IRA page->accessed = true; if (/*(oldEntry & ARM_PTE_DIRTY) != 0 */ true) page->modified = true; // remove the mapping object/decrement the wired_count of the // page if (area->wiring == B_NO_LOCK) { vm_page_mapping* mapping = NULL; vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) break; } ASSERT(mapping != NULL); area->mappings.Remove(mapping); page->mappings.Remove(mapping); queue.Add(mapping); } else page->DecrementWiredCount(); if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); if (updatePageQueue) { if (page->Cache()->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); } } DEBUG_PAGE_ACCESS_END(page); } } Flush(); // flush explicitly, since we directly use the lock } while (start != 0 && start < end); // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not // really critical here, as in all cases this method is used, the unmapped // area range is unmapped for good (resized/cut) and the pages will likely // be freed. locker.Unlock(); // free removed mappings bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = queue.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }
void X86VMTranslationMap64Bit::UnmapArea(VMArea* area, bool deletingAddressSpace, bool ignoreTopCachePageFlags) { TRACE("X86VMTranslationMap64Bit::UnmapArea(%p)\n", area); if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { X86VMTranslationMap64Bit::UnmapPages(area, area->Base(), area->Size(), true); return; } bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; RecursiveLocker locker(fLock); ThreadCPUPinner pinner(thread_get_current_thread()); VMAreaMappings mappings; mappings.MoveFrom(&area->mappings); for (VMAreaMappings::Iterator it = mappings.GetIterator(); vm_page_mapping* mapping = it.Next();) { vm_page* page = mapping->page; page->mappings.Remove(mapping); VMCache* cache = page->Cache(); bool pageFullyUnmapped = false; if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); pageFullyUnmapped = true; } if (unmapPages || cache != area->cache) { addr_t address = area->Base() + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); uint64* entry = X86PagingMethod64Bit::PageTableEntryForAddress( fPagingStructures->VirtualPML4(), address, fIsKernelMap, false, NULL, fPageMapper, fMapCount); if (entry == NULL) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table", page, area, address); continue; } uint64 oldEntry = X86PagingMethod64Bit::ClearTableEntry(entry); if ((oldEntry & X86_64_PTE_PRESENT) == 0) { panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " "has no page table entry", page, area, address); continue; } // transfer the accessed/dirty flags to the page and invalidate // the mapping, if necessary if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { page->accessed = true; if (!deletingAddressSpace) InvalidatePage(address); } if ((oldEntry & X86_64_PTE_DIRTY) != 0) page->modified = true; if (pageFullyUnmapped) { DEBUG_PAGE_ACCESS_START(page); if (cache->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); DEBUG_PAGE_ACCESS_END(page); } } fMapCount--; } Flush(); // flush explicitely, since we directly use the lock locker.Unlock(); bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = mappings.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }
void X86VMTranslationMap64Bit::UnmapPages(VMArea* area, addr_t base, size_t size, bool updatePageQueue) { if (size == 0) return; addr_t start = base; addr_t end = base + size - 1; TRACE("X86VMTranslationMap64Bit::UnmapPages(%p, %#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", area, start, end); VMAreaMappings queue; RecursiveLocker locker(fLock); ThreadCPUPinner pinner(thread_get_current_thread()); do { uint64* pageTable = X86PagingMethod64Bit::PageTableForAddress( fPagingStructures->VirtualPML4(), start, fIsKernelMap, false, NULL, fPageMapper, fMapCount); if (pageTable == NULL) { // Move on to the next page table. start = ROUNDUP(start + 1, k64BitPageTableRange); continue; } for (uint32 index = start / B_PAGE_SIZE % k64BitTableEntryCount; index < k64BitTableEntryCount && start < end; index++, start += B_PAGE_SIZE) { uint64 oldEntry = X86PagingMethod64Bit::ClearTableEntry( &pageTable[index]); if ((oldEntry & X86_64_PTE_PRESENT) == 0) continue; fMapCount--; if ((oldEntry & X86_64_PTE_ACCESSED) != 0) { // Note, that we only need to invalidate the address, if the // accessed flags was set, since only then the entry could have // been in any TLB. InvalidatePage(start); } if (area->cache_type != CACHE_TYPE_DEVICE) { // get the page vm_page* page = vm_lookup_page( (oldEntry & X86_64_PTE_ADDRESS_MASK) / B_PAGE_SIZE); ASSERT(page != NULL); DEBUG_PAGE_ACCESS_START(page); // transfer the accessed/dirty flags to the page if ((oldEntry & X86_64_PTE_ACCESSED) != 0) page->accessed = true; if ((oldEntry & X86_64_PTE_DIRTY) != 0) page->modified = true; // remove the mapping object/decrement the wired_count of the // page if (area->wiring == B_NO_LOCK) { vm_page_mapping* mapping = NULL; vm_page_mappings::Iterator iterator = page->mappings.GetIterator(); while ((mapping = iterator.Next()) != NULL) { if (mapping->area == area) break; } ASSERT(mapping != NULL); area->mappings.Remove(mapping); page->mappings.Remove(mapping); queue.Add(mapping); } else page->DecrementWiredCount(); if (!page->IsMapped()) { atomic_add(&gMappedPagesCount, -1); if (updatePageQueue) { if (page->Cache()->temporary) vm_page_set_state(page, PAGE_STATE_INACTIVE); else if (page->modified) vm_page_set_state(page, PAGE_STATE_MODIFIED); else vm_page_set_state(page, PAGE_STATE_CACHED); } } DEBUG_PAGE_ACCESS_END(page); } } Flush(); // flush explicitly, since we directly use the lock } while (start != 0 && start < end); // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not // really critical here, as in all cases this method is used, the unmapped // area range is unmapped for good (resized/cut) and the pages will likely // be freed. locker.Unlock(); // free removed mappings bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); while (vm_page_mapping* mapping = queue.RemoveHead()) object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); }