diff --git a/kernel/include/conc/sleep_queue.hpp b/kernel/include/conc/condition_variable.hpp similarity index 82% rename from kernel/include/conc/sleep_queue.hpp rename to kernel/include/conc/condition_variable.hpp index d7269fb6..3307fe64 100644 --- a/kernel/include/conc/sleep_queue.hpp +++ b/kernel/include/conc/condition_variable.hpp @@ -5,8 +5,8 @@ // http://www.opensource.org/licenses/MIT) //======================================================================= -#ifndef SLEEP_QUEUE_H -#define SLEEP_QUEUE_H +#ifndef CONDITION_VARIABLE_H +#define CONDITION_VARIABLE_H #include #include @@ -18,12 +18,7 @@ /*! * \brief A simple sleep queue */ -struct sleep_queue { -private: - mutable spinlock lock; - circular_buffer queue; - -public: +struct condition_variable { /*! * \brief Test if the sleep queue is empty */ @@ -58,6 +53,10 @@ public: * \return true if the thread was woken up, false if the timeout is passed */ bool sleep(size_t ms); + +private: + mutable spinlock lock; ///< The spin lock used for protecting the queue + circular_buffer queue; ///< The queue of waiting threads }; #endif diff --git a/kernel/include/conc/int_lock.hpp b/kernel/include/conc/int_lock.hpp index 0f9b8096..4a3a6272 100644 --- a/kernel/include/conc/int_lock.hpp +++ b/kernel/include/conc/int_lock.hpp @@ -12,32 +12,51 @@ #include "arch.hpp" +/*! + * \brief An interrupt lock. This lock disable preemption on acquire. + */ struct int_lock { -private: - size_t rflags; - -public: + /*! + * \brief Acquire the lock. This will disable preemption. + */ void acquire(){ arch::disable_hwint(rflags); } + /*! + * \brief Release the lock. This will enable preemption. + */ void release(){ arch::enable_hwint(rflags); } + +private: + size_t rflags; ///< The CPU flags }; +/*! + * \brief A direct interrupt lock (RAII). + * + * This is the equivalent of a std::lock_guard but does not need to + * store a lock. + */ struct direct_int_lock { -private: - int_lock lock; - -public: + /*! + * \brief Construct a new direct_int_lock and acquire the lock. + */ direct_int_lock(){ lock.acquire(); } + /*! + * \brief Destruct a direct_int_lock and release the lock. + */ ~direct_int_lock(){ lock.release(); } + +private: + int_lock lock; ///< The interrupt lock }; #endif diff --git a/kernel/include/conc/mutex.hpp b/kernel/include/conc/mutex.hpp index 8300307c..cc2b5abd 100644 --- a/kernel/include/conc/mutex.hpp +++ b/kernel/include/conc/mutex.hpp @@ -16,72 +16,66 @@ #include "scheduler.hpp" #include "logging.hpp" -template +/*! + * \brief A mutex implementation. + * + * Once the lock is acquired, the critical section is only accessible by the + * thread who acquired the mutex. + */ struct mutex { -private: - mutable spinlock lock; - volatile size_t value; - circular_buffer queue; - const char* name; - -public: + /*! + * \brief Initialize the mutex (either to 1 or 0) + * \param v The intial value of the mutex + */ void init(size_t v = 1){ - value = v; - - if(Debug){ - name = ""; + if(v > 1){ + value = 1; + } else { + value = v; } } - void set_name(const char* name){ - this->name = name; - } - + /*! + * \brief Acquire the lock + */ void acquire(){ lock.acquire(); if(value > 0){ value = 0; - if(Debug){ - logging::logf(logging::log_level::TRACE, "%s(mutex): directly acquired (process %d)\n", name, scheduler::get_pid()); - } - lock.release(); } else { auto pid = scheduler::get_pid(); queue.push(pid); - if(Debug){ - logging::logf(logging::log_level::TRACE, "%s(mutex): wait %d\n", name, pid); - } - scheduler::block_process_light(pid); lock.release(); scheduler::reschedule(); } } + /*! + * \brief Acquire the lock + */ void release(){ std::lock_guard l(lock); if(queue.empty()){ value = 1; - if(Debug){ - logging::logf(logging::log_level::TRACE, "%s(mutex): direct release (process %d)\n", name, scheduler::get_pid()); - } } else { auto pid = queue.pop(); scheduler::unblock_process(pid); - if(Debug){ - logging::logf(logging::log_level::TRACE, "%s(mutex): wake %d\n", name, pid); - } - //No need to increment value, the process won't //decrement it } } + +private: + mutable spinlock lock; ///< The spin protecting the value + volatile size_t value; ///< The value of the mutex + circular_buffer queue; ///< The sleep queue }; #endif diff --git a/kernel/include/conc/semaphore.hpp b/kernel/include/conc/semaphore.hpp index fd2cf936..aea23aac 100644 --- a/kernel/include/conc/semaphore.hpp +++ b/kernel/include/conc/semaphore.hpp @@ -14,17 +14,26 @@ #include "spinlock.hpp" #include "scheduler.hpp" +/*! + * \brief A semaphore implementation. + * + * The critical section can be open to several processes. + */ struct semaphore { -private: - mutable spinlock lock; - volatile size_t value; - circular_buffer queue; - -public: + /*! + * \brief Initialize the semaphore + * \param v The intial value of the semaphore + */ void init(size_t v){ value = v; } + /*! + * \brief Acquire the lock. + * + * This will effectively decrease the current counter by 1 once the critical + * section is entered. + */ void acquire(){ lock.acquire(); @@ -41,6 +50,12 @@ public: } } + /*! + * \brief Release the lock. + * + * This will effectively increase the current counter by 1 once the critical + * section is left. + */ void release(){ std::lock_guard l(lock); @@ -56,23 +71,34 @@ public: } } - void release(size_t v){ + /*! + * \brief Release the lock several times. + * + * This will effectively increase the current counter by n once the critical + * section is left. + */ + void release(size_t n){ std::lock_guard l(lock); if(queue.empty()){ - value += v; + value += n; } else { - while(v && !queue.empty()){ + while(n && !queue.empty()){ auto pid = queue.pop(); scheduler::unblock_process(pid); - --v; + --n; } - if(v){ - value += v; + if(n){ + value += n; } } } + +private: + mutable spinlock lock; ///< The spin lock protecting the counter + volatile size_t value; ///< The value of the counter + circular_buffer queue; ///< The sleep queue }; #endif diff --git a/kernel/include/conc/spinlock.hpp b/kernel/include/conc/spinlock.hpp index 906a0819..da7c1733 100644 --- a/kernel/include/conc/spinlock.hpp +++ b/kernel/include/conc/spinlock.hpp @@ -8,21 +8,33 @@ #ifndef SPINLOCK_H #define SPINLOCK_H +/*! + * \brief Implementation of a spinlock + * + * A spinlock simply waits in a loop until the lock is available. + */ struct spinlock { -private: - volatile size_t lock = 0; - -public: + /*! + * \brief Acquire the lock. + * + * This will wait indefinitely. + */ void acquire(){ while(!__sync_bool_compare_and_swap(&lock, 0, 1)); __sync_synchronize(); //TODO The last synchronize is probably not necessary } + /*! + * \brief Release the lock + */ void release(){ __sync_synchronize(); lock = 0; } + +private: + volatile size_t lock = 0; ///< The value of the lock }; #endif diff --git a/kernel/include/net/network.hpp b/kernel/include/net/network.hpp index a3867309..0f9aa293 100644 --- a/kernel/include/net/network.hpp +++ b/kernel/include/net/network.hpp @@ -37,7 +37,7 @@ struct interface_descriptor { network::ip::address ip_address; ///< The interface IP address network::ip::address gateway; ///< The interface IP gateway - mutable mutex<> tx_lock; //To synchronize the queue + mutable mutex tx_lock; //To synchronize the queue mutable semaphore tx_sem; mutable semaphore rx_sem; @@ -50,7 +50,7 @@ struct interface_descriptor { void (*hw_send)(interface_descriptor&, ethernet::packet& p); void send(ethernet::packet& p){ - std::lock_guard> l(tx_lock); + std::lock_guard l(tx_lock); tx_queue.push(p); tx_sem.release(); } diff --git a/kernel/include/net/socket.hpp b/kernel/include/net/socket.hpp index 2f0fd0c3..413e7a2f 100644 --- a/kernel/include/net/socket.hpp +++ b/kernel/include/net/socket.hpp @@ -15,7 +15,7 @@ #include "tlib/net_constants.hpp" -#include "conc/sleep_queue.hpp" +#include "conc/condition_variable.hpp" #include "net/ethernet_packet.hpp" @@ -41,7 +41,7 @@ struct socket { std::vector packets; circular_buffer listen_packets; - sleep_queue listen_queue; + condition_variable listen_queue; socket(){} socket(size_t id, socket_domain domain, socket_type type, socket_protocol protocol, size_t next_fd, bool listen) diff --git a/kernel/include/terminal.hpp b/kernel/include/terminal.hpp index f3543723..4f54231d 100644 --- a/kernel/include/terminal.hpp +++ b/kernel/include/terminal.hpp @@ -13,7 +13,7 @@ #include -#include "conc/sleep_queue.hpp" +#include "conc/condition_variable.hpp" namespace stdio { @@ -35,7 +35,7 @@ struct virtual_terminal { circular_buffer canonical_buffer; circular_buffer raw_buffer; - sleep_queue input_queue; + condition_variable input_queue; void print(char c); diff --git a/kernel/src/conc/sleep_queue.cpp b/kernel/src/conc/condition_variable.cpp similarity index 78% rename from kernel/src/conc/sleep_queue.cpp rename to kernel/src/conc/condition_variable.cpp index 8bc9a891..13e87610 100644 --- a/kernel/src/conc/sleep_queue.cpp +++ b/kernel/src/conc/condition_variable.cpp @@ -5,25 +5,25 @@ // http://www.opensource.org/licenses/MIT) //======================================================================= -#include "conc/sleep_queue.hpp" +#include "conc/condition_variable.hpp" #include "scheduler.hpp" #include "logging.hpp" #include "assert.hpp" -bool sleep_queue::empty() const { +bool condition_variable::empty() const { std::lock_guard l(lock); return queue.empty(); } -scheduler::pid_t sleep_queue::top_process() const { +scheduler::pid_t condition_variable::top_process() const { std::lock_guard l(lock); return queue.top(); } -scheduler::pid_t sleep_queue::wake_up() { +scheduler::pid_t condition_variable::wake_up() { std::lock_guard l(lock); while (!queue.empty()) { @@ -34,7 +34,7 @@ scheduler::pid_t sleep_queue::wake_up() { queue.pop(); if (pid != scheduler::INVALID_PID) { - logging::logf(logging::log_level::TRACE, "sleep_queue: wake %d\n", pid); + logging::logf(logging::log_level::TRACE, "condition_variable: wake %d\n", pid); // Indicate to the scheduler that this process will be able to run // We use a hint here because it is possible that the thread was @@ -48,7 +48,7 @@ scheduler::pid_t sleep_queue::wake_up() { return scheduler::INVALID_PID; } -void sleep_queue::wake_up_all() { +void condition_variable::wake_up_all() { std::lock_guard l(lock); while (!queue.empty()) { @@ -59,7 +59,7 @@ void sleep_queue::wake_up_all() { queue.pop(); if (pid != scheduler::INVALID_PID) { - logging::logf(logging::log_level::TRACE, "sleep_queue: wake(all) %d\n", pid); + logging::logf(logging::log_level::TRACE, "condition_variable: wake(all) %d\n", pid); // Indicate to the scheduler that this process will be able to run // We use a hint here because it is possible that the thread was @@ -69,18 +69,18 @@ void sleep_queue::wake_up_all() { } } -void sleep_queue::sleep() { +void condition_variable::sleep() { lock.acquire(); //Get the current process information auto pid = scheduler::get_pid(); - logging::logf(logging::log_level::TRACE, "sleep_queue: wait %d\n", pid); + logging::logf(logging::log_level::TRACE, "condition_variable: wait %d\n", pid); //Enqueue the process in the sleep queue queue.push(pid); - thor_assert(!queue.full(), "The sleep_queue queue is full!"); + thor_assert(!queue.full(), "The condition_variable queue is full!"); //This process will sleep scheduler::block_process_light(pid); @@ -90,7 +90,7 @@ void sleep_queue::sleep() { scheduler::reschedule(); } -bool sleep_queue::sleep(size_t ms) { +bool condition_variable::sleep(size_t ms) { if (!ms) { return false; } @@ -100,12 +100,12 @@ bool sleep_queue::sleep(size_t ms) { //Get the current process information auto pid = scheduler::get_pid(); - logging::logf(logging::log_level::TRACE, "sleep_queue: %u wait with timeout %u\n", pid, ms); + logging::logf(logging::log_level::TRACE, "condition_variable: %u wait with timeout %u\n", pid, ms); //Enqueue the process in the sleep queue queue.push(pid); - thor_assert(!queue.full(), "The sleep_queue queue is full!"); + thor_assert(!queue.full(), "The condition_variable queue is full!"); //This process will sleep scheduler::block_process_timeout_light(pid, ms); diff --git a/kernel/src/drivers/ata.cpp b/kernel/src/drivers/ata.cpp index 9a1648bf..f845cdf2 100644 --- a/kernel/src/drivers/ata.cpp +++ b/kernel/src/drivers/ata.cpp @@ -28,10 +28,10 @@ static constexpr const size_t BLOCK_SIZE = 512; ata::drive_descriptor* drives; -mutex<> ata_lock; +mutex ata_lock; -mutex<> primary_lock; -mutex<> secondary_lock; +mutex primary_lock; +mutex secondary_lock; block_cache cache; @@ -350,10 +350,6 @@ void ata::detect_disks(){ primary_lock.init(0); secondary_lock.init(0); - ata_lock.set_name("ata_lock"); - primary_lock.set_name("ata_primary_lock"); - secondary_lock.set_name("ata_secondary_lock"); - // Init the cache with 256 blocks cache.init(BLOCK_SIZE, 256); diff --git a/kernel/src/net/arp_layer.cpp b/kernel/src/net/arp_layer.cpp index cdb64551..57f61dbb 100644 --- a/kernel/src/net/arp_layer.cpp +++ b/kernel/src/net/arp_layer.cpp @@ -14,14 +14,14 @@ #include "net/arp_cache.hpp" #include "net/ip_layer.hpp" -#include "conc/sleep_queue.hpp" +#include "conc/condition_variable.hpp" #include "logging.hpp" #include "kernel_utils.hpp" namespace { -sleep_queue wait_queue; +condition_variable wait_queue; } //end of anonymous namespace diff --git a/kernel/src/net/tcp_layer.cpp b/kernel/src/net/tcp_layer.cpp index fe7d7d20..c78290fd 100644 --- a/kernel/src/net/tcp_layer.cpp +++ b/kernel/src/net/tcp_layer.cpp @@ -9,7 +9,7 @@ #include #include -#include "conc/sleep_queue.hpp" +#include "conc/condition_variable.hpp" #include "net/tcp_layer.hpp" #include "net/dns_layer.hpp" @@ -41,7 +41,7 @@ struct tcp_connection { size_t target_port; std::atomic listening; - sleep_queue queue; + condition_variable queue; circular_buffer packets; tcp_connection(size_t source_port, size_t target_port)