Aufgrund einer Wartung wird GitLab am 18.01. zwischen 8:00 und 9:00 Uhr kurzzeitig nicht zur Verfügung stehen. / Due to maintenance, GitLab will be temporarily unavailable on 18.01. between 8:00 and 9:00 am.

mod.rs 3.19 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
use crate::arch::irq;
9
10
11
12
13
use crate::arch::kernel::percore::*;
use crate::scheduler::task::TaskHandle;
use crate::synch::semaphore::*;
use crate::synch::spinlock::SpinlockIrqSave;
use alloc::collections::BTreeMap;
14
use core::sync::atomic::{AtomicBool, Ordering};
15
16
17
18

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

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

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/// 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 {
		let irq = irq::nested_disable();

		if let Some(driver) = crate::arch::kernel::pci::get_network_driver() {
			driver.borrow_mut().set_polling_mode(value);
		}

		irq::nested_enable(irq);

		// wakeup network thread to sleep for longer time
		NET_SEM.release();
	}
}
40
41
42

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

45
pub fn netwait_and_wakeup(handles: &[usize], millis: Option<u64>) {
46
47
	// do we have to wakeup a thread?
	if handles.len() > 0 {
48
		let mut guard = NIC_QUEUE.lock();
49

50
51
52
		for i in handles {
			if let Some(task) = guard.remove(i) {
				core_scheduler().custom_wakeup(task);
53
54
			}
		}
55
56
	}

57
58
	let mut reset_nic = false;

Stefan Lankes's avatar
Stefan Lankes committed
59
	// check if the driver should be in the polling mode
60
61
62
63
	while POLLING.swap(false, Ordering::SeqCst) == true {
		reset_nic = true;

		let core_scheduler = core_scheduler();
Stefan Lankes's avatar
Stefan Lankes committed
64
		let wakeup_time = Some(crate::arch::processor::get_timer_ticks() + POLL_PERIOD);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

		core_scheduler.block_current_task(wakeup_time);

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

	if reset_nic {
		let irq = irq::nested_disable();

		if let Some(driver) = crate::arch::kernel::pci::get_network_driver() {
			driver.borrow_mut().set_polling_mode(false);
		}

		irq::nested_enable(irq);
	} else {
		NET_SEM.acquire(millis);
	}
83
}
84

85
pub fn netwait(handle: usize, millis: Option<u64>) {
86
87
88
89
90
91
92
93
94
95
	// 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,
		};
96
		let mut guard = NIC_QUEUE.lock();
97
		let core_scheduler = core_scheduler();
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
		// 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);
		}
116
	}
117
}