mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
[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 "device_manager.h"
|
||||
#include "objects/endpoint.h"
|
||||
@@ -22,6 +23,8 @@ endpoint::close()
|
||||
{
|
||||
kobject::close();
|
||||
|
||||
util::scoped_lock lock {m_lock};
|
||||
|
||||
for (auto &data : m_blocked) {
|
||||
if (data.th)
|
||||
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.tag = tag;
|
||||
|
||||
util::scoped_lock lock {m_lock};
|
||||
|
||||
if (!check_signal(j6_signal_endpoint_can_send)) {
|
||||
assert_signal(j6_signal_endpoint_can_recv);
|
||||
m_blocked.append(sender);
|
||||
|
||||
lock.release();
|
||||
sender.th->wait_on_object(this);
|
||||
|
||||
// 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)
|
||||
timeout += clock::get().value();
|
||||
|
||||
util::scoped_lock lock {m_lock};
|
||||
|
||||
if (!check_signal(j6_signal_endpoint_can_recv)) {
|
||||
assert_signal(j6_signal_endpoint_can_send);
|
||||
m_blocked.append(receiver);
|
||||
|
||||
lock.release();
|
||||
receiver.th->wait_on_object(this, timeout);
|
||||
|
||||
// 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);
|
||||
|
||||
util::scoped_lock lock {m_lock};
|
||||
|
||||
if (!check_signal(j6_signal_endpoint_can_send)) {
|
||||
assert_signal(j6_signal_endpoint_can_recv);
|
||||
|
||||
@@ -110,6 +123,9 @@ endpoint::signal_irq(unsigned irq)
|
||||
}
|
||||
|
||||
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)
|
||||
deassert_signal(j6_signal_endpoint_can_send);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// Definition of endpoint kobject types
|
||||
|
||||
#include <j6/signals.h>
|
||||
#include <util/spinlock.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
#include "objects/kobject.h"
|
||||
@@ -72,6 +73,7 @@ private:
|
||||
|
||||
j6_status_t do_message_copy(const thread_data &sender, thread_data &receiver);
|
||||
|
||||
util::spinlock m_lock;
|
||||
util::vector<thread_data> m_blocked;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user