[kernel] Add locking to endpoint
Endpoints could previously crash if two senders were concurrently writing to them, so this change adds a spinlock and protects functions that touch the signals and blocked list.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
#include "assert.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "device_manager.h"
|
#include "device_manager.h"
|
||||||
#include "objects/endpoint.h"
|
#include "objects/endpoint.h"
|
||||||
@@ -22,6 +23,8 @@ endpoint::close()
|
|||||||
{
|
{
|
||||||
kobject::close();
|
kobject::close();
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
for (auto &data : m_blocked) {
|
for (auto &data : m_blocked) {
|
||||||
if (data.th)
|
if (data.th)
|
||||||
data.th->wake_on_result(this, j6_status_closed);
|
data.th->wake_on_result(this, j6_status_closed);
|
||||||
@@ -37,9 +40,13 @@ endpoint::send(j6_tag_t tag, const void *data, size_t data_len)
|
|||||||
sender.len = data_len;
|
sender.len = data_len;
|
||||||
sender.tag = tag;
|
sender.tag = tag;
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
if (!check_signal(j6_signal_endpoint_can_send)) {
|
if (!check_signal(j6_signal_endpoint_can_send)) {
|
||||||
assert_signal(j6_signal_endpoint_can_recv);
|
assert_signal(j6_signal_endpoint_can_recv);
|
||||||
m_blocked.append(sender);
|
m_blocked.append(sender);
|
||||||
|
|
||||||
|
lock.release();
|
||||||
sender.th->wait_on_object(this);
|
sender.th->wait_on_object(this);
|
||||||
|
|
||||||
// we woke up having already finished the send
|
// we woke up having already finished the send
|
||||||
@@ -68,9 +75,13 @@ endpoint::receive(j6_tag_t *tag, void *data, size_t *data_len, uint64_t timeout)
|
|||||||
if (timeout)
|
if (timeout)
|
||||||
timeout += clock::get().value();
|
timeout += clock::get().value();
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
if (!check_signal(j6_signal_endpoint_can_recv)) {
|
if (!check_signal(j6_signal_endpoint_can_recv)) {
|
||||||
assert_signal(j6_signal_endpoint_can_send);
|
assert_signal(j6_signal_endpoint_can_send);
|
||||||
m_blocked.append(receiver);
|
m_blocked.append(receiver);
|
||||||
|
|
||||||
|
lock.release();
|
||||||
receiver.th->wait_on_object(this, timeout);
|
receiver.th->wait_on_object(this, timeout);
|
||||||
|
|
||||||
// we woke up having already finished the recv
|
// we woke up having already finished the recv
|
||||||
@@ -96,6 +107,8 @@ endpoint::signal_irq(unsigned irq)
|
|||||||
{
|
{
|
||||||
j6_tag_t tag = j6_tag_from_irq(irq);
|
j6_tag_t tag = j6_tag_from_irq(irq);
|
||||||
|
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
if (!check_signal(j6_signal_endpoint_can_send)) {
|
if (!check_signal(j6_signal_endpoint_can_send)) {
|
||||||
assert_signal(j6_signal_endpoint_can_recv);
|
assert_signal(j6_signal_endpoint_can_recv);
|
||||||
|
|
||||||
@@ -110,6 +123,9 @@ endpoint::signal_irq(unsigned irq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_data receiver = m_blocked.pop_front();
|
thread_data receiver = m_blocked.pop_front();
|
||||||
|
kassert(receiver.len_p && receiver.tag_p,
|
||||||
|
"endpoint had can_send but m_blocked was empty");
|
||||||
|
|
||||||
if (m_blocked.count() == 0)
|
if (m_blocked.count() == 0)
|
||||||
deassert_signal(j6_signal_endpoint_can_send);
|
deassert_signal(j6_signal_endpoint_can_send);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/// Definition of endpoint kobject types
|
/// Definition of endpoint kobject types
|
||||||
|
|
||||||
#include <j6/signals.h>
|
#include <j6/signals.h>
|
||||||
|
#include <util/spinlock.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
@@ -72,6 +73,7 @@ private:
|
|||||||
|
|
||||||
j6_status_t do_message_copy(const thread_data &sender, thread_data &receiver);
|
j6_status_t do_message_copy(const thread_data &sender, thread_data &receiver);
|
||||||
|
|
||||||
|
util::spinlock m_lock;
|
||||||
util::vector<thread_data> m_blocked;
|
util::vector<thread_data> m_blocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user