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

View File

@ -58,11 +58,11 @@ public:
const char* objectType);
void Unpublish();
inline void NotifyOne(status_t result = B_OK);
inline void NotifyAll(status_t result = B_OK);
inline int32 NotifyOne(status_t result = B_OK);
inline int32 NotifyAll(status_t result = B_OK);
static void NotifyOne(const void* object, status_t result);
static void NotifyAll(const void* object, status_t result);
static int32 NotifyOne(const void* object, status_t result);
static int32 NotifyAll(const void* object, status_t result);
void Add(ConditionVariableEntry* entry);
int32 EntriesCount() { return atomic_get(&fEntriesCount); }
@ -79,9 +79,9 @@ public:
void Dump() const;
private:
static void _Notify(const void* object, bool all, status_t result);
void _Notify(bool all, status_t result);
void _NotifyLocked(bool all, status_t result);
static int32 _Notify(const void* object, bool all, status_t result);
int32 _Notify(bool all, status_t result);
int32 _NotifyLocked(bool all, status_t result);
protected:
typedef DoublyLinkedList<ConditionVariableEntry> EntryList;
@ -102,17 +102,17 @@ protected:
};
inline void
inline int32
ConditionVariable::NotifyOne(status_t result)
{
_Notify(false, result);
return _Notify(false, result);
}
inline void
inline int32
ConditionVariable::NotifyAll(status_t result)
{
_Notify(true, result);
return _Notify(true, result);
}

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)
{
_Notify(object, false, result);
return _Notify(object, false, result);
}
/*static*/ void
/*static*/ int32
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)
{
InterruptsLocker ints;
ReadSpinLocker hashLocker(sConditionVariableHashLock);
ConditionVariable* variable = sConditionVariableHash.Lookup(object);
if (variable == NULL)
return;
return 0;
SpinLocker variableLocker(variable->fLock);
hashLocker.Unlock();
variable->_NotifyLocked(all, result);
return variable->_NotifyLocked(all, result);
}
void
int32
ConditionVariable::_Notify(bool all, status_t result)
{
InterruptsSpinLocker _(fLock);
if (!fEntries.IsEmpty()) {
if (result > B_OK) {
panic("tried to notify with invalid result %" B_PRId32 "\n", result);
result = B_ERROR;
}
_NotifyLocked(all, result);
return _NotifyLocked(all, result);
}
return 0;
}
/*! Called with interrupts disabled and the condition variable's spinlock held.
*/
void
int32
ConditionVariable::_NotifyLocked(bool all, status_t result)
{
int32 notified = 0;
// Dequeue and wake up the blocked threads.
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
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);
}
notified++;
if (!all)
break;
}
return notified;
}