diff --git a/README.md b/README.md index f23f527..6f6972e 100644 --- a/README.md +++ b/README.md @@ -555,6 +555,10 @@ It is also **recommended** (but not mandatory) to define those: | `Dmod_Mutex_Delete` | *Releases mutex memory* | | `Dmod_Mutex_Lock` | *Locks the mutex* | | `Dmod_Mutex_Unlock` | *Unlocks the mutex* | +| `Dmod_Semaphore_New` | *Creates new semaphore* | +| `Dmod_Semaphore_Wait`| *Waits for semaphore* | +| `Dmod_Semaphore_Post`| *Signals semaphore* | +| `Dmod_Semaphore_Delete`| *Releases semaphore memory* | 6. **Initialize the Dmod system**: Before using any Dmod functions, you must call `Dmod_Initialize()` to initialize the system's global variables. This function should be called once at the beginning of your application, before loading any modules. @@ -868,4 +872,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/inc/dmod_sal.h b/inc/dmod_sal.h index 6bad8c0..e584789 100644 --- a/inc/dmod_sal.h +++ b/inc/dmod_sal.h @@ -323,6 +323,10 @@ DMOD_BUILTIN_API(Dmod, 1.0, void*, _Mutex_New, ( bool Recursive ) ); DMOD_BUILTIN_API(Dmod, 1.0, int , _Mutex_Lock, ( void* Mutex ) ); DMOD_BUILTIN_API(Dmod, 1.0, int , _Mutex_Unlock, ( void* Mutex ) ); DMOD_BUILTIN_API(Dmod, 1.0, void , _Mutex_Delete, ( void* Mutex ) ); +DMOD_BUILTIN_API(Dmod, 1.0, void*, _Semaphore_New, ( uint32_t InitialValue ) ); +DMOD_BUILTIN_API(Dmod, 1.0, int , _Semaphore_Wait, ( void* Semaphore ) ); +DMOD_BUILTIN_API(Dmod, 1.0, int , _Semaphore_Post, ( void* Semaphore ) ); +DMOD_BUILTIN_API(Dmod, 1.0, void , _Semaphore_Delete, ( void* Semaphore ) ); DMOD_BUILTIN_API(Dmod, 1.0, size_t, _GetLeftStackSize, ( void ) ); //! @} diff --git a/src/system/if/dmod_if_rtos.c b/src/system/if/dmod_if_rtos.c index 3822673..8a1d042 100644 --- a/src/system/if/dmod_if_rtos.c +++ b/src/system/if/dmod_if_rtos.c @@ -31,6 +31,7 @@ #if DMOD_USE_PTHREAD # define __USE_UNIX98 # include +# include # ifdef __linux__ /* Forward declarations for Linux-specific thread attribute functions */ extern int pthread_getattr_np(pthread_t th, pthread_attr_t *attr); @@ -178,6 +179,129 @@ DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, void, _Mutex_Delete, ( void* Mutex )) #endif } +/** + * @brief Create new semaphore + * + * @param InitialValue Initial semaphore value + * + * @return Pointer to new semaphore + */ +DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, void*, _Semaphore_New, ( uint32_t InitialValue )) +{ + #if DMOD_USE_PTHREAD + sem_t* Semaphore = Dmod_Malloc(sizeof(sem_t)); + if( Semaphore == NULL ) + { + DMOD_LOG_ERROR("Cannot create new semaphore - cannot allocate memory\n"); + return NULL; + } + + if( sem_init(Semaphore, 0, InitialValue) != 0 ) + { + DMOD_LOG_ERROR("Cannot create new semaphore - cannot initialize semaphore\n"); + Dmod_Free(Semaphore); + return NULL; + } + + return Semaphore; + #else + (void)InitialValue; + return NULL; + #endif +} + +/** + * @brief Wait for semaphore + * + * @param Semaphore Semaphore to wait for + * + * @return 0 on success, negative errno on error + */ +DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, int, _Semaphore_Wait, ( void* Semaphore )) +{ + #if DMOD_USE_PTHREAD + if( Semaphore == NULL ) + { + DMOD_LOG_ERROR("Cannot wait for semaphore - invalid semaphore\n"); + return -EINVAL; + } + + return sem_wait(Semaphore); + #else + if( Semaphore == NULL ) + { + return 0; // No-op if semaphore is NULL + } + else + { + DMOD_LOG_WARN("Dmod_Semaphore_Wait interface not implemented\n"); + return -ENOSYS; + } + #endif +} + +/** + * @brief Post semaphore + * + * @param Semaphore Semaphore to post + * + * @return 0 on success, negative errno on error + */ +DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, int, _Semaphore_Post, ( void* Semaphore )) +{ + #if DMOD_USE_PTHREAD + if( Semaphore == NULL ) + { + DMOD_LOG_ERROR("Cannot post semaphore - invalid semaphore\n"); + return -EINVAL; + } + + return sem_post(Semaphore); + #else + if( Semaphore == NULL ) + { + return 0; // No-op if semaphore is NULL + } + else + { + DMOD_LOG_WARN("Dmod_Semaphore_Post interface not implemented\n"); + return -ENOSYS; + } + #endif +} + +/** + * @brief Delete semaphore + * + * @param Semaphore Semaphore to delete + */ +DMOD_INPUT_WEAK_API_DECLARATION(Dmod, 1.0, void, _Semaphore_Delete, ( void* Semaphore )) +{ + #if DMOD_USE_PTHREAD + if( Semaphore == NULL ) + { + DMOD_LOG_ERROR("Cannot delete semaphore - invalid semaphore\n"); + return; + } + + if( sem_destroy(Semaphore) != 0 ) + { + DMOD_LOG_ERROR("Cannot delete semaphore - cannot destroy semaphore\n"); + } + + Dmod_Free(Semaphore); + #else + if( Semaphore == NULL ) + { + return; // No-op if semaphore is NULL + } + else + { + DMOD_LOG_WARN("Dmod_Semaphore_Delete interface not implemented\n"); + } + #endif +} + /** * @brief Get the remaining stack size in the current thread * diff --git a/tests/system/public/CMakeLists.txt b/tests/system/public/CMakeLists.txt index a9eb033..3644572 100644 --- a/tests/system/public/CMakeLists.txt +++ b/tests/system/public/CMakeLists.txt @@ -7,6 +7,7 @@ set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_readnextmodule.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_loadfile_package_path.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_irq.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_semaphore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_verify_apis.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_api_signature.cpp PARENT_SCOPE diff --git a/tests/system/public/tests_dmod_semaphore.cpp b/tests/system/public/tests_dmod_semaphore.cpp new file mode 100644 index 0000000..da68ce9 --- /dev/null +++ b/tests/system/public/tests_dmod_semaphore.cpp @@ -0,0 +1,22 @@ +#include +#include +#include "dmod.h" + +TEST(DmodSemaphoreTest, NewWaitPostDelete) +{ + void* semaphore = Dmod_Semaphore_New(1); + ASSERT_NE(semaphore, nullptr); + + EXPECT_EQ(Dmod_Semaphore_Wait(semaphore), 0); + EXPECT_EQ(Dmod_Semaphore_Post(semaphore), 0); + EXPECT_EQ(Dmod_Semaphore_Wait(semaphore), 0); + + Dmod_Semaphore_Delete(semaphore); +} + +TEST(DmodSemaphoreTest, HandlesNullSemaphore) +{ + EXPECT_EQ(Dmod_Semaphore_Wait(nullptr), -EINVAL); + EXPECT_EQ(Dmod_Semaphore_Post(nullptr), -EINVAL); + EXPECT_NO_FATAL_FAILURE(Dmod_Semaphore_Delete(nullptr)); +}