From a87fe36862afeabb8d089de4fa9c361e31998ebd Mon Sep 17 00:00:00 2001 From: Ingo Huerner Date: Fri, 13 Jun 2014 16:40:48 +0200 Subject: Implemented on demand/static loading of plugins (part I); ATTENTION: pluginf config file has been changed, see persistence_client_library.h for details --- include/persistence_client_custom.h | 2 +- include/persistence_client_library.h | 36 +++ src/persistence_client_library.c | 103 +++++--- src/persistence_client_library_backup_filelist.c | 21 +- src/persistence_client_library_custom_loader.c | 285 ++++++++++++--------- src/persistence_client_library_custom_loader.h | 33 ++- src/persistence_client_library_data_organization.c | 10 + src/persistence_client_library_data_organization.h | 5 + src/persistence_client_library_dbus_cmd.c | 1 - 9 files changed, 302 insertions(+), 194 deletions(-) diff --git a/include/persistence_client_custom.h b/include/persistence_client_custom.h index b9bf8c9..302226a 100644 --- a/include/persistence_client_custom.h +++ b/include/persistence_client_custom.h @@ -34,7 +34,7 @@ * - 2012.07.14 ihuerner 1.0.0.0 Initial version of the interface */ - + /** \ingroup GEN_PERS_CLIENTLIB_INTERFACE API document * \{ */ diff --git a/include/persistence_client_library.h b/include/persistence_client_library.h index 1bd005a..f7a835c 100644 --- a/include/persistence_client_library.h +++ b/include/persistence_client_library.h @@ -40,6 +40,42 @@ * The Persistence Client Library (PCL) provides an API to applications to read and write persistent data * via a key-value and a file interface.
* It also provide a plugin API to allow users to extend the client library with custom storage solutions. + * + * @section Custom plugin configuration file + * @attention + * The plugin configuration file has been changed! + * + * The configuration file has now the following format
+ * + * + * Predefined plugin name
+ * Use one of the following names: + * - early => predefined custom library for early persistence + * - secure => predefined custom library for secure persistence + * - emergency => predefined custom library for emengency persistence + * - hwinfo => predefined custom library for hw information + * - custom1 => custom library 1 + * - custom2 => custom library 2 + * - custom3 => custom library 3 + * + * Path and library name:
+ * The name and path of the library + * + * Valid loading type: + * - "init" ==> if the plugin must be laoding during the pclInitLibrary function + * - "on" ==> if on demand laoding of the plugin is requested. The plugin will be loaded + * when a plugin function will be loaded the first time + * + * Init Type: + * - sync ==> use the "plugin_init" function for plugin initialization + * - async ==> use the "plugin_init_async" function for plugin initialization + * + * Example:
+ * hwinfo /usr/local/lib/libhwinfoperscustom.so init async + * + * @note + * Make sure that there is only ONE blank between each entry and no blank at the end of the file. + * The parser has been optimized for speed, so there is less error checking. */ diff --git a/src/persistence_client_library.c b/src/persistence_client_library.c index 94b1169..18d5cdd 100644 --- a/src/persistence_client_library.c +++ b/src/persistence_client_library.c @@ -45,21 +45,27 @@ static int gShutdownMode = 0; static int gCancelCounter = 0; +int customAsyncInitClbk(int errcode) +{ + printf("Dummy async init Callback\n"); +} + + int pclInitLibrary(const char* appName, int shutdownMode) { - int status = 0; int i = 0, rval = 1; + printf("INIT START\n\n"); + if(gPclInitialized == PCLnotInitialized) { + printf("INIT START ==> DO INIT\n\n"); gShutdownMode = shutdownMode; DLT_REGISTER_CONTEXT(gPclDLTContext,"PCL","Context for persistence client library logging"); DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclInitLibrary => I N I T Persistence Client Library - "), DLT_STRING(appName), DLT_STRING("- init counter: "), DLT_INT(gPclInitialized) ); - /// environment variable for on demand loading of custom libraries - const char *pOnDemandLoad = getenv("PERS_CUSTOM_LIB_LOAD_ON_DEMAND"); /// environment variable for max key value data const char *pDataSize = getenv("PERS_MAX_KEY_VAL_DATA_SIZE"); /// blacklist path environment variable @@ -121,9 +127,9 @@ int pclInitLibrary(const char* appName, int shutdownMode) DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("PAS interface is not enabled, enable with \"./configure --enable-pasinterface\"")); #endif + /// get custom library names to load - status = get_custom_libraries(); - if(status >= 0) + if(get_custom_libraries() >= 0) { // initialize custom library structure for(i = 0; i < PersCustomLib_LastEntry; i++) @@ -131,42 +137,62 @@ int pclInitLibrary(const char* appName, int shutdownMode) invalidate_custom_plugin(i); } - if(pOnDemandLoad == NULL) // load all available libraries now - { - for(i=0; i < PersCustomLib_LastEntry; i++ ) - { - if(check_valid_idx(i) != -1) - { - if(load_custom_library(i, &gPersCustomFuncs[i] ) == 1) - { - if( (gPersCustomFuncs[i].custom_plugin_init) != NULL) - { - DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclInitLibrary => Loaded plugin: "), - DLT_STRING(get_custom_client_lib_name(i))); - gPersCustomFuncs[i].custom_plugin_init(); - } - else - { - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r could not load plugin functions: "), - DLT_STRING(get_custom_client_lib_name(i))); - } - } - else - { - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r could not load plugin: "), - DLT_STRING(get_custom_client_lib_name(i))); - } - } - else - { - continue; - } - } - } + for(i=0; i < PersCustomLib_LastEntry; i++ ) + { + if(check_valid_idx(i) != -1) + { + if(getCustomLoadingType(i) == LoadType_PclInit) // check if the plugin must be loaded on plc init + { + if(load_custom_library(i, &gPersCustomFuncs[i] ) == 1) + { + PersInitType_e initType = getCustomInitType(i); + if(initType == Init_Synchronous) + { + if( (gPersCustomFuncs[i].custom_plugin_init) != NULL) + { + DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclInitLibrary => plugin: "), DLT_STRING(get_custom_client_lib_name(i))); + gPersCustomFuncs[i].custom_plugin_init(); + } + else + { + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r could not load plugin functions: "), + DLT_STRING(get_custom_client_lib_name(i))); + } + } + else if(initType == Init_Asynchronous) + { + if( (gPersCustomFuncs[i].custom_plugin_init_async) != NULL) + { + DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclInitLibrary => plugin: "), DLT_STRING(get_custom_client_lib_name(i))); + gPersCustomFuncs[i].custom_plugin_init_async(customAsyncInitClbk); + } + else + { + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r could not load plugin functions: "), + DLT_STRING(get_custom_client_lib_name(i))); + } + } + else + { + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r unknown init type "), DLT_STRING(get_custom_client_lib_name(i))); + } + } + else + { + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclInitLibrary => E r r o r could not load plugin: "), + DLT_STRING(get_custom_client_lib_name(i))); + } + } + } + else + { + continue; + } + } } else { - DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("pclInit => Failed to load custom library config table => error number:"), DLT_INT(status)); + DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("pclInit => Failed to load custom library config table")); } // initialize keyHandle array @@ -186,6 +212,7 @@ int pclInitLibrary(const char* appName, int shutdownMode) DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclInitLibrary => I N I T Persistence Client Library - "), DLT_STRING(gAppId), DLT_STRING("- ONLY INCREMENT init counter: "), DLT_INT(gPclInitialized) ); } + return rval; } diff --git a/src/persistence_client_library_backup_filelist.c b/src/persistence_client_library_backup_filelist.c index 79188ee..c8da7b5 100644 --- a/src/persistence_client_library_backup_filelist.c +++ b/src/persistence_client_library_backup_filelist.c @@ -51,23 +51,6 @@ void* key_val_dup(void *p); int key_val_cmp(const void *p1, const void *p2 ); - -/// the size of the token array -enum configConstants -{ - TOKENARRAYSIZE = 255 -}; - - -const char gCharLookup[] = -{ - 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, // from 0x0 (NULL) to 0x1F (unit seperator) - 0,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, // from 020 (space) to 0x2F (?) - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, // from 040 (@) to 0x5F (_) - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1 // from 060 (') to 0x7E (~) -}; - - char* gpConfigFileMap = 0; char* gpTokenArray[TOKENARRAYSIZE] = {0}; int gTokenCounter = 0; @@ -82,7 +65,7 @@ static jsw_rbtree_t *gRb_tree_bl = NULL; int need_backup_key(unsigned int key); -void fillCharTokenArray() +void fillFileBackupCharTokenArray() { unsigned int i=0; int blankCount=0; @@ -210,7 +193,7 @@ int readBlacklistConfigFile(const char* filename) // reset the token counter gTokenCounter = 0; - fillCharTokenArray(); + fillFileBackupCharTokenArray(); // create filenames and store them in the tree createAndStoreFileNames(); diff --git a/src/persistence_client_library_custom_loader.c b/src/persistence_client_library_custom_loader.c index d0dc4ae..36fc0b8 100644 --- a/src/persistence_client_library_custom_loader.c +++ b/src/persistence_client_library_custom_loader.c @@ -33,14 +33,99 @@ /// type definition of persistence custom library information typedef struct sPersCustomLibInfo { - char libname[CustLibMaxLen]; - int valid; + char libname[CustLibMaxLen]; + int valid; + PersInitType_e initFunction; + PersLoadingType_e loadingType; } PersCustomLibInfo; /// array with custom client library names static PersCustomLibInfo gCustomLibArray[PersCustomLib_LastEntry]; +char* gpCustomConfigFileMap = 0; +char* gpCustomTokenArray[TOKENARRAYSIZE]; +int gCustomTokenCounter = 0; +unsigned int gCustomConfigFileSize = 0; + + + +void fillCustomCharTokenArray() +{ + unsigned int i=0; + int blankCount=0; + char* tmpPointer = gpCustomConfigFileMap; + + // set the first pointer to the start of the file + gpCustomTokenArray[blankCount] = tmpPointer; + blankCount++; + + while(i < gCustomConfigFileSize) + { + if(1 != gCharLookup[(int)*tmpPointer]) + { + *tmpPointer = 0; + + // check if we are at the end of the token array + if(blankCount >= TOKENARRAYSIZE) + { + break; + } + gpCustomTokenArray[blankCount] = tmpPointer+1; + blankCount++; + gCustomTokenCounter++; + + } + tmpPointer++; + i++; + } +} + +PersLoadingType_e getCustomLoadingType(int i) +{ + return gCustomLibArray[i].loadingType; +} + +PersLoadingType_e getLoadingType(const char* type) +{ + PersLoadingType_e persLoadingType = LoadType_Undefined; + + if(0 == strcmp(type, "init") ) + { + persLoadingType = LoadType_PclInit; + } + else if(0 == strcmp(type, "od") ) + { + persLoadingType = LoadType_OnDemand; + } + + return persLoadingType; +} + +PersInitType_e getCustomInitType(int i) +{ + return gCustomLibArray[i].initFunction; +} + +PersInitType_e getInitType(const char* policy) +{ + PersInitType_e persInitType = Init_Undefined; + + if(0 == strcmp(policy, "sync")) + { + persInitType = Init_Synchronous; + } + else if (0 == strcmp(policy, "async")) + { + persInitType = Init_Asynchronous; + } + + return persInitType; +} + + + + PersistenceCustomLibs_e custom_client_name_to_id(const char* lib_name, int substring) { @@ -124,18 +209,16 @@ PersistenceCustomLibs_e custom_client_name_to_id(const char* lib_name, int subst int get_custom_libraries() { - int rval = 0, fd = 0, j = 0; - + int rval = 0, fd = 0, j = 0, i= 0; + int status = 0; struct stat buffer; - char* delimiters = " \n"; // search for blank and end of line - char* configFileMap = 0; - char* token = 0; + const char *filename = getenv("PERS_CLIENT_LIB_CUSTOM_LOAD"); - if(filename == NULL) - { - filename = "/etc/pclCustomLibConfigFile.cfg"; // use default filename - } + if(filename == NULL) + { + filename = "/etc/pclCustomLibConfigFile.cfg"; // use default filename + } for(j=0; j 20) // file needs to be at least bigger then 20 bytes - { - fd = open(filename, O_RDONLY); - if (fd != -1) - { - configFileMap = (char*)mmap(0, buffer.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0); - - if(configFileMap != MAP_FAILED) - { - int libId = 0; - - // get the library identifier (early, secure, emergency, ...) - token = strtok(configFileMap, delimiters); - libId = custom_client_name_to_id(token, 0); - - - if(libId < PersCustomLib_LastEntry) - { - gCustomLibArray[libId].valid = 1; - } - else - { - munmap(configFileMap, buffer.st_size); // @CB: Add - close(fd); // @CB: Add // close file descriptor before return - return EPERS_OUTOFBOUNDS; // out of array bounds - } - - // get the library name - token = strtok (NULL, delimiters); - strncpy(gCustomLibArray[libId].libname, token, CustLibMaxLen); - gCustomLibArray[libId].libname[CustLibMaxLen-1] = '\0'; // Ensures 0-Termination - - while( token != NULL ) - { - // get the library identifier (early, secure, emergency, ...) - token = strtok(NULL, delimiters); - if(token != NULL) - { - libId = custom_client_name_to_id(token, 0); - if(libId < PersCustomLib_LastEntry) - { - gCustomLibArray[libId].valid = 1; - } - else - { - rval = EPERS_OUTOFBOUNDS; - break; - } - } - else - { - break; - } - - // get the library name - token = strtok (NULL, delimiters); - if(token != NULL) - { - strncpy(gCustomLibArray[libId].libname, token, CustLibMaxLen); - gCustomLibArray[libId].libname[CustLibMaxLen-1] = '\0'; // Ensures 0-Termination - } - else - { - break; - } - } - - munmap(configFileMap, buffer.st_size); - - #if 0 // debuging - for(j=0; j Name: %s | valid: %d \n", gCustomLibArray[j].libname, gCustomLibArray[j].valid); - } - #endif - } - else - { - rval = EPERS_CONFIGMAPFAILED; - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error - mapping of file failed")); - } - close(fd); - } - else - { - rval = EPERS_CONFIGNOTAVAILABLE; - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error - no file with plugins available:"), DLT_STRING(filename), DLT_STRING(strerror(errno))); - } - } - else - { - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error - invalid file size"), DLT_STRING(filename), DLT_STRING(strerror(errno))); - } + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error ==> Error file open: "), + DLT_STRING(filename), DLT_STRING("err msg: "), DLT_STRING(strerror(errno)) ); + + return -1; + } + + // check for empty file + if(gCustomConfigFileSize >= 0) + { + // map the config file into memory + gpCustomConfigFileMap = (char*)mmap(0, gCustomConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (gpCustomConfigFileMap == MAP_FAILED) + { + gpCustomConfigFileMap = 0; + close(fd); + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error ==> Error mapping the file")); + return -1; + } + + // reset the token counter + gCustomTokenCounter = 0; + + fillCustomCharTokenArray(); + + while( i < TOKENARRAYSIZE ) + { + if(gpCustomTokenArray[i] != 0 && gpCustomTokenArray[i+1] != 0 && gpCustomTokenArray[i+2] != 0 &&gpCustomTokenArray[i+3] != 0 ) + { + int libId = custom_client_name_to_id(gpCustomTokenArray[i], 0); // get the custom libID + + // assign the libraryname + strncpy(gCustomLibArray[libId].libname, gpCustomTokenArray[i+1], CustLibMaxLen); + gCustomLibArray[libId].libname[CustLibMaxLen-1] = '\0'; // Ensures 0-Termination + + gCustomLibArray[libId].loadingType = getLoadingType(gpCustomTokenArray[i+2]); + gCustomLibArray[libId].initFunction = getInitType(gpCustomTokenArray[i+3]); + gCustomLibArray[libId].valid = 1; // marks as valid; +#if 0 + // debug + printf(" 1. => %s => %d \n", gpCustomTokenArray[i], libId); + printf(" 2. => %s => %s \n", gpCustomTokenArray[i+1], gCustomLibArray[libId].libname); + printf(" 3. => %s => %d \n", gpCustomTokenArray[i+2], (int)gCustomLibArray[libId].initFunction); + printf(" 4. => %s => %d \n\n", gpCustomTokenArray[i+3], (int)gCustomLibArray[libId].loadingType); +#endif + } + else + { + break; + } + i+=4; // move to the next configuration file entry + } + + close(fd); } else { - rval = EPERS_CONFIGNOSTAT; - DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("lload config file error - can't stat config file:"), DLT_STRING(filename), DLT_STRING(strerror(errno))); + DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("load config file error ==> Error file size is 0")); + close(fd); + rval = -1; } + return rval; } @@ -394,24 +447,6 @@ int load_custom_library(PersistenceCustomLibs_e customLib, Pers_custom_functs_s } - -int load_all_custom_libraries() -{ - int rval = 0, - i = 0; - - for(i=0; i