Skip to content

Commit b36933a

Browse files
Update mutex and condition-variable interface (#3158)
* Adhering to new mutex api * casting assert arg as expected * Using correct mutex call * Formatting * Fixing interface for wait/pend * Fixing conditionvariable to adhere to new interface * Updated Os::Stub's implementation of ConditionVariable per new interface * Formatting and updating Test's ConditionVariable implementation to the new API * bugfix to ut * Fixes per PR review.
1 parent 706fadf commit b36933a

14 files changed

+129
-83
lines changed

Os/Condition.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ ConditionVariable::~ConditionVariable() {
88
m_delegate.~ConditionVariableInterface();
99
}
1010

11-
void ConditionVariable::wait(Os::Mutex& mutex) {
11+
ConditionVariable::Status ConditionVariable::pend(Os::Mutex& mutex) {
1212
FW_ASSERT(&this->m_delegate == reinterpret_cast<ConditionVariableInterface*>(&this->m_handle_storage[0]));
13-
FW_ASSERT(this->m_lock == nullptr || this->m_lock == &mutex); // Confirm the same mutex used across waits
13+
if (this->m_lock != nullptr && this->m_lock != &mutex) {
14+
return Status::ERROR_DIFFERENT_MUTEX;
15+
};
1416
this->m_lock = &mutex;
15-
// Attempt to lock the mutex and ensure that this was successful or the lock was already held
16-
Mutex::Status lock_status = this->m_lock->take();
17-
FW_ASSERT(lock_status == Mutex::Status::OP_OK || lock_status == Mutex::Status::ERROR_DEADLOCK);
18-
this->m_delegate.wait(mutex);
17+
return this->m_delegate.pend(mutex);
18+
}
19+
void ConditionVariable::wait(Os::Mutex& mutex) {
20+
Status status = this->pend(mutex);
21+
FW_ASSERT(status == Status::OP_OK, static_cast<FwAssertArgType>(status));
1922
}
2023
void ConditionVariable::notify() {
2124
FW_ASSERT(&this->m_delegate == reinterpret_cast<ConditionVariableInterface*>(&this->m_handle_storage[0]));
@@ -26,9 +29,9 @@ void ConditionVariable::notifyAll() {
2629
this->m_delegate.notifyAll();
2730
}
2831

29-
ConditionVariableHandle* ConditionVariable::getHandle(){
32+
ConditionVariableHandle* ConditionVariable::getHandle() {
3033
FW_ASSERT(&this->m_delegate == reinterpret_cast<const ConditionVariableInterface*>(&this->m_handle_storage[0]));
3134
return this->m_delegate.getHandle();
3235
}
3336

34-
}
37+
} // namespace Os

Os/Condition.hpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ class ConditionVariableHandle {};
1919
//! reacquiring the mutex once the condition has been notified.
2020
class ConditionVariableInterface {
2121
public:
22+
enum Status {
23+
OP_OK, //!< Operation was successful
24+
ERROR_MUTEX_NOT_HELD, //!< When trying to wait but we don't hold the mutex
25+
ERROR_DIFFERENT_MUTEX, //!< When trying to use a different mutex than expected mutex
26+
ERROR_NOT_IMPLEMENTED, //!< When trying to use a feature that isn't implemented
27+
ERROR_OTHER //!< All other errors
28+
};
29+
2230
//! Default constructor
2331
ConditionVariableInterface() = default;
2432
//! Default destructor
@@ -37,7 +45,8 @@ class ConditionVariableInterface {
3745
//! thread of execution.
3846
//!
3947
//! \param mutex: mutex to unlock as part of this operation
40-
virtual void wait(Os::Mutex& mutex) = 0;
48+
//! \return status of the conditional wait
49+
virtual Status pend(Os::Mutex& mutex) = 0;
4150

4251
//! \brief notify a single waiter on this condition variable
4352
//!
@@ -88,10 +97,24 @@ class ConditionVariable final : public ConditionVariableInterface {
8897
//!
8998
//! \warning it is invalid to supply a mutex different from those supplied by others
9099
//! \warning conditions *must* be rechecked after the condition variable unlocks
91-
//! \note unlocked mutexes will be locked before waiting and will be relocked before this function returns
100+
//! \warning the mutex must be locked by the calling task
101+
//!
102+
//! \param mutex: mutex to unlock as part of this operation
103+
//! \return status of the conditional wait
104+
Status pend(Os::Mutex& mutex) override;
105+
106+
//! \brief wait on a condition variable
107+
//!
108+
//! Wait on a condition variable. This function will atomically unlock the provided mutex and block on the condition
109+
//! in one step. Blocking will occur until a future `notify` or `notifyAll` call is made to this variable on another
110+
//! thread of execution. This function delegates to the underlying implementation.
111+
//!
112+
//! \warning it is invalid to supply a mutex different from those supplied by others
113+
//! \warning conditions *must* be rechecked after the condition variable unlocks
114+
//! \warning the mutex must be locked by the calling task
92115
//!
93116
//! \param mutex: mutex to unlock as part of this operation
94-
void wait(Os::Mutex& mutex) override;
117+
void wait(Os::Mutex& mutex);
95118

96119
//! \brief notify a single waiter on this condition variable
97120
//!
@@ -118,8 +141,9 @@ class ConditionVariable final : public ConditionVariableInterface {
118141
// This section is used to store the implementation-defined file handle. To Os::File and fprime, this type is
119142
// opaque and thus normal allocation cannot be done. Instead, we allow the implementor to store then handle in
120143
// the byte-array here and set `handle` to that address for storage.
121-
alignas(FW_HANDLE_ALIGNMENT) ConditionVariableHandleStorage m_handle_storage; //!< Storage for aligned FileHandle data
122-
ConditionVariableInterface& m_delegate; //!< Delegate for the real implementation
144+
alignas(FW_HANDLE_ALIGNMENT)
145+
ConditionVariableHandleStorage m_handle_storage; //!< Storage for aligned FileHandle data
146+
ConditionVariableInterface& m_delegate; //!< Delegate for the real implementation
123147
};
124-
}
125-
#endif //OS_CONDITION_HPP_
148+
} // namespace Os
149+
#endif // OS_CONDITION_HPP_

Os/Mutex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ ScopeLock::ScopeLock(Mutex& mutex) : m_mutex(mutex) {
4848
}
4949

5050
ScopeLock::~ScopeLock() {
51-
this->m_mutex.release();
51+
this->m_mutex.unLock();
5252
}
5353

5454
} // namespace Os

Os/Posix/ConditionVariable.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
// \brief Posix implementations for Os::ConditionVariable
44
// ======================================================================
55
#include "Os/Posix/ConditionVariable.hpp"
6-
#include "Os/Posix/Mutex.hpp"
76
#include "Fw/Types/Assert.hpp"
7+
#include "Os/Posix/Mutex.hpp"
8+
#include "Os/Posix/error.hpp"
89

910
namespace Os {
1011
namespace Posix {
@@ -18,9 +19,10 @@ PosixConditionVariable::~PosixConditionVariable() {
1819
(void)pthread_cond_destroy(&this->m_handle.m_condition);
1920
}
2021

21-
void PosixConditionVariable::wait(Os::Mutex& mutex) {
22+
PosixConditionVariable::Status PosixConditionVariable::pend(Os::Mutex& mutex) {
2223
PosixMutexHandle* mutex_handle = reinterpret_cast<PosixMutexHandle*>(mutex.getHandle());
23-
FW_ASSERT(pthread_cond_wait(&this->m_handle.m_condition, &mutex_handle->m_mutex_descriptor) == 0);
24+
PlatformIntType status = pthread_cond_wait(&this->m_handle.m_condition, &mutex_handle->m_mutex_descriptor);
25+
return posix_status_to_conditional_status(status);
2426
}
2527
void PosixConditionVariable::notify() {
2628
FW_ASSERT(pthread_cond_signal(&this->m_handle.m_condition) == 0);
@@ -33,6 +35,6 @@ ConditionVariableHandle* PosixConditionVariable::getHandle() {
3335
return &m_handle;
3436
}
3537

36-
}
37-
}
38-
}
38+
} // namespace Mutex
39+
} // namespace Posix
40+
} // namespace Os

Os/Posix/ConditionVariable.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class PosixConditionVariable : public ConditionVariableInterface {
3232
ConditionVariableInterface& operator=(const ConditionVariableInterface& other) override = delete;
3333

3434
//! \brief wait releasing mutex
35-
void wait(Os::Mutex& mutex) override;
35+
PosixConditionVariable::Status pend(Os::Mutex& mutex) override;
3636

3737
//! \brief notify a single waiter
3838
void notify() override;

Os/Posix/DefaultMutex.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,24 @@
22
// \title Os/Posix/DefaultMutex.cpp
33
// \brief sets default Os::Mutex Posix implementation via linker
44
// ======================================================================
5-
#include "Os/Posix/Mutex.hpp"
6-
#include "Os/Posix/ConditionVariable.hpp"
75
#include "Os/Delegate.hpp"
6+
#include "Os/Posix/ConditionVariable.hpp"
7+
#include "Os/Posix/Mutex.hpp"
88
namespace Os {
99

1010
//! \brief get a delegate for MutexInterface that intercepts calls for Posix
1111
//! \param aligned_new_memory: aligned memory to fill
1212
//! \return: pointer to delegate
13-
MutexInterface *MutexInterface::getDelegate(MutexHandleStorage& aligned_new_memory) {
14-
return Os::Delegate::makeDelegate<MutexInterface, Os::Posix::Mutex::PosixMutex>(
15-
aligned_new_memory
16-
);
13+
MutexInterface* MutexInterface::getDelegate(MutexHandleStorage& aligned_new_memory) {
14+
return Os::Delegate::makeDelegate<MutexInterface, Os::Posix::Mutex::PosixMutex>(aligned_new_memory);
1715
}
1816

1917
//! \brief get a delegate for MutexInterface that intercepts calls for Posix
2018
//! \param aligned_new_memory: aligned memory to fill
2119
//! \return: pointer to delegate
22-
ConditionVariableInterface *ConditionVariableInterface::getDelegate(ConditionVariableHandleStorage& aligned_new_memory) {
23-
return Os::Delegate::makeDelegate<ConditionVariableInterface, Os::Posix::Mutex::PosixConditionVariable, ConditionVariableHandleStorage>(
24-
aligned_new_memory
25-
);
26-
}
20+
ConditionVariableInterface* ConditionVariableInterface::getDelegate(
21+
ConditionVariableHandleStorage& aligned_new_memory) {
22+
return Os::Delegate::makeDelegate<ConditionVariableInterface, Os::Posix::Mutex::PosixConditionVariable,
23+
ConditionVariableHandleStorage>(aligned_new_memory);
2724
}
25+
} // namespace Os

Os/Posix/Mutex.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// \title Os/Posix/Mutex.cpp
33
// \brief Posix implementation for Os::Mutex
44
// ======================================================================
5+
#include <Fw/Types/Assert.hpp>
56
#include <Os/Posix/Mutex.hpp>
67
#include <Os/Posix/error.hpp>
7-
#include <Fw/Types/Assert.hpp>
88

99
namespace Os {
1010
namespace Posix {
@@ -14,23 +14,23 @@ PosixMutex::PosixMutex() : Os::MutexInterface(), m_handle() {
1414
// set attributes
1515
pthread_mutexattr_t attribute;
1616
PlatformIntType status = pthread_mutexattr_init(&attribute);
17-
FW_ASSERT(status == 0, status);
17+
FW_ASSERT(status == 0, static_cast<FwAssertArgType>(status));
1818

1919
// set to normal mutex type
2020
status = pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_ERRORCHECK);
21-
FW_ASSERT(status == 0, status);
21+
FW_ASSERT(status == 0, static_cast<FwAssertArgType>(status));
2222

2323
// set to check for priority inheritance
2424
status = pthread_mutexattr_setprotocol(&attribute, PTHREAD_PRIO_INHERIT);
25-
FW_ASSERT(status == 0, status);
25+
FW_ASSERT(status == 0, static_cast<FwAssertArgType>(status));
2626

2727
status = pthread_mutex_init(&this->m_handle.m_mutex_descriptor, &attribute);
28-
FW_ASSERT(status == 0, status);
28+
FW_ASSERT(status == 0, static_cast<FwAssertArgType>(status));
2929
}
3030

3131
PosixMutex::~PosixMutex() {
3232
PlatformIntType status = pthread_mutex_destroy(&this->m_handle.m_mutex_descriptor);
33-
FW_ASSERT(status == 0, status);
33+
FW_ASSERT(status == 0, static_cast<FwAssertArgType>(status));
3434
}
3535

3636
PosixMutex::Status PosixMutex::take() {

Os/Posix/error.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,5 +184,21 @@ Mutex::Status posix_status_to_mutex_status(PlatformIntType posix_status){
184184
}
185185
return status;
186186
}
187+
188+
ConditionVariable::Status posix_status_to_conditional_status(PlatformIntType posix_status) {
189+
ConditionVariable::Status status = ConditionVariable::Status::ERROR_OTHER;
190+
switch (posix_status) {
191+
case 0:
192+
status = ConditionVariable::Status::OP_OK;
193+
break;
194+
case EPERM:
195+
status = ConditionVariable::Status::ERROR_MUTEX_NOT_HELD;
196+
break;
197+
default:
198+
status = ConditionVariable::Status::ERROR_OTHER;
199+
break;
200+
}
201+
return status;
202+
}
187203
}
188204
}

Os/Posix/error.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Os/FileSystem.hpp"
1010
#include "Os/Directory.hpp"
1111
#include "Os/RawTime.hpp"
12+
#include "Os/Condition.hpp"
1213

1314
namespace Os {
1415
namespace Posix {
@@ -49,6 +50,13 @@ Os::Task::Status posix_status_to_task_status(PlatformIntType posix_status);
4950
//!
5051
Os::Mutex::Status posix_status_to_mutex_status(PlatformIntType posix_status);
5152

53+
//! Convert a Posix return status (int) for Conditional Variable operations to the Os::ConditionVariable::Status
54+
//! representation.
55+
//! \param posix_status: return status
56+
//! \return: Os::ConditionVariable::Status representation of the error
57+
//!
58+
Os::ConditionVariable::Status posix_status_to_conditional_status(PlatformIntType posix_status);
59+
5260
}
5361
}
5462
#endif

Os/Stub/ConditionVariable.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ namespace Os {
99
namespace Stub {
1010
namespace Mutex {
1111

12-
void StubConditionVariable::wait(Os::Mutex& mutex) {
12+
StubConditionVariable::Status StubConditionVariable::pend(Os::Mutex& mutex) {
1313
// This stub implementation can only be used in deployments that never need to wait on any ConditionVariable.
14-
// Trigger an assertion if anyone ever tries to wait.
15-
FW_ASSERT(0);
14+
// Return error if anyone ever tries to wait.
15+
return StubConditionVariable::Status::ERROR_NOT_IMPLEMENTED;
1616
}
1717
void StubConditionVariable::notify() {
1818
// Nobody is waiting, because we assert if anyone tries to wait.
@@ -27,6 +27,6 @@ ConditionVariableHandle* StubConditionVariable::getHandle() {
2727
return &m_handle;
2828
}
2929

30-
}
31-
}
32-
}
30+
} // namespace Mutex
31+
} // namespace Stub
32+
} // namespace Os

0 commit comments

Comments
 (0)