kernel/condition_variable: Return the count of unblocked threads from Notify.

No reason not to, and it's needed in user_mutex to avoid a very rare
potential race, anyway.
This commit is contained in:
Augustin Cavalier
2023-07-25 15:27:40 -04:00
parent 2cc89328fa
commit aca21731ff
2 changed files with 27 additions and 22 deletions
+11 -11
View File
@@ -58,11 +58,11 @@ public:
const char* objectType); const char* objectType);
void Unpublish(); void Unpublish();
inline void NotifyOne(status_t result = B_OK); inline int32 NotifyOne(status_t result = B_OK);
inline void NotifyAll(status_t result = B_OK); inline int32 NotifyAll(status_t result = B_OK);
static void NotifyOne(const void* object, status_t result); static int32 NotifyOne(const void* object, status_t result);
static void NotifyAll(const void* object, status_t result); static int32 NotifyAll(const void* object, status_t result);
void Add(ConditionVariableEntry* entry); void Add(ConditionVariableEntry* entry);
int32 EntriesCount() { return atomic_get(&fEntriesCount); } int32 EntriesCount() { return atomic_get(&fEntriesCount); }
@@ -79,9 +79,9 @@ public:
void Dump() const; void Dump() const;
private: private:
static void _Notify(const void* object, bool all, status_t result); static int32 _Notify(const void* object, bool all, status_t result);
void _Notify(bool all, status_t result); int32 _Notify(bool all, status_t result);
void _NotifyLocked(bool all, status_t result); int32 _NotifyLocked(bool all, status_t result);
protected: protected:
typedef DoublyLinkedList<ConditionVariableEntry> EntryList; typedef DoublyLinkedList<ConditionVariableEntry> EntryList;
@@ -102,17 +102,17 @@ protected:
}; };
inline void inline int32
ConditionVariable::NotifyOne(status_t result) ConditionVariable::NotifyOne(status_t result)
{ {
_Notify(false, result); return _Notify(false, result);
} }
inline void inline int32
ConditionVariable::NotifyAll(status_t result) ConditionVariable::NotifyAll(status_t result)
{ {
_Notify(true, result); return _Notify(true, result);
} }
+16 -11
View File
@@ -324,56 +324,58 @@ ConditionVariable::Wait(recursive_lock* lock, uint32 flags, bigtime_t timeout)
} }
/*static*/ void /*static*/ int32
ConditionVariable::NotifyOne(const void* object, status_t result) ConditionVariable::NotifyOne(const void* object, status_t result)
{ {
_Notify(object, false, result); return _Notify(object, false, result);
} }
/*static*/ void /*static*/ int32
ConditionVariable::NotifyAll(const void* object, status_t result) ConditionVariable::NotifyAll(const void* object, status_t result)
{ {
_Notify(object, true, result); return _Notify(object, true, result);
} }
/*static*/ void /*static*/ int32
ConditionVariable::_Notify(const void* object, bool all, status_t result) ConditionVariable::_Notify(const void* object, bool all, status_t result)
{ {
InterruptsLocker ints; InterruptsLocker ints;
ReadSpinLocker hashLocker(sConditionVariableHashLock); ReadSpinLocker hashLocker(sConditionVariableHashLock);
ConditionVariable* variable = sConditionVariableHash.Lookup(object); ConditionVariable* variable = sConditionVariableHash.Lookup(object);
if (variable == NULL) if (variable == NULL)
return; return 0;
SpinLocker variableLocker(variable->fLock); SpinLocker variableLocker(variable->fLock);
hashLocker.Unlock(); hashLocker.Unlock();
variable->_NotifyLocked(all, result); return variable->_NotifyLocked(all, result);
} }
void int32
ConditionVariable::_Notify(bool all, status_t result) ConditionVariable::_Notify(bool all, status_t result)
{ {
InterruptsSpinLocker _(fLock); InterruptsSpinLocker _(fLock);
if (!fEntries.IsEmpty()) { if (!fEntries.IsEmpty()) {
if (result > B_OK) { if (result > B_OK) {
panic("tried to notify with invalid result %" B_PRId32 "\n", result); panic("tried to notify with invalid result %" B_PRId32 "\n", result);
result = B_ERROR; result = B_ERROR;
} }
_NotifyLocked(all, result); return _NotifyLocked(all, result);
} }
return 0;
} }
/*! Called with interrupts disabled and the condition variable's spinlock held. /*! Called with interrupts disabled and the condition variable's spinlock held.
*/ */
void int32
ConditionVariable::_NotifyLocked(bool all, status_t result) ConditionVariable::_NotifyLocked(bool all, status_t result)
{ {
int32 notified = 0;
// Dequeue and wake up the blocked threads. // Dequeue and wake up the blocked threads.
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) { while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
Thread* thread = atomic_pointer_get_and_set(&entry->fThread, (Thread*)NULL); Thread* thread = atomic_pointer_get_and_set(&entry->fThread, (Thread*)NULL);
@@ -417,9 +419,12 @@ ConditionVariable::_NotifyLocked(bool all, status_t result)
thread_unblock_locked(thread, result); thread_unblock_locked(thread, result);
} }
notified++;
if (!all) if (!all)
break; break;
} }
return notified;
} }