Skip to content

Mutex - #41

Closed
kloenk wants to merge 1 commit into
rustfrom
lock
Closed

kloenk wants to merge 1 commit into
rustfrom
lock

Conversation

@kloenk

@kloenk kloenk commented Nov 29, 2020

Copy link
Copy Markdown
Member

Create a Mutex and pr_* macros

@kloenk

ghost commented Nov 29, 2020

Copy link
Copy Markdown
Member Author

Draft for now, so I can first use it somewhere.

@kloenk

ghost commented Nov 29, 2020

Copy link
Copy Markdown
Member Author

used it in the example as example. ready from my side.

@kloenk
kloenk marked this pull request as ready for review November 29, 2020 23:15
Comment thread rust/kernel/src/lib.rs
Comment thread rust/kernel/src/sync.rs
Comment thread rust/kernel/src/sync.rs
@alex

ghost commented Nov 29, 2020

Copy link
Copy Markdown
Member

It's a 3p library, but it may make sense to consider using https://docs.rs/lock_api/0.4.2/lock_api/

Comment thread rust/kernel/src/sync.rs
@kloenk

ghost commented Nov 29, 2020

Copy link
Copy Markdown
Member Author

It's a 3p library, but it may make sense to consider using https://docs.rs/lock_api/0.4.2/lock_api/

I would like to keep the dependencies for kernel at a bare minimum. So would like to implement by my self, instead of using this crate.

Comment thread rust/kernel/src/sync.rs Outdated
@kloenk
kloenk force-pushed the lock branch 2 times, most recently from d0d1dba to e4b7ba2 Compare November 30, 2020 00:07
@kloenk kloenk changed the title Mutex and pr_* Mutex Nov 30, 2020
@kloenk

ghost commented Nov 30, 2020

Copy link
Copy Markdown
Member Author

renamed to only Mutex, as i think the example is enough to test, and so can keep the change smaller

Comment thread drivers/char/rust_example/src/lib.rs Outdated
Comment thread rust/kernel/src/sync.rs Outdated
Comment thread rust/kernel/src/sync.rs Outdated
Comment thread rust/kernel/src/sync.rs Outdated
Comment thread rust/kernel/src/sync.rs Outdated
@kloenk

ghost commented Nov 30, 2020

Copy link
Copy Markdown
Member Author

Something broke now. Should sleep now, will Fix tomorrow.

Comment thread rust/kernel/src/sync.rs Outdated
Signed-off-by: Finn Behrens <me@kloenk.de>
Comment thread rust/kernel/src/sync.rs
}

impl<T: ?Sized> Mutex<T> {
/// acquire a lock on the mutex

ghost Nov 30, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicks: uppercase on first letter, end with period ..

Comment thread rust/kernel/src/sync.rs
/// acquire a lock on the mutex
/// # unsafe
/// This is unsafe, as it returns a second lock if one is already help by the current process
// with CONFIG_DEBUG_LOCK_ALLOW mutex_lock is a macro, which calls mutex_lock_nested(&mutex, 0)

ghost Nov 30, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicks: missing /, typo help -> held, use Markdown syntax, i.e. `CONFIG_DEBUG_LOCK_ALLOW` and `mutex_lock_nested(&mutex, 0)`, end with .. Also "task" instead of "process".

Comment thread rust/kernel/src/sync.rs
Comment thread rust/kernel/src/sync.rs
impl<T: ?Sized> Mutex<T> {
/// acquire a lock on the mutex
/// # unsafe
/// This is unsafe, as it returns a second lock if one is already help by the current process

ghost Nov 30, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any kernel APIs we can use to make this safe? It'd be a shame if all mutex usage requires unsafe.

ghost Nov 30, 2020 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could test if the mutex is already locked and panic in that case (similar to what Rust's std guarantees: a deadlock or a panic but never returning), but that would pretty much be like redoing the kernel mutex debugging infrastructure, so not sure how it will be received. Even if we go that route, we should have both APIs.

ghost Dec 2, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ "panic in that case" -> "deadlock in that case" -- considering we are the kernel, it is way better to deadlock a task (with perhaps a warning or even an oops prior to the deadlock itself) than kill the entire system.


Hmm... I wonder, could we do this statically for a subset of the use cases? Say, two types, Mutex and MutexLocked which move themselves into each other on every operation (& forget themselves to avoid calling unnecessary drops which would require a test). Then we could have code like:

let m = m.lock();
...
let m = m.unlock();

Things like trylock could return an enum of either locked/unlocked, there could be a m.take(|...| { ... }), etc.

Of course, this doesn't work if one needs to keep the mutex stored in different states, but in some use cases this could be enough.

What do you think?

ghost Dec 2, 2020

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan. With mutexguard you only need a reference of the mutex. Your idea needs a owned type which can not live in a struct or similar.

ghost Dec 5, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must be missing something here. Given that mutexes are not recursive, how is it that lock() can return a second MutexGuard when the mutex is already locked (by whomever)?

ghost Dec 5, 2020

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it's unsafe, as if you call Ut 2 times from the same function, it calles 2 times mutex_unlock, which results in a kernel panic.

ghost Dec 5, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this and it just deadlocked the task, perhaps we have different debugging configurations. In any case, whether it deadlocks or panics, why does it make this unsafe?

Mutex from the std library is not unsafe and behaves similarly:

The exact behavior on locking a mutex in the thread which already holds the lock is left unspecified. However, this function will not return on the second call (it might panic or deadlock, for example).

ghost Dec 5, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does it make this unsafe?

It depends whether the panic is a controlled one or one triggered due to a double free, GPF or similar.

Mutex from the std library is not unsafe and behaves similarly:

Yeah, this is what I mentioned in my first comment above.

ghost Dec 5, 2020

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove them unsafe again, and Wirte some documentation. I can only do it after my exams. So either feel free to take my work, or wait until I have more time again.

ghost Dec 6, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about it. Good luck on your exams! :)

Comment thread rust/kernel/src/sync.rs
use crate::bindings;

pub struct Mutex<T: ?Sized> {
lock: bindings::mutex,

ghost Dec 6, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct mutex contains a struct list_head, which is a self-referential data structure. So we need to pin Mutex before we can safely initialise and use it.

Comment thread rust/kernel/src/sync.rs
#[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
pub unsafe fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
unsafe {
bindings::mutex_lock_nested(

ghost Dec 6, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to call mutex_init before you can safely use it. Where is it being called?

ghost Dec 6, 2020

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some mutexes (I think it was in the rtlink code) I don't saw it called anywhere. So I thought it works without calling mutex_unit if you set the head_list

ghost Dec 6, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some mutexes (I think it was in the rtlink code) I don't saw it called anywhere.

In such cases they were probably defined with DEFINE_MUTEX, which allows them to skip mutex_init.

So I thought it works without calling mutex_unit if you set the head_list

Where are you setting the head of the list?

In any case, check out Generic Mutex Subsystem, in particular:
A mutex must only be initialized via the API (see below).

@wedsonaf

ghost commented Dec 9, 2020

Copy link
Copy Markdown

Hi Finn,

I just saw on the rust-for-linux list archive that you are doing this to implement pr_*; I'm not responding there because I just joined the list, so I don't have the thread to reply to.

Anyway, I don't think mutex is what you need for this because it will put the task to sleep when it is locked, which means that the pr_* functions you implement won't be usable for contexts where sleeping is not an option, for example, interrupt contents. You'll likely need a spinlock -- I was working on an implementation before, I'll upload to a branch here so that you can take a look.

But if you only need to set a value once, other sync primitives may be cheaper/better. Could you give more details on what you're trying to do?

Thanks!

@kloenk

ghost commented Dec 19, 2020

Copy link
Copy Markdown
Member Author

Yes, I only want to set the value once. So I guess other sync primitives are better.

@ojeda

ghost commented Mar 12, 2021

Copy link
Copy Markdown
Member

This will be superseded by #102 more or less, but the contribution has been very welcome!

@kloenk Perhaps you want to review the other one and/or compare it with this one; e.g. the other one does not have Display, uses a different interface, etc. :-)

@kloenk

ghost commented Mar 12, 2021

Copy link
Copy Markdown
Member Author

Yes, closing this sounds like a good plan. Display I would like for easy (println) debugging :-). Hopefully I have time to implement it this weekend.

@kloenk kloenk closed this Mar 12, 2021
@ojeda
ojeda deleted the lock branch March 18, 2021 11:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants