[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <3160105.1740674652@warthog.procyon.org.uk>
Date: Thu, 27 Feb 2025 16:44:12 +0000
From: David Howells <dhowells@...hat.com>
To: "H. Peter Anvin" <hpa@...or.com>
Cc: dhowells@...hat.com, linux-kernel@...r.kernel.org, pinskia@...il.com,
Neal Gompa <neal@...pa.dev>
Subject: Convert the kernel to C++: Lock-holding class
Hi Peter,
I played with the code a bit and implemented a generic template class to hold
a lock:
template<typename LOCK>
struct Lock {
LOCK &m;
bool is_locked;
Lock(LOCK &mutex) : m(mutex) {
m.lock();
is_locked = true;
}
~Lock() {
if (is_locked)
m.unlock();
}
void drop() {
if (is_locked)
m.unlock();
is_locked = false;
}
void reget() {
m.lock();
is_locked = true;
}
operator bool() {
return is_locked;
}
};
used something like with the Mutex, Semaphore and Inode classes below:
int bar(Inode *inode, int x)
{
Lock m_lock = inode->m;
for (int i = 0; i < 10; i++) {
Lock m_sem(inode->s);
do_something(inode);
m_lock.drop();
do_something_else(inode);
m_lock.reget();
}
}
It seems that the storage for objects of this lock-holding class entirely
optimise away under reasonable conditions. The compiler can keep track of
both the lock pointer/ref *and* the is_locked member without having to
actually store them - even when exception handling is thrown into the mix.
A further thing I've noticed is that zero-size classes can be passed in the
argument list without the consumption of register/stack space. I wonder if it
might be possible to use an argument to indicate the possession of a lock?
E.g.:
class Have_lock {};
class Pass_lock {};
template<typename LOCK>
struct Lock {
...
operator Have_lock() {
__builtin_compile_time_assert(is_locked);
BUG_ON(!is_locked);
return Have_lock();
}
operator Pass_lock() {
__builtin_compile_time_assert(is_locked);
BUG_ON(!is_locked);
is_locked = false;
return Have_lock();
}
};
int do_something(Inode *i, Have_lock l);
int do_something_and_unlock(Inode *i, Pass_lock l);
David
---
Silly, non-functional implementation of a mutex and a semaphore class so that
I could see it trivially in the .o file:
struct Mutex {
int counter;
void lock() {
__atomic_fetch_sub(&counter, 1, __ATOMIC_RELEASE);
}
void unlock() {
__atomic_fetch_add(&counter, 1, __ATOMIC_ACQUIRE);
}
};
struct Semaphore {
int counter;
void lock() {
__atomic_fetch_sub(&counter, 1, __ATOMIC_RELEASE);
}
void unlock() {
__atomic_fetch_add(&counter, 1, __ATOMIC_ACQUIRE);
}
};
struct Inode {
int ref;
Mutex m;
Semaphore s;
};
Powered by blists - more mailing lists