21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/process/TerminationDeferral.h"
23#include "pedigree/kernel/process/Thread.h"
24#include "pedigree/kernel/processor/Processor.h"
28#if (HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS) || PEDIGREE_CONCURRENCY_SMOKE_TESTS
29NetworkFilter::CallbackPinHook NetworkFilter::m_CallbackPinHook =
nullptr;
33 : m_Callbacks(), m_Lock(), m_NextCallbackId(1), m_pActiveInvocations(nullptr) {}
39 if (callbackContext) {
40 FATAL(
"NetworkFilter cannot be destroyed from callback context.");
43 for (
size_t level = 1; level <= 4; ++level) {
47 m_Callbacks[level - 1].count() ? *m_Callbacks[level - 1].begin() :
nullptr;
48 const size_t id = item ? item->id : 0;
54 FATAL(
"NetworkFilter callback teardown did not complete.");
61 if (!level || level > 4) {
66 const size_t callbackBoundary = m_NextCallbackId;
78 for (
auto candidate : m_Callbacks[level - 1]) {
79 if (candidate->id <= afterId || candidate->id >= callbackBoundary) {
83 afterId = candidate->id;
84 if (!candidate->enabled) {
89 invocation.item = item;
91 invocation.next = m_pActiveInvocations;
92 m_pActiveInvocations = &invocation;
101#if (HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS) || PEDIGREE_CONCURRENCY_SMOKE_TESTS
102 CallbackPinHook hook = __atomic_load_n(&m_CallbackPinHook, __ATOMIC_ACQUIRE);
104 hook(item->callback, item->id);
107 accepted = item->callback(packet, sz);
110 auto completionGuard = item->drainWaiters.acquire();
111 bool wakeDrainers =
false;
114 while (*link && *link != &invocation) {
115 link = &((*link)->next);
118 *link = invocation.next;
120 FATAL(
"NetworkFilter lost an active callback invocation.");
123 if (!item->inFlight) {
124 FATAL(
"NetworkFilter callback pin underflow.");
127 if (!item->inFlight) {
128 wakeDrainers = item->draining;
142 if (!level || level > 4 || !callback) {
143 return static_cast<size_t>(-1);
147 item->callback = callback;
150 item->enabled =
true;
151 item->draining =
false;
154 size_t id = m_NextCallbackId++;
155 if (!
id ||
id ==
static_cast<size_t>(-1)) {
156 FATAL(
"NetworkFilter callback identifiers exhausted.");
159 m_Callbacks[level - 1].pushBack(item);
166 if (!level || level > 4 ||
id ==
static_cast<size_t>(-1)) {
172 bool deleteNow =
false;
173 bool callbackRemoval =
false;
178 it != m_Callbacks[level - 1].end(); ++it) {
179 if ((*it)->id !=
id) {
184 item->enabled =
false;
185 callbackRemoval = isCallbackInvocation(current);
186 if (callbackRemoval) {
187 if (!item->draining && !item->inFlight) {
188 m_Callbacks[level - 1].erase(it);
192 item->draining =
true;
205 }
else if (!callbackRemoval) {
206 drainCallback(level, item);
212void NetworkFilter::drainCallback(
size_t level, CallbackItem* item) {
214 bool complete =
false;
216 auto waitGuard = item->drainWaiters.acquire();
218 if (!item->inFlight) {
223 const WaitQueue::WakeReason reason =
225 reinterpret_cast<uintptr_t
>(item->callback));
234 bool deleteItem =
false;
236 if (!item->removers) {
237 FATAL(
"NetworkFilter callback remover underflow.");
240 if (!item->removers) {
242 it != m_Callbacks[level - 1].end(); ++it) {
244 m_Callbacks[level - 1].erase(it);
257bool NetworkFilter::isCallbackInvocation(
Thread* thread)
const {
258 for (ActiveInvocation* invocation = m_pActiveInvocations; invocation;
259 invocation = invocation->next) {
260 if (invocation->thread == thread) {
267#if (HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS) || PEDIGREE_CONCURRENCY_SMOKE_TESTS
268void NetworkFilter::setCallbackPinHook(CallbackPinHook hook) {
269 __atomic_store_n(&m_CallbackPinHook, hook, __ATOMIC_RELEASE);
::Iterator< T, node_t > Iterator
size_t installCallback(size_t level, bool(*callback)(uintptr_t, size_t))
bool filter(size_t level, uintptr_t packet, size_t sz)
bool removeCallback(size_t level, size_t id)
NetworkFilter()
Default constructor, boring.
virtual ~NetworkFilter()
Destructor, also boring.
static ProcessorInformation & information()
bool acquire(bool recurse=false, bool safe=true)