2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
5 #ifndef UNUSED_VNODES_H
6 #define UNUSED_VNODES_H
11 #include <util/AutoLock.h>
12 #include <util/list.h>
14 #include <low_resource_manager.h>
19 const static uint32 kMaxUnusedVnodes
= 8192;
20 // This is the maximum number of unused vnodes that the system
21 // will keep around (weak limit, if there is enough memory left,
22 // they won't get flushed even when hitting that limit).
23 // It may be chosen with respect to the available memory or enhanced
24 // by some timestamp/frequency heurism.
27 /*! \brief Guards sUnusedVnodeList and sUnusedVnodes.
29 Innermost lock. Must not be held when acquiring any other lock.
31 static mutex sUnusedVnodesLock
= MUTEX_INITIALIZER("unused vnodes");
32 static list sUnusedVnodeList
;
33 static uint32 sUnusedVnodes
= 0;
35 static const int32 kMaxHotVnodes
= 1024;
36 static rw_lock sHotVnodesLock
= RW_LOCK_INITIALIZER("hot vnodes");
37 static Vnode
* sHotVnodes
[kMaxHotVnodes
];
38 static int32 sNextHotVnodeIndex
= 0;
40 static const int32 kUnusedVnodesCheckInterval
= 64;
41 static int32 sUnusedVnodesCheckCount
= 0;
44 /*! Must be called with sHotVnodesLock write-locked.
47 flush_hot_vnodes_locked()
49 MutexLocker
unusedLocker(sUnusedVnodesLock
);
51 int32 count
= std::min(sNextHotVnodeIndex
, kMaxHotVnodes
);
52 for (int32 i
= 0; i
< count
; i
++) {
53 Vnode
* vnode
= sHotVnodes
[i
];
58 if (vnode
->IsUnused()) {
59 list_add_item(&sUnusedVnodeList
, vnode
);
68 unusedLocker
.Unlock();
70 sNextHotVnodeIndex
= 0;
75 /*! To be called when the vnode's ref count drops to 0.
76 Must be called with sVnodeLock at least read-locked and the vnode locked.
77 \param vnode The vnode.
78 \return \c true, if the caller should trigger unused vnode freeing.
81 vnode_unused(Vnode
* vnode
)
83 ReadLocker
hotReadLocker(sHotVnodesLock
);
85 vnode
->SetUnused(true);
88 int32 checkCount
= atomic_add(&sUnusedVnodesCheckCount
, 1);
89 if (checkCount
== kUnusedVnodesCheckInterval
) {
90 uint32 unusedCount
= atomic_get((int32
*)&sUnusedVnodes
);
91 if (unusedCount
> kMaxUnusedVnodes
92 && low_resource_state(
93 B_KERNEL_RESOURCE_PAGES
| B_KERNEL_RESOURCE_MEMORY
)
94 != B_NO_LOW_RESOURCE
) {
95 // there are too many unused vnodes -- tell the caller to free the
99 // nothing urgent -- reset the counter and re-check then
100 atomic_set(&sUnusedVnodesCheckCount
, 0);
104 // nothing to do, if the node is already hot
109 int32 index
= atomic_add(&sNextHotVnodeIndex
, 1);
110 if (index
< kMaxHotVnodes
) {
112 sHotVnodes
[index
] = vnode
;
116 // the array is full -- it has to be emptied
117 hotReadLocker
.Unlock();
118 WriteLocker
hotWriteLocker(sHotVnodesLock
);
120 // unless someone was faster than we were, we have to flush the array
121 if (sNextHotVnodeIndex
>= kMaxHotVnodes
)
122 flush_hot_vnodes_locked();
125 index
= sNextHotVnodeIndex
++;
127 sHotVnodes
[index
] = vnode
;
133 /*! To be called when the vnode's ref count is changed from 0 to 1.
134 Must be called with sVnodeLock at least read-locked and the vnode locked.
135 \param vnode The vnode.
138 vnode_used(Vnode
* vnode
)
140 ReadLocker
hotReadLocker(sHotVnodesLock
);
142 if (!vnode
->IsUnused())
145 vnode
->SetUnused(false);
147 if (!vnode
->IsHot()) {
148 MutexLocker
unusedLocker(sUnusedVnodesLock
);
149 list_remove_item(&sUnusedVnodeList
, vnode
);
155 /*! To be called when the vnode's is about to be freed.
156 Must be called with sVnodeLock at least read-locked and the vnode locked.
157 \param vnode The vnode.
160 vnode_to_be_freed(Vnode
* vnode
)
162 ReadLocker
hotReadLocker(sHotVnodesLock
);
164 if (vnode
->IsHot()) {
165 // node is hot -- remove it from the array
166 // TODO: Maybe better completely flush the array while at it?
167 int32 count
= atomic_get(&sNextHotVnodeIndex
);
168 count
= std::min(count
, kMaxHotVnodes
);
169 for (int32 i
= 0; i
< count
; i
++) {
170 if (sHotVnodes
[i
] == vnode
) {
171 sHotVnodes
[i
] = NULL
;
175 } else if (vnode
->IsUnused()) {
176 MutexLocker
unusedLocker(sUnusedVnodesLock
);
177 list_remove_item(&sUnusedVnodeList
, vnode
);
181 vnode
->SetUnused(false);
188 WriteLocker
hotWriteLocker(sHotVnodesLock
);
189 flush_hot_vnodes_locked();
194 unused_vnodes_check_started()
196 atomic_set(&sUnusedVnodesCheckCount
, kUnusedVnodesCheckInterval
+ 1);
201 unused_vnodes_check_done()
203 atomic_set(&sUnusedVnodesCheckCount
, 0);
207 #endif // UNUSED_VNODES_H