1 /* 2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef HEAP_CACHE_H 6 #define HEAP_CACHE_H 7 8 9 #include <package/hpkg/DataReader.h> 10 11 #include <condition_variable.h> 12 #include <util/DoublyLinkedList.h> 13 #include <util/OpenHashTable.h> 14 #include <vm/vm_types.h> 15 16 17 using BPackageKit::BHPKG::BAbstractBufferedDataReader; 18 using BPackageKit::BHPKG::BDataReader; 19 20 21 class BDataIO; 22 23 24 class CachedDataReader : public BAbstractBufferedDataReader { 25 public: 26 CachedDataReader(); 27 virtual ~CachedDataReader(); 28 29 status_t Init(BAbstractBufferedDataReader* reader, 30 off_t size); 31 32 virtual status_t ReadData(off_t offset, void* buffer, 33 size_t size); 34 virtual status_t ReadDataToOutput(off_t offset, size_t size, 35 BDataIO* output); 36 37 private: 38 class CacheLineLocker 39 : public DoublyLinkedListLinkImpl<CacheLineLocker> { 40 public: 41 CacheLineLocker(CachedDataReader* reader, off_t cacheLineOffset) 42 : 43 fReader(reader), 44 fOffset(cacheLineOffset) 45 { 46 fReader->_LockCacheLine(this); 47 } 48 49 ~CacheLineLocker() 50 { 51 fReader->_UnlockCacheLine(this); 52 } 53 54 off_t Offset() const 55 { 56 return fOffset; 57 } 58 59 CacheLineLocker*& HashNext() 60 { 61 return fHashNext; 62 } 63 64 DoublyLinkedList<CacheLineLocker>& Queue() 65 { 66 return fQueue; 67 } 68 69 void Wait(mutex& lock) 70 { 71 fWaitCondition.Init(this, "cached reader line locker"); 72 ConditionVariableEntry waitEntry; 73 fWaitCondition.Add(&waitEntry); 74 mutex_unlock(&lock); 75 waitEntry.Wait(); 76 mutex_lock(&lock); 77 } 78 79 void WakeUp() 80 { 81 fWaitCondition.NotifyOne(); 82 } 83 84 private: 85 CachedDataReader* fReader; 86 off_t fOffset; 87 CacheLineLocker* fHashNext; 88 DoublyLinkedList<CacheLineLocker> fQueue; 89 ConditionVariable fWaitCondition; 90 }; 91 92 friend class CacheLineLocker; 93 94 struct LockerHashDefinition { 95 typedef off_t KeyType; 96 typedef CacheLineLocker ValueType; 97 98 size_t HashKey(off_t key) const 99 { 100 return size_t(key / kCacheLineSize); 101 } 102 103 size_t Hash(const CacheLineLocker* value) const 104 { 105 return HashKey(value->Offset()); 106 } 107 108 bool Compare(off_t key, const CacheLineLocker* value) const 109 { 110 return value->Offset() == key; 111 } 112 113 CacheLineLocker*& GetLink(CacheLineLocker* value) const 114 { 115 return value->HashNext(); 116 } 117 }; 118 119 typedef BOpenHashTable<LockerHashDefinition> LockerTable; 120 121 struct PagesDataOutput; 122 123 private: 124 status_t _ReadCacheLine(off_t lineOffset, 125 size_t lineSize, off_t requestOffset, 126 size_t requestLength, BDataIO* output); 127 128 void _DiscardPages(vm_page** pages, size_t firstPage, 129 size_t pageCount); 130 void _CachePages(vm_page** pages, size_t firstPage, 131 size_t pageCount); 132 status_t _WritePages(vm_page** pages, 133 size_t pagesRelativeOffset, 134 size_t requestLength, BDataIO* output); 135 status_t _ReadIntoPages(vm_page** pages, 136 size_t firstPage, size_t pageCount); 137 138 void _LockCacheLine(CacheLineLocker* lineLocker); 139 void _UnlockCacheLine(CacheLineLocker* lineLocker); 140 141 private: 142 static const size_t kCacheLineSize = 64 * 1024; 143 static const size_t kPagesPerCacheLine 144 = kCacheLineSize / B_PAGE_SIZE; 145 146 private: 147 mutex fLock; 148 BAbstractBufferedDataReader* fReader; 149 VMCache* fCache; 150 LockerTable fCacheLineLockers; 151 }; 152 153 154 #endif // HEAP_CACHE_H 155