summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-03-20 17:09:46 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-03-20 17:09:46 +0100
commitbc1da7f1fd2e366d290db4b33f07b9806d2a6932 (patch)
tree8b72a3606893dd69113fd47fe97c47c2abdd1907
parent93aa4d581d98155e7f49880ba600bb32acd2659f (diff)
downloadserenity-bc1da7f1fd2e366d290db4b33f07b9806d2a6932.zip
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.
-rw-r--r--Kernel/NetworkAdapter.cpp6
-rw-r--r--Kernel/NetworkAdapter.h17
-rw-r--r--Kernel/NetworkTask.cpp12
-rw-r--r--Kernel/Process.cpp8
-rw-r--r--Kernel/Process.h5
-rw-r--r--Kernel/Scheduler.cpp9
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 <Kernel/IPv4.h>
#include <Kernel/ARP.h>
#include <Kernel/ICMP.h>
+#include <Kernel/Alarm.h>
+
+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<ByteBuffer> 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<HashMap<IPv4Address, MACAddress>>& 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 <AK/Weakable.h>
#include <Kernel/Lock.h>
+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<typename Callback> static void for_each(Callback);
template<typename Callback> static void for_each_in_pgrp(pid_t, Callback);
template<typename Callback> static void for_each_in_state(State, Callback);
@@ -382,6 +386,7 @@ private:
dword m_pending_signals { 0 };
dword m_signal_mask { 0 };
RetainPtr<Socket> 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 <AK/TemporaryChange.h>
+#include <Kernel/Alarm.h>
//#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;