Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/silk/fibers/fiber.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <atomic>
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>
Expand Down Expand Up @@ -43,6 +44,11 @@ using FiberParametersDtor = void(void * parameters) noexcept;
*/
using FiberSwitchCallback = void(Fiber * fiber) noexcept;

/**
* Memory mapping callback. Called when silk maps or unmaps memory outside the C++ heap.
*/
using MemoryMapCallback = void(void * ptr, size_t size) noexcept;

/**
* Packed fiber identity: [category:8 | cpu:10 | counter:46] stored as uint64_t.
* category: byte passed to run; the runtime treats it as opaque.
Expand Down Expand Up @@ -165,6 +171,11 @@ class FiberScheduler
// across the OS thread the fiber borrows. Not invoked for proxy fibers.
FiberSwitchCallback * fiberSuspend = nullptr;
FiberSwitchCallback * fiberResume = nullptr;

// Optional hooks for silk memory maps/unmaps outside the heap: fiber stacks (guard pages
// excluded) and io_uring rings.
MemoryMapCallback * accountMemoryMapped = nullptr;
MemoryMapCallback * accountMemoryUnmapped = nullptr;
};

/**
Expand Down
31 changes: 31 additions & 0 deletions src/fibers/fiber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ Fiber::~Fiber() noexcept
{
int r = ::munmap(stack, FiberScheduler::getOptions().fiberStackSize + 2 * kPageSize);
SILK_ASSERT(!r);

if (FiberScheduler::getOptions().accountMemoryUnmapped)
{
FiberScheduler::getOptions().accountMemoryUnmapped(
static_cast<uint8_t *>(stack) + kPageSize, FiberScheduler::getOptions().fiberStackSize);
}
}
}

Expand Down Expand Up @@ -344,6 +350,11 @@ bool Fiber::initialize(

r = ::mprotect(static_cast<uint8_t *>(stack) + kPageSize + fiberStackSize, kPageSize, PROT_NONE);
SILK_ASSERT(!r);

if (FiberScheduler::getOptions().accountMemoryMapped)
{
FiberScheduler::getOptions().accountMemoryMapped(static_cast<uint8_t *>(stack) + kPageSize, fiberStackSize);
}
}

#if defined(__SANITIZE_ADDRESS__)
Expand Down Expand Up @@ -688,6 +699,23 @@ struct FiberScheduler::ProcessorState
BoundedQueue<Fiber *> readyQueue;
};

static void accountRingMemoryMappings(const io_uring & ring, MemoryMapCallback * callback) noexcept
{
if (!callback)
{
return;
}

callback(ring.sq.sqes, ring.sq.sqes_sz);
callback(ring.sq.ring_ptr, ring.sq.ring_sz);

// The kernel serves both rings from one mapping given IORING_FEAT_SINGLE_MMAP.
if (ring.cq.ring_ptr != ring.sq.ring_ptr)
{
callback(ring.cq.ring_ptr, ring.cq.ring_sz);
}
}

void FiberScheduler::ProcessorState::initialize(uint16_t cpu) noexcept
{
SILK_ASSERT(cpu < kInvalidProcessorNumber);
Expand All @@ -709,6 +737,8 @@ void FiberScheduler::ProcessorState::initialize(uint16_t cpu) noexcept
// postWakeup posts cross-ring doorbells with IOSQE_CQE_SKIP_SUCCESS to drop the send-side completion.
SILK_ASSERT(params.features & IORING_FEAT_CQE_SKIP);

accountRingMemoryMappings(ring, options.accountMemoryMapped);

// Arm the wakeup doorbell. The kernel can end the multishot poll on CQ overflow,
// so handleCompletionQueueSlow re-arms it through the same path on F_MORE loss.
enqueueDoorbell();
Expand All @@ -726,6 +756,7 @@ void FiberScheduler::ProcessorState::destroy() noexcept
{
if (eventFd >= 0)
{
accountRingMemoryMappings(ring, options.accountMemoryUnmapped);
::io_uring_queue_exit(&ring);
::close(eventFd);
}
Expand Down