mod.rs 3.03 KB
Newer Older
1
2
3
4
5
6
7
// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

8
9
10
11
12
use crate::arch::kernel::percore::*;
use crate::scheduler::task::TaskHandle;
use crate::synch::semaphore::*;
use crate::synch::spinlock::SpinlockIrqSave;
use alloc::collections::BTreeMap;
13
use core::sync::atomic::{AtomicBool, Ordering};
14
15
16
17

static NET_SEM: Semaphore = Semaphore::new(0);
static NIC_QUEUE: SpinlockIrqSave<BTreeMap<usize, TaskHandle>> =
	SpinlockIrqSave::new(BTreeMap::new());
18
19
static POLLING: AtomicBool = AtomicBool::new(false);

Stefan Lankes's avatar
Stefan Lankes committed
20
21
22
/// period (in usec) to check, if the driver should still use the polling mode
const POLL_PERIOD: u64 = 20_000;

23
24
25
26
27
/// set driver in polling mode and threads will not be blocked
fn set_polling_mode(value: bool) {
	// is the driver already in polling mode?
	if POLLING.swap(value, Ordering::SeqCst) != value {
		if let Some(driver) = crate::arch::kernel::pci::get_network_driver() {
28
			driver.lock().set_polling_mode(value);
29
30
31
32
33
34
		}

		// wakeup network thread to sleep for longer time
		NET_SEM.release();
	}
}
35
36
37

pub fn netwakeup() {
	NET_SEM.release();
38
}
Stefan Lankes's avatar
Stefan Lankes committed
39

40
pub fn netwait_and_wakeup(handles: &[usize], millis: Option<u64>) {
41
42
	// do we have to wakeup a thread?
	if handles.len() > 0 {
43
		let mut guard = NIC_QUEUE.lock();
44

45
46
47
		for i in handles {
			if let Some(task) = guard.remove(i) {
				core_scheduler().custom_wakeup(task);
48
49
			}
		}
50
51
	}

52
53
	let mut reset_nic = false;

Stefan Lankes's avatar
Stefan Lankes committed
54
	// check if the driver should be in the polling mode
55
56
57
58
	while POLLING.swap(false, Ordering::SeqCst) == true {
		reset_nic = true;

		let core_scheduler = core_scheduler();
Stefan Lankes's avatar
Stefan Lankes committed
59
		let wakeup_time = Some(crate::arch::processor::get_timer_ticks() + POLL_PERIOD);
60
61
62
63
64
65
66
67
68

		core_scheduler.block_current_task(wakeup_time);

		// Switch to the next task.
		core_scheduler.reschedule();
	}

	if reset_nic {
		if let Some(driver) = crate::arch::kernel::pci::get_network_driver() {
69
			driver.lock().set_polling_mode(false);
70
71
72
73
		}
	} else {
		NET_SEM.acquire(millis);
	}
74
}
75

76
pub fn netwait(handle: usize, millis: Option<u64>) {
77
78
79
80
81
82
83
84
85
86
	// smoltcp want to poll the nic
	let is_polling = if let Some(t) = millis { t == 0 } else { false };

	if is_polling {
		set_polling_mode(true);
	} else {
		let wakeup_time = match millis {
			Some(ms) => Some(crate::arch::processor::get_timer_ticks() + ms * 1000),
			_ => None,
		};
87
		let mut guard = NIC_QUEUE.lock();
88
		let core_scheduler = core_scheduler();
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
		// Block the current task and add it to the wakeup queue.
		core_scheduler.block_current_task(wakeup_time);
		guard.insert(handle, core_scheduler.get_current_task_handle());

		// release lock
		drop(guard);

		// Switch to the next task.
		core_scheduler.reschedule();

		// if the timer is expired, we have still the task in the btreemap
		// => remove it from the btreemap
		if millis.is_some() {
			let mut guard = NIC_QUEUE.lock();

			guard.remove(&handle);
		}
107
	}
108
}