📄 cdb.c
字号:
/*************************************************************************** spm.c - RTLinux kernel module for storing information about available SPM types. ------------------- begin : 2002 authors : Silvio Boehler emails : sboehler@student.ethz.ch ***************************************************************************//*************************************************************************** Changes ------- date - name - description09.09.2002 - silvio - begin work **************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************//** * Debugging stuff */#include "debugging.h"#ifdef DBG_LVL#undef DBG_LVL#endif#define DBG_LVL 0/** * The interface for this module */#include "cdb.h"/** * We use statistics and configuration parameters */#include "system.h"#include "parameter_types.h"#include "parameters.h"#include "ports.h"#include "cdb.h"#include "memory.h"//-------------------------------------------------------------------// TYPES//-------------------------------------------------------------------/** * This is an entry in the SPM database. Reference counting is used * for */typedef struct { int refs; // we do reference counting, char name[SWR_CDB_MAX_NAME_LENGTH]; const swr_spc_desc_t *desc;}database_entry_t;typedef struct { int nbr_spms; pthread_mutex_t mutex; int last_id; database_entry_t **entries;}database_t;//-------------------------------------------------------------------// GLOBAL VARIABLES//-------------------------------------------------------------------database_t *database;//-------------------------------------------------------------------// MACROS//-------------------------------------------------------------------#define INDEX(id) ( (id) & (DB_SIZE - 1) )#define TURN(id) ( (id) >> SWR_CDB_SIZE_LOG_2 )#define DB_SIZE (1 << SWR_CDB_SIZE_LOG_2)//-------------------------------------------------------------------//// PRIVATE FUNCTIONS////-------------------------------------------------------------------//-------------------------------------------------------------------// Initializing and destroying SPM descriptions//-------------------------------------------------------------------/** * Create and initialize SPM description. * * @param nbr_inputs The number of inputs * * @param nbr_outputs The number of outputs * * @param nbr_config_params The number of configuration parameters * * @param nbr_stats_params The number of statistics parameters * * @return A pointer to the newly allocated SPM description. In case * of an error, NULL is returned. * */swr_spc_desc_t *create_spc_desc(int nbr_inputs, int nbr_outputs, int nbr_config_params, int nbr_stats_params) { swr_spc_desc_t *desc = swr_malloc(sizeof(swr_spc_desc_t)); if (!desc) { PR_DBG(0, "Couldn't create SPM description\n"); return NULL; } init_parameters_desc(&desc->stats, nbr_stats_params); init_parameters_desc(&desc->config, nbr_config_params); init_ports_desc(&desc->inputs, nbr_inputs); init_ports_desc(&desc->outputs, nbr_outputs); desc->fn_init = NULL; desc->fn_process_data = NULL; desc->fn_reconfigure = NULL; desc->fn_configure_inputs = NULL; desc->fn_configure_outputs = NULL; desc->fn_custom_msg = NULL; desc->fn_finalize = NULL; return desc;}/** * Free a SPM description. * * @param desc A pointer to the SPM description which is to free. * * @return 0 if success, a negative number in case of an error. */int free_spc_desc(swr_spc_desc_t *desc) { int error = 0; if (!desc) { PR_DBG(0, "desc == NULL\n"); return -1; } error |= finalize_parameters_desc(&desc->config); error |= finalize_parameters_desc(&desc->stats); error |= finalize_ports_desc(&desc->inputs); error |= finalize_ports_desc(&desc->outputs); error |= swr_free(desc); if (error) { PR_DBG(0, "freeing failed\n"); return error; } return 0;}/** * Check whether a SPM description is complete. * * @param desc The SPM description to be checked. * * @return 0 if the description is not complete, !0 if it is complete. */inline int description_complete(const swr_spc_desc_t *desc) { if (desc) return parameters_desc_complete(desc->config) && parameters_desc_complete(desc->stats) && ports_desc_complete(desc->inputs) && ports_desc_complete(desc->outputs); PR_DBG(0, "desc == NULL"); return -1;}//-------------------------------------------------------------------// Initializing and destroying of the database//-------------------------------------------------------------------/** * Create the database. * * @return 0 if success, a negative number if error. */int create_database(void) { database = (database_t *)swr_malloc(sizeof(database_t)); if (!database) { PR_DBG(0, "couldn't allocate database\n"); return -1; } database->nbr_spms = 0; database->last_id = -1; PR_DBG(1, "Database created\n"); return 0;}/** * Destroy the database. * * @return 0 if success, a negative number if error. */int destroy_database(void) { int error = swr_free(database); if (error) { PR_DBG(0, "Error freeing the database\n"); return -1; } PR_DBG(1, "Database destroyed\n"); return 0;}/** * Create array of pointers to entries * * @return 0 if success, a negative number if error. */int create_entries_array(void) { int i; database->entries = (database_entry_t **)swr_malloc(sizeof(database_entry_t *[DB_SIZE])); if (!database->entries) { PR_DBG(0, "Couldn't allocate array\n"); return -1; } for (i = 0; i < DB_SIZE; i++) database->entries[i] = 0; PR_DBG(1, "Created and initialized array\n"); return 0;}/** * Destroy array of pointers to entries * * @return 0 if success, a negative number if error. */int destroy_entries_array(void) { if (swr_free(database->entries)) { PR_DBG(0, "Couldn't free database entries array\n"); return -1; } PR_DBG(1, "Freed array\n"); return 0;}/** * Initialize the database * * @return 0 if success, a negative number if error. */int initialize(void) { int error; error = create_database(); if (error) goto create_database_failed; error = create_entries_array(); if (error) goto create_entries_array_failed; error = pthread_mutex_init(&database->mutex, 0); if (error) goto init_mutex_failed; return 0;init_mutex_failed: destroy_entries_array();create_entries_array_failed: destroy_database();create_database_failed: return -1;}/** * Finalize the database */void finalize(void) { pthread_mutex_lock(&database->mutex); destroy_entries_array(); destroy_database(); pthread_mutex_unlock(&database->mutex); pthread_mutex_destroy(&database->mutex);}//-------------------------------------------------------------------// Basic database functions//-------------------------------------------------------------------/** * Get the next free id. * * @param id A pointer to swr_spc_id_t where the id will be written. * * @return 0 if success, a negative number if error */int get_new_id(swr_spc_id_t *id) { int i; for (i = 1; i <= DB_SIZE; i++) { if (!database->entries[INDEX(database->last_id + i)]) { database->last_id += i; *id = database->last_id; return 0; } } PR_DBG(0, "Database full, can't create new entry\n"); return -1;}/** * Check if the ID is valid and the corresponding SPM exists in the * database. * * @param id The ID which is to check. * * @return !0 if valid, 0 if not valid. */int validate_id(swr_spc_id_t id) { if (id < 0) { PR_DBG(0, "id invalid (id < 0)\n"); return 0; } if (!database->entries[INDEX(id)]) { PR_DBG(0, "id invalid (entry doesn't exist)\n"); return 0; } if (database->entries[INDEX(id)]->desc->id != id) { PR_DBG(0, "id invalid (SPM exists but other id)\n" ); return 0; } // ID is valid: return 1;}/** * Look up if an SPM for a given name exists in the database. * * @param name The name of the SPM to look for. * * @return The ID of the SPM if success, SWR_SPM_INVALID_ID if error or not found. */swr_spc_id_t get_id(const char *name) { swr_spc_id_t id = SWR_SPM_INVALID_ID; database_entry_t **entry; database_entry_t **first = &database->entries[0]; database_entry_t **beyond = &database->entries[DB_SIZE]; if (!name) { PR_DBG(0, "name == NULL\n"); return SWR_SPM_INVALID_ID; } for (entry = first; entry < beyond && id == SWR_SPM_INVALID_ID; entry++) { if (*entry && !strncmp((*entry)->name, name, SWR_CDB_MAX_NAME_LENGTH)) { id = (*entry)->desc->id; return id; } } return SWR_SPM_INVALID_ID;}int cdb_get_name(swr_spc_id_t id, char *buffer) {#ifndef FAST if (!validate_id(id)) { PR_DBG(0, "ID not valid\n"); return -1; } if (!buffer) { PR_DBG(0, "buffer for name is NULL\n"); return -2; }#endif strncpy(buffer, database->entries[INDEX(id)]->name, SWR_CDB_MAX_NAME_LENGTH); return 0;}/** * Get all IDs from the CDB * * @param buffer The buffer where the IDs will be written. * * @return nbr The number of IDs which fit in the buffer. * * @return The number of IDs which has been written, or a negative * number in case of an error. */int get_all_ids(swr_spc_id_t *buffer, int nbr) { database_entry_t **cur_entry, **beyond_entry = database->entries + DB_SIZE; swr_spc_id_t *cur_id = buffer, *beyond_id = buffer + nbr; if (!buffer) { PR_DBG(0, "buffer == NULL\n"); return -1; } for (cur_entry = database->entries; cur_entry < beyond_entry && cur_id < beyond_id; cur_entry++) { if (*cur_entry) { *cur_id++ = (*cur_entry)->desc->id; } } return cur_id - buffer;}/** * Create database entry * * @return A pointer to the newly created database entry. */database_entry_t *create_database_entry(void) { return (database_entry_t *)swr_malloc(sizeof(database_entry_t));}/** * Add database entry * * @param desc A pointer to the SPM description which should be added * to the database. * * */swr_spc_id_t add_database_entry(swr_spc_desc_t **desc, const char *name) { database_entry_t *entry; if (!desc) { PR_DBG(0, "desc == NULL -> give me the address of your pointer!\n"); return SWR_SPM_INVALID_ID; } if (!*desc) { PR_DBG(0, "*desc == NULL -> nothing to register\n"); return SWR_SPM_INVALID_ID; } // If now an error occurs, desc has to be cleaned up if (!description_complete(*desc)) { PR_DBG(0, "The description is not complete yet, I do not take it.\n"); goto cleanup_desc; } if (!name) { PR_DBG(0, "name == NULL\n"); goto cleanup_desc; } if (get_id(name) != SWR_SPM_INVALID_ID) { PR_DBG(0, "A module named '%s' does already exist, registration failed\n", name ); goto cleanup_desc; } if (get_new_id(&(*desc)->id)) { PR_DBG(0, "Couldn't get new ID\n"); goto cleanup_desc; } entry = create_database_entry(); if (!entry) { PR_DBG(0, "Couldn't create entry\n"); goto cleanup_desc; } entry->desc = *desc; entry->refs = 0; strncpy(entry->name, name, SWR_CDB_MAX_NAME_LENGTH); database->entries[INDEX(entry->desc->id)] = entry; database->nbr_spms++; return (*desc)->id;cleanup_desc: free_spc_desc(*desc); *desc = NULL; return SWR_SPM_INVALID_ID;}/** * Remove database entry * * @param id The ID of the database entry which should be removed. * * @return 0 if success, a negative number if error. */int remove_database_entry(swr_spc_id_t id) { database_entry_t *entry; if (!validate_id(id)) { PR_DBG(0, "ID not valid\n"); return -1; } entry = database->entries[INDEX(id)]; if (entry->refs != 0) { PR_DBG(0, "still active references, not removing SPM %s\n", entry->name ); return -3; } if (free_spc_desc((swr_spc_desc_t *)entry->desc)) { PR_DBG(0, "fatal error while freeing desc\n"); return -4; } if (swr_free(entry)) { PR_DBG(0, "Fatal error while freeing entry\n"); return -5; } database->entries[INDEX(id)] = NULL; database->nbr_spms--; return 0;}/** * Get a reference to a SPM */int cdb_get_reference(const swr_spc_desc_t **ref, swr_spc_id_t id) { if (!validate_id(id)) { PR_DBG(0, "the specified ID is not valid\n"); return -1; } // id is valid database->entries[INDEX(id)]->refs++; *ref = database->entries[INDEX(id)]->desc; return 0;}/** * Free a reference to a SPM */int cdb_free_reference(const swr_spc_desc_t **ref) { swr_spc_id_t id; if (!ref) { PR_DBG(0, "ref points to NULL\n"); return -1; } if (!*ref) { PR_DBG(0, "*ref points to NULL\n"); return -2; } // ref is not NULL, so take the ID: id = ((swr_spc_desc_t *)*ref)->id; if (!validate_id(id)) { PR_DBG(0, "ID of returned reference not valid!\n"); return -3; } if (database->entries[INDEX(id)]->refs == 0) { PR_DBG(0, "Can't free reference 'cause refs already == 0\n"); return -4; } database->entries[INDEX(id)]->refs--; *ref = NULL; return 0;}//-------------------------------------------------------------------//// INTERFACE FUNCTIONS////-------------------------------------------------------------------/** * Get an empty SPM description. Space for all arrays is already * allocated, but the actual values have still to be filled out. */swr_spc_desc_t *swr_spc_get_new_desc(int nbr_inputs, int nbr_outputs, int nbr_config_params, int nbr_stats_params) { return create_spc_desc(nbr_inputs, nbr_outputs, nbr_config_params, nbr_stats_params);}/** * Free an SPM description. This should only be used with unregistered * descriptions which have been explicitely allocated with * swr_get_new_spc_desc(). */int swr_spc_free_desc(swr_spc_desc_t *desc) { return free_spc_desc(desc);}/** * Register a SPM in the database. The description has to be filled * out. */swr_spc_id_t swr_cdb_register_spc(swr_spc_desc_t** desc, const char *name) { swr_spc_id_t id; pthread_mutex_lock(&database->mutex); id = add_database_entry(desc, name); pthread_mutex_unlock(&database->mutex); if (id == SWR_SPM_INVALID_ID) PR_DBG(0, "module not registered\n"); return id;}/** * Unregister a SPM from the database. */int swr_cdb_unregister_spc(swr_spc_id_t id) { int error; pthread_mutex_lock(&database->mutex); error = remove_database_entry(id); pthread_mutex_unlock(&database->mutex); if (error) { PR_DBG(0, "Couldn't unregister SPM\n"); return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -