kernel/thread: Use a rw_spinlock for the sThreadHashLock.
On a dual-core system with no other applications but the standard ones running, my standard "compile HaikuDepot with hot disk cache" benchmark shows a consistent ~5% improvement after this patch (~33.7s -> ~31.9s sys). On systems with higher core and thread counts, these numbers are probably very much larger (I'd imagine it could be up to even 10 or 15%.) Change-Id: I5df2a075bae7c71b84c6fcd33ead60df8e844757 Reviewed-on: https://review.haiku-os.org/c/861 Reviewed-by: Adrien Destugues <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
e6bb34532a
commit
568bb7eeab
@@ -73,7 +73,7 @@ typedef BKernel::TeamThreadTable<Thread> ThreadHashTable;
|
|||||||
// thread list
|
// thread list
|
||||||
static Thread sIdleThreads[SMP_MAX_CPUS];
|
static Thread sIdleThreads[SMP_MAX_CPUS];
|
||||||
static ThreadHashTable sThreadHash;
|
static ThreadHashTable sThreadHash;
|
||||||
static spinlock sThreadHashLock = B_SPINLOCK_INITIALIZER;
|
static rw_spinlock sThreadHashLock = B_RW_SPINLOCK_INITIALIZER;
|
||||||
static thread_id sNextThreadID = 2;
|
static thread_id sNextThreadID = 2;
|
||||||
// ID 1 is allocated for the kernel by Team::Team() behind our back
|
// ID 1 is allocated for the kernel by Team::Team() behind our back
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu)
|
|||||||
msg.read_sem = -1;
|
msg.read_sem = -1;
|
||||||
|
|
||||||
// add to thread table -- yet invisible
|
// add to thread table -- yet invisible
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
sThreadHash.Insert(this);
|
sThreadHash.Insert(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ Thread::~Thread()
|
|||||||
mutex_destroy(&fLock);
|
mutex_destroy(&fLock);
|
||||||
|
|
||||||
// remove from thread table
|
// remove from thread table
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
sThreadHash.Remove(this);
|
sThreadHash.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ Thread::Create(const char* name, Thread*& _thread)
|
|||||||
/*static*/ Thread*
|
/*static*/ Thread*
|
||||||
Thread::Get(thread_id id)
|
Thread::Get(thread_id id)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
Thread* thread = sThreadHash.Lookup(id);
|
Thread* thread = sThreadHash.Lookup(id);
|
||||||
if (thread != NULL)
|
if (thread != NULL)
|
||||||
thread->AcquireReference();
|
thread->AcquireReference();
|
||||||
@@ -299,7 +299,7 @@ Thread::Get(thread_id id)
|
|||||||
Thread::GetAndLock(thread_id id)
|
Thread::GetAndLock(thread_id id)
|
||||||
{
|
{
|
||||||
// look it up and acquire a reference
|
// look it up and acquire a reference
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
Thread* thread = sThreadHash.Lookup(id);
|
Thread* thread = sThreadHash.Lookup(id);
|
||||||
if (thread == NULL)
|
if (thread == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -333,7 +333,7 @@ Thread::GetDebug(thread_id id)
|
|||||||
/*static*/ bool
|
/*static*/ bool
|
||||||
Thread::IsAlive(thread_id id)
|
Thread::IsAlive(thread_id id)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
return sThreadHash.Lookup(id) != NULL;
|
return sThreadHash.Lookup(id) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ Thread::Init(bool idleThread)
|
|||||||
bool
|
bool
|
||||||
Thread::IsAlive() const
|
Thread::IsAlive() const
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
|
|
||||||
return sThreadHash.Lookup(id) != NULL;
|
return sThreadHash.Lookup(id) != NULL;
|
||||||
}
|
}
|
||||||
@@ -486,7 +486,7 @@ Thread::DeactivateCPUTimeUserTimers()
|
|||||||
ThreadListIterator::ThreadListIterator()
|
ThreadListIterator::ThreadListIterator()
|
||||||
{
|
{
|
||||||
// queue the entry
|
// queue the entry
|
||||||
InterruptsSpinLocker locker(sThreadHashLock);
|
InterruptsWriteSpinLocker locker(sThreadHashLock);
|
||||||
sThreadHash.InsertIteratorEntry(&fEntry);
|
sThreadHash.InsertIteratorEntry(&fEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ ThreadListIterator::ThreadListIterator()
|
|||||||
ThreadListIterator::~ThreadListIterator()
|
ThreadListIterator::~ThreadListIterator()
|
||||||
{
|
{
|
||||||
// remove the entry
|
// remove the entry
|
||||||
InterruptsSpinLocker locker(sThreadHashLock);
|
InterruptsWriteSpinLocker locker(sThreadHashLock);
|
||||||
sThreadHash.RemoveIteratorEntry(&fEntry);
|
sThreadHash.RemoveIteratorEntry(&fEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,7 +503,7 @@ Thread*
|
|||||||
ThreadListIterator::Next()
|
ThreadListIterator::Next()
|
||||||
{
|
{
|
||||||
// get the next team -- if there is one, get reference for it
|
// get the next team -- if there is one, get reference for it
|
||||||
InterruptsSpinLocker locker(sThreadHashLock);
|
InterruptsWriteSpinLocker locker(sThreadHashLock);
|
||||||
Thread* thread = sThreadHash.NextElement(&fEntry);
|
Thread* thread = sThreadHash.NextElement(&fEntry);
|
||||||
if (thread != NULL)
|
if (thread != NULL)
|
||||||
thread->AcquireReference();
|
thread->AcquireReference();
|
||||||
@@ -1016,7 +1016,7 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel)
|
|||||||
ThreadLocker threadLocker(thread);
|
ThreadLocker threadLocker(thread);
|
||||||
|
|
||||||
InterruptsSpinLocker threadCreationLocker(gThreadCreationLock);
|
InterruptsSpinLocker threadCreationLocker(gThreadCreationLock);
|
||||||
SpinLocker threadHashLocker(sThreadHashLock);
|
WriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
|
|
||||||
// check the thread limit
|
// check the thread limit
|
||||||
if (sUsedThreads >= sMaxThreads) {
|
if (sUsedThreads >= sMaxThreads) {
|
||||||
@@ -2164,7 +2164,7 @@ thread_exit(void)
|
|||||||
SpinLocker threadCreationLocker(gThreadCreationLock);
|
SpinLocker threadCreationLocker(gThreadCreationLock);
|
||||||
|
|
||||||
// mark invisible in global hash/list, so it's no longer accessible
|
// mark invisible in global hash/list, so it's no longer accessible
|
||||||
SpinLocker threadHashLocker(sThreadHashLock);
|
WriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
thread->visible = false;
|
thread->visible = false;
|
||||||
sUsedThreads--;
|
sUsedThreads--;
|
||||||
threadHashLocker.Unlock();
|
threadHashLocker.Unlock();
|
||||||
@@ -2375,7 +2375,7 @@ thread_reset_for_exec(void)
|
|||||||
thread_id
|
thread_id
|
||||||
allocate_thread_id()
|
allocate_thread_id()
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
|
|
||||||
// find the next unused ID
|
// find the next unused ID
|
||||||
thread_id id;
|
thread_id id;
|
||||||
@@ -2396,7 +2396,7 @@ allocate_thread_id()
|
|||||||
thread_id
|
thread_id
|
||||||
peek_next_thread_id()
|
peek_next_thread_id()
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
return sNextThreadID;
|
return sNextThreadID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2423,7 +2423,7 @@ thread_yield(void)
|
|||||||
void
|
void
|
||||||
thread_map(void (*function)(Thread* thread, void* data), void* data)
|
thread_map(void (*function)(Thread* thread, void* data), void* data)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
|
|
||||||
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
|
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
|
||||||
Thread* thread = it.Next();) {
|
Thread* thread = it.Next();) {
|
||||||
@@ -2609,7 +2609,7 @@ thread_max_threads(void)
|
|||||||
int32
|
int32
|
||||||
thread_used_threads(void)
|
thread_used_threads(void)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
return sUsedThreads;
|
return sUsedThreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3153,10 +3153,11 @@ find_thread(const char* name)
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return thread_get_current_thread_id();
|
return thread_get_current_thread_id();
|
||||||
|
|
||||||
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
|
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
|
||||||
|
|
||||||
// TODO: Scanning the whole hash with the thread hash lock held isn't
|
// Scanning the whole hash with the thread hash lock held isn't exactly
|
||||||
// exactly cheap -- although this function is probably used very rarely.
|
// cheap, but since this function is probably used very rarely, and we
|
||||||
|
// only need a read lock, it's probably acceptable.
|
||||||
|
|
||||||
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
|
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
|
||||||
Thread* thread = it.Next();) {
|
Thread* thread = it.Next();) {
|
||||||
|
|||||||
Reference in New Issue
Block a user