Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions inc/private/dmod_mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extern "C" {
# error "This is private DMOD header. Don't include this outside DMOD library"
#endif

extern bool Dmod_Mgr_BuildSystemModuleList( void );
extern void Dmod_Mgr_FreeSystemModuleList( void );
extern bool Dmod_Mgr_IsSystemModule( const char* ModuleName );
extern void Dmod_Mgr_PrintSystemModules( void );
extern bool Dmod_Mgr_IsLoaded( const char* ModuleName );
Expand Down
5 changes: 5 additions & 0 deletions src/system/dmod_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ bool Dmod_Initialize( size_t NumIrqs, size_t MaxHandlersPerIrq )
{
return false;
}
if( !Dmod_Mgr_BuildSystemModuleList() )
{
DMOD_LOG_WARN("Cannot build the list of system modules - built-in APIs will be checked one by one\n");
}
return Dmod_BuiltinInputApi.InputSection != NULL && Dmod_BuiltinOutputApi.OutputSection != NULL;
}

Expand All @@ -157,6 +161,7 @@ bool Dmod_Initialize( size_t NumIrqs, size_t MaxHandlersPerIrq )
*/
bool Dmod_Deinitialize(void)
{
Dmod_Mgr_FreeSystemModuleList();
Dmod_Irq_Deinit();
return true;
}
Expand Down
184 changes: 169 additions & 15 deletions src/system/private/dmod_mgr.c
Original file line number Diff line number Diff line change
@@ -1,23 +1,152 @@
#define DMOD_PRIVATE
#include <string.h>
#include "dmod.h"
#include "private/dmod_vars.h"
#include "private/dmod_ctx.h"
#include "private/dmod_mgr.h"

/**
* @brief checks if the given module is a system module
*
* @param ModuleName Name of the module to check
*
* @return True if module is a system module, false otherwise
* @brief Names of the system modules - the modules the built-in input APIs belong to
*
* Packed one after another, each terminated with '\0', the list itself with an
* empty name. Built once (see Dmod_Mgr_BuildSystemModuleList), so that
* Dmod_Mgr_IsSystemModule() does not have to check the signature of every
* built-in API on each call.
*/
bool Dmod_Mgr_IsSystemModule( const char* ModuleName )
static char* SystemModuleNames = NULL;

/**
* @brief Read the module name of a built-in API signature that names a module
*
* @param Signature API signature
* @param outModuleName Buffer for the module name (DMOD_MAX_MODULE_NAME_LENGTH bytes)
*
* @return True if the signature is one that Dmod_ApiSignature_IsModule() accepts
*/
static bool ReadSystemModuleName( const char* Signature, char* outModuleName )
{
if(ModuleName == NULL || ModuleName[0] == 0)
if(
strncmp( Signature, DMOD_SIGNATURE_PREFIX, sizeof( DMOD_SIGNATURE_PREFIX ) - 1 ) != 0
&& strncmp( Signature, DMOD_BUILTIN_SIGNATURE_PREFIX, sizeof( DMOD_BUILTIN_SIGNATURE_PREFIX ) - 1 ) != 0
&& strncmp( Signature, DMOD_MAL_SIGNATURE_PREFIX, sizeof( DMOD_MAL_SIGNATURE_PREFIX ) - 1 ) != 0
&& strncmp( Signature, DMOD_DIF_SIGNATURE_PREFIX, sizeof( DMOD_DIF_SIGNATURE_PREFIX ) - 1 ) != 0
)
{
DMOD_LOG_ERROR("Cannot check if module is system module - invalid module name (empty or NULL)\n");
return false;
}

memset( outModuleName, 0, DMOD_MAX_MODULE_NAME_LENGTH );
return Dmod_ApiSignature_ReadModuleName( Signature, outModuleName, DMOD_MAX_MODULE_NAME_LENGTH - 1 );
}

/**
* @brief Find a system module name in the packed list
*
* @param Names Packed list of names (see SystemModuleNames)
* @param ModuleName Name to look for
* @param Length Number of characters of ModuleName to compare
*
* @return True if a name in the list starts with the first Length characters of ModuleName
*/
static bool FindSystemModuleName( const char* Names, const char* ModuleName, size_t Length )
{
for( const char* name = Names; *name != '\0'; name += strlen( name ) + 1 )
{
if( strncmp( name, ModuleName, Length ) == 0 )
{
return true;
}
}
return false;
}

/**
* @brief Add a module name to the packed list of names, unless it is already there
*
* @param Names Packed list of names (NULL for an empty one)
* @param Size Size of the list in bytes, updated on return
* @param ModuleName Name to add
*
* @return The list (possibly reallocated), or NULL on allocation failure
*/
static char* AddSystemModuleName( char* Names, size_t* Size, const char* ModuleName )
{
size_t length = strlen( ModuleName );
if( Names != NULL && FindSystemModuleName( Names, ModuleName, length + 1 ) )
{
return Names;
}

size_t used = ( Names == NULL ) ? 0 : *Size - 1;
char* names = Dmod_Realloc( Names, used + length + 2 );
if( names == NULL )
{
Dmod_Free( Names );
return NULL;
}

memcpy( &names[used], ModuleName, length + 1 );
names[used + length + 1] = '\0';
*Size = used + length + 2;
return names;
}

/**
* @brief Build the list of the system module names, if it is not built yet
*
* @return True if the list is available
*/
bool Dmod_Mgr_BuildSystemModuleList( void )
{
if( SystemModuleNames != NULL )
{
return true;
}

Dmod_BuiltinInputApi.SectionSize = (size_t)((void*)&__dmod_inputs_end - (void*)&__dmod_inputs_start);
size_t numberOfEntries = Dmod_Api_GetNumberOfEntries( &Dmod_BuiltinInputApi );
char* names = NULL;
size_t size = 0;
char moduleName[DMOD_MAX_MODULE_NAME_LENGTH];
for(size_t i = 0; i < numberOfEntries; i++)
{
const char* signature = Dmod_BuiltinInputApi.InputSection->Entries[i].Signature;
if( !Dmod_ApiSignature_IsValid( signature ) || !ReadSystemModuleName( signature, moduleName ) || moduleName[0] == '\0' )
{
continue;
}
names = AddSystemModuleName( names, &size, moduleName );
if( names == NULL )
{
DMOD_LOG_ERROR("Cannot allocate memory for the list of system modules\n");
return false;
}
}

SystemModuleNames = names;
return SystemModuleNames != NULL;
}

/**
* @brief Free the list of the system module names
*/
void Dmod_Mgr_FreeSystemModuleList( void )
{
Dmod_Free( SystemModuleNames );
SystemModuleNames = NULL;
}

/**
* @brief Check if the given module is a system module by checking every built-in API
*
* Fallback for when the list of the system module names cannot be built.
*
* @param ModuleName Name of the module to check
*
* @return True if module is a system module, false otherwise
*/
static bool IsSystemModuleInApis( const char* ModuleName )
{
Dmod_BuiltinInputApi.SectionSize = (size_t)((void*)&__dmod_inputs_end - (void*)&__dmod_inputs_start);
size_t numberOfEntries = Dmod_Api_GetNumberOfEntries( &Dmod_BuiltinInputApi );
for(size_t i = 0; i < numberOfEntries; i++)
Expand All @@ -30,6 +159,27 @@ bool Dmod_Mgr_IsSystemModule( const char* ModuleName )
return false;
}

/**
* @brief checks if the given module is a system module
*
* @param ModuleName Name of the module to check
*
* @return True if module is a system module, false otherwise
*/
bool Dmod_Mgr_IsSystemModule( const char* ModuleName )
{
if(ModuleName == NULL || ModuleName[0] == 0)
{
DMOD_LOG_ERROR("Cannot check if module is system module - invalid module name (empty or NULL)\n");
return false;
}
if( !Dmod_Mgr_BuildSystemModuleList() )
{
return IsSystemModuleInApis( ModuleName );
}
return FindSystemModuleName( SystemModuleNames, ModuleName, strlen( ModuleName ) );
}

/**
* @brief Prints all system modules to the log
*/
Expand All @@ -53,12 +203,14 @@ void Dmod_Mgr_PrintSystemModules( void )
*/
bool Dmod_Mgr_IsLoaded( const char* ModuleName )
{
if(Dmod_Mgr_IsSystemModule( ModuleName ))
/* Loaded modules first: a lookup in the context table is cheap, while
* Dmod_Mgr_IsSystemModule() checks the signature of every built-in API. */
if(Dmod_Context_Get( ModuleName ) != NULL)
{
return true;
return true;
}

return Dmod_Context_Get( ModuleName ) != NULL;
return Dmod_Mgr_IsSystemModule( ModuleName );
}

/**
Expand All @@ -70,10 +222,12 @@ bool Dmod_Mgr_IsLoaded( const char* ModuleName )
*/
bool Dmod_Mgr_IsEnabled( const char* ModuleName )
{
if(Dmod_Mgr_IsSystemModule( ModuleName ))
/* See Dmod_Mgr_IsLoaded() for why loaded modules are checked first */
Dmod_Context_t* context = Dmod_Context_Get( ModuleName );
if(context != NULL && Dmod_IsEnabled( context ))
{
return true;
return true;
}
Dmod_Context_t* context = Dmod_Context_Get( ModuleName );
return context != NULL && Dmod_IsEnabled( context );

return Dmod_Mgr_IsSystemModule( ModuleName );
}
57 changes: 57 additions & 0 deletions tests/system/private/tests_dmod_mgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,63 @@ TEST_F(DmodMgrTest, IsNullModule)
ASSERT_FALSE(Dmod_Mgr_IsSystemModule(NULL));
}

/**
* @brief Test for Dmod_Mgr_BuildSystemModuleList
*
* The test checks if the list of the system modules can be built more than
* once, and if the result of Dmod_Mgr_IsSystemModule does not change with it.
*/
TEST_F(DmodMgrTest, BuildSystemModuleList)
{
ASSERT_TRUE(Dmod_Mgr_BuildSystemModuleList());
ASSERT_TRUE(Dmod_Mgr_BuildSystemModuleList());
ASSERT_TRUE(Dmod_Mgr_IsSystemModule("Dmod"));
ASSERT_FALSE(Dmod_Mgr_IsSystemModule("Test"));
}

/**
* @brief Test for Dmod_Mgr_FreeSystemModuleList
*
* The test checks if Dmod_Mgr_IsSystemModule builds the list of the system
* modules again when it has been freed.
*/
TEST_F(DmodMgrTest, IsSystemModuleAfterFreeingList)
{
Dmod_Mgr_FreeSystemModuleList();
ASSERT_TRUE(Dmod_Mgr_IsSystemModule("Dmod"));
ASSERT_FALSE(Dmod_Mgr_IsSystemModule("Test"));
}

/**
* @brief Test for Dmod_Mgr_IsSystemModule
*
* The test checks if every module named by a built-in API signature is
* reported as a system module.
*/
TEST_F(DmodMgrTest, IsSystemModuleForEveryBuiltinApi)
{
Dmod_BuiltinInputApi.SectionSize = (size_t)((uint8_t*)&__dmod_inputs_end - (uint8_t*)&__dmod_inputs_start);
size_t numberOfEntries = Dmod_Api_GetNumberOfEntries(&Dmod_BuiltinInputApi);
ASSERT_GT(numberOfEntries, 0u);
size_t checked = 0;
for(size_t i = 0; i < numberOfEntries; i++)
{
const char* signature = Dmod_BuiltinInputApi.InputSection->Entries[i].Signature;
char moduleName[DMOD_MAX_MODULE_NAME_LENGTH] = {0};
if(!Dmod_ApiSignature_IsValid(signature)
|| Dmod_ApiSignature_IsTest(signature)
|| strncmp(signature, DMOD_IRQ_SIGNATURE_PREFIX, sizeof(DMOD_IRQ_SIGNATURE_PREFIX) - 1) == 0
|| !Dmod_ApiSignature_ReadModuleName(signature, moduleName, sizeof(moduleName) - 1)
|| moduleName[0] == '\0')
{
continue;
}
EXPECT_TRUE(Dmod_Mgr_IsSystemModule(moduleName)) << moduleName;
checked++;
}
ASSERT_GT(checked, 0u);
}

// ===============================================================
// Tests for Dmod_Mgr_IsLoaded
// ===============================================================
Expand Down
Loading