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