lib: Add epoch-based SMR
This commit is contained in:
@@ -29,6 +29,15 @@ void page_hold(struct page* page) {
|
||||
atomic_fetch_add(&page->holds, 1, ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
bool page_try_hold(struct page* page) {
|
||||
size_t holds = atomic_load(&page->holds, ATOMIC_RELAXED);
|
||||
while (holds) {
|
||||
if (atomic_compare_exchange_weak(&page->holds, &holds, holds + 1, ATOMIC_ACQUIRE, ATOMIC_RELAXED))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void page_unhold(struct page* page) {
|
||||
if (atomic_fetch_sub(&page->holds, 1, ATOMIC_RELEASE) != 1)
|
||||
return;
|
||||
|
||||
@@ -445,7 +445,7 @@ static errno_t fault_anon(
|
||||
errno_t status = anon_new(anon->page, ©);
|
||||
if (status)
|
||||
return status;
|
||||
*radix_slot(&m->amap->anons, slot) = copy;
|
||||
radix_replace(&m->amap->anons, slot, copy);
|
||||
anon_unref(anon);
|
||||
anon = copy;
|
||||
writable = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/epoch.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/utils.h>
|
||||
@@ -143,10 +144,34 @@ static errno_t fill(struct vmo* vmo, uint64_t index, enum vmo_access access, str
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct page* lookup_fast(struct vmo* vmo, uint64_t index) {
|
||||
epoch_enter();
|
||||
struct page* page = radix_lookup(&vmo->pages, index);
|
||||
if (page && !page_try_hold(page))
|
||||
page = nullptr;
|
||||
const bool valid =
|
||||
page && radix_lookup(&vmo->pages, index) == page && !(atomic_load(&page->flags, ATOMIC_ACQUIRE) & PAGE_BUSY);
|
||||
epoch_exit();
|
||||
|
||||
if (page && !valid) {
|
||||
page_unhold(page);
|
||||
return nullptr;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
errno_t vmo_get_page(struct vmo* vmo, uint64_t index, enum vmo_access access, struct page** out) {
|
||||
if (vmo->pager->lookup)
|
||||
return ENOTSUP;
|
||||
|
||||
if (access == VMO_READ) {
|
||||
struct page* page = lookup_fast(vmo, index);
|
||||
if (page) {
|
||||
*out = page;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&vmo->lock);
|
||||
while (true) {
|
||||
struct page* page = radix_lookup(&vmo->pages, index);
|
||||
|
||||
Reference in New Issue
Block a user