From bc1da7f1fd2e366d290db4b33f07b9806d2a6932 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 20 Mar 2019 17:09:46 +0100 Subject: Kernel: Snooze the NetworkTask until there are incoming packets to process. This is accomplished using a new Alarm class and a BlockedSnoozing state. Basically, you call Process::snooze_until(some_alarm) and then the scheduler won't wake up the process until some_alarm.is_ringing() returns true. --- Kernel/NetworkAdapter.cpp | 6 ++++++ Kernel/NetworkAdapter.h | 17 +++++++++++++++++ Kernel/NetworkTask.cpp | 12 ++++++------ Kernel/Process.cpp | 8 ++++++++ Kernel/Process.h | 5 +++++ Kernel/Scheduler.cpp | 9 +++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Kernel/NetworkAdapter.cpp b/Kernel/NetworkAdapter.cpp index fb09272a98..2188988b66 100644 --- a/Kernel/NetworkAdapter.cpp +++ b/Kernel/NetworkAdapter.cpp @@ -25,6 +25,7 @@ NetworkAdapter* NetworkAdapter::from_ipv4_address(const IPv4Address& address) } NetworkAdapter::NetworkAdapter() + : m_packet_queue_alarm(*this) { // FIXME: I wanna lock :( ASSERT_INTERRUPTS_DISABLED(); @@ -90,3 +91,8 @@ void NetworkAdapter::set_ipv4_address(const IPv4Address& address) { m_ipv4_address = address; } + +bool PacketQueueAlarm::is_ringing() const +{ + return m_adapter.has_queued_packets(); +} diff --git a/Kernel/NetworkAdapter.h b/Kernel/NetworkAdapter.h index 512c80dfa4..a040aaced2 100644 --- a/Kernel/NetworkAdapter.h +++ b/Kernel/NetworkAdapter.h @@ -7,6 +7,18 @@ #include #include #include +#include + +class NetworkAdapter; + +class PacketQueueAlarm final : public Alarm { +public: + PacketQueueAlarm(NetworkAdapter& adapter) : m_adapter(adapter) { } + virtual ~PacketQueueAlarm() override { } + virtual bool is_ringing() const override; +private: + NetworkAdapter& m_adapter; +}; class NetworkAdapter { public: @@ -24,6 +36,10 @@ public: ByteBuffer dequeue_packet(); + Alarm& packet_queue_alarm() { return m_packet_queue_alarm; } + + bool has_queued_packets() const { return !m_packet_queue.is_empty(); } + protected: NetworkAdapter(); void set_mac_address(const MACAddress& mac_address) { m_mac_address = mac_address; } @@ -33,5 +49,6 @@ protected: private: MACAddress m_mac_address; IPv4Address m_ipv4_address; + PacketQueueAlarm m_packet_queue_alarm; SinglyLinkedList m_packet_queue; }; diff --git a/Kernel/NetworkTask.cpp b/Kernel/NetworkTask.cpp index 200ab0a3b8..b1b20c1c4e 100644 --- a/Kernel/NetworkTask.cpp +++ b/Kernel/NetworkTask.cpp @@ -34,16 +34,16 @@ Lockable>& arp_table() void NetworkTask_main() { - auto* e1000_ptr = E1000NetworkAdapter::the(); - ASSERT(e1000_ptr); - auto& e1000 = *e1000_ptr; - e1000.set_ipv4_address(IPv4Address(192, 168, 5, 2)); + auto* adapter_ptr = E1000NetworkAdapter::the(); + ASSERT(adapter_ptr); + auto& adapter = *adapter_ptr; + adapter.set_ipv4_address(IPv4Address(192, 168, 5, 2)); kprintf("NetworkTask: Enter main loop.\n"); for (;;) { - auto packet = e1000.dequeue_packet(); + auto packet = adapter.dequeue_packet(); if (packet.is_null()) { - sleep(100); + current->snooze_until(adapter.packet_queue_alarm()); continue; } if (packet.size() < (int)(sizeof(EthernetFrameHeader))) { diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index b542606fcb..995144d2a0 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1735,6 +1735,13 @@ void Process::unblock() m_state = Process::Runnable; } +void Process::snooze_until(Alarm& alarm) +{ + m_snoozing_alarm = &alarm; + block(Process::BlockedSnoozing); + Scheduler::yield(); +} + void Process::block(Process::State new_state) { if (state() != Process::Running) { @@ -2871,6 +2878,7 @@ const char* to_string(Process::State state) case Process::BlockedConnect: return "Connect"; case Process::BlockedReceive: return "Receive"; case Process::BeingInspected: return "Inspect"; + case Process::BlockedSnoozing: return "Snoozing"; } kprintf("to_string(Process::State): Invalid state: %u\n", state); ASSERT_NOT_REACHED(); diff --git a/Kernel/Process.h b/Kernel/Process.h index 9067d45ac4..75f5a86637 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -14,6 +14,7 @@ #include #include +class Alarm; class FileDescriptor; class PageDirectory; class Region; @@ -78,6 +79,7 @@ public: BlockedSelect, BlockedConnect, BlockedReceive, + BlockedSnoozing, }; enum Priority { @@ -139,6 +141,8 @@ public: void set_wakeup_time(dword t) { m_wakeup_time = t; } dword wakeup_time() const { return m_wakeup_time; } + void snooze_until(Alarm&); + template static void for_each(Callback); template static void for_each_in_pgrp(pid_t, Callback); template static void for_each_in_state(State, Callback); @@ -382,6 +386,7 @@ private: dword m_pending_signals { 0 }; dword m_signal_mask { 0 }; RetainPtr m_blocked_socket; + Alarm* m_snoozing_alarm { nullptr }; byte m_termination_status { 0 }; byte m_termination_signal { 0 }; diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 7370144d7c..84cd0fcd04 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -4,6 +4,7 @@ #include "RTC.h" #include "i8253.h" #include +#include //#define LOG_EVERY_CONTEXT_SWITCH //#define SCHEDULER_DEBUG @@ -136,6 +137,14 @@ bool Scheduler::pick_next() return true; } + if (process.state() == Process::BlockedSnoozing) { + if (process.m_snoozing_alarm->is_ringing()) { + process.m_snoozing_alarm = nullptr; + process.unblock(); + } + return true; + } + if (process.state() == Process::Skip1SchedulerPass) { process.set_state(Process::Skip0SchedulerPasses); return true; -- cgit v1.2.3