From f923add0a9b6bd17d43f72c21eec4e01e19240cf Mon Sep 17 00:00:00 2001 From: zilio nicolas Date: Tue, 7 Jul 2015 11:12:52 +0200 Subject: clean version for locks --- dma/ipe.h | 1 + pcilib/CMakeLists.txt | 4 +- pcilib/kmem.h | 1 + pcilib/lock.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ pcilib/lock.h | 55 ++++++++++++++++++++++++ pcilib/locking.c | 74 ++++++++++++++++++++++++++++++++ pcilib/locking.h | 44 +++++++++++++++++++ pcilib/pci.c | 8 ++++ pcilib/pci.h | 2 +- pcitool/cli.c | 17 ++++++-- protocols/software.c | 41 +++++++++++++----- 11 files changed, 346 insertions(+), 17 deletions(-) create mode 100644 pcilib/lock.c create mode 100644 pcilib/lock.h create mode 100644 pcilib/locking.c create mode 100644 pcilib/locking.h diff --git a/dma/ipe.h b/dma/ipe.h index 5640606..021e5a4 100644 --- a/dma/ipe.h +++ b/dma/ipe.h @@ -79,6 +79,7 @@ static const pcilib_register_description_t ipe_dma_registers[] = { {0x005C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_addr", "Number of descriptors configured"}, {0x0060, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_thresh", "Update threshold of progress register"}, {0x0000, 0, 32, PCILIB_VERSION, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMACONF, "dma_version", "Version of DMA engine"}, + {0x005, 0, 32, PCILIB_VERSION, 0x00000040, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMACONF, "test", "testdesc"}, {0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL} }; #endif /* _PCILIB_EXPORT_C */ diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index c9bf0fb..ebb5cec 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -3,8 +3,8 @@ include_directories( ${CMAKE_SOURCE_DIR}/pcilib ) -set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h kmem.h irq.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h) -add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c kmem.c irq.c dma.c event.c plugin.c tools.c error.c debug.c env.c) +set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h kmem.h irq.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h locking.h lock.h) +add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c kmem.c irq.c dma.c event.c plugin.c tools.c error.c debug.c env.c locking.c lock.c) target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS}) add_dependencies(pcilib dma protocols) diff --git a/pcilib/kmem.h b/pcilib/kmem.h index 8299379..65bdf04 100644 --- a/pcilib/kmem.h +++ b/pcilib/kmem.h @@ -31,6 +31,7 @@ typedef enum { PCILIB_KMEM_USE_DMA_RING = 1, PCILIB_KMEM_USE_DMA_PAGES = 2, PCILIB_KMEM_USE_SOFTWARE_REGISTERS = 3, + PCILIB_KMEM_USE_MUTEXES = 4, PCILIB_KMEM_USE_USER = 0x10 } pcilib_kmem_use_t; diff --git a/pcilib/lock.c b/pcilib/lock.c new file mode 100644 index 0000000..8715d21 --- /dev/null +++ b/pcilib/lock.c @@ -0,0 +1,116 @@ +#define _GNU_SOURCE +#define _XOPEN_SOURCE 600 + +#include +#include +#include "error.h" +#include "lock.h" +#include "pci.h" + +/* + * this function will take the lock for the semaphore pointed by semId + */ +void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ + int err; + struct timespec *time; + va_list pa; + va_start(pa,flags); + + if(flags & MUTEX_LOCK){ + err=pthread_mutex_lock(lock_ctx);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + /** if the lock haven't been acquired and errno==EOWNERDEAD, it means the previous application that got the lock crashed, we have to remake the lock "consistent" so*/ + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_lock(lock_ctx); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + } + } + else if(flags & MUTEX_TRYLOCK){ + err=pthread_mutex_trylock(lock_ctx);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_lock(lock_ctx); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + } + } + else if(flags & MUTEX_TIMEDLOCK){ + time=va_arg(pa,struct timespec*); + va_end(pa); + err=pthread_mutex_timedlock(lock_ctx, time);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_timedlock(lock_ctx, time); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)), errno); + } + } + else pcilib_error("wrong flag for pcilib_lock"); +} + +/** + * this function will unlock the semaphore pointed by lock_ctx. + */ +void pcilib_unlock(pcilib_lock_t* lock_ctx){ + int err; + if((err=pthread_mutex_unlock(lock_ctx))!=0) pcilib_error("can't unlock semaphore\n"); +} + +/** + * pcilib_init_lock + * this function initialize a new semaphore in the kernel if it's not already initialized given the key that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore + * @param[out] lock_ctx the pointer that will points to the semaphore for other functions + * @param[in] keysem the integer that permits to define to what the semaphore is attached + */ +pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, char* lock_id, ...){ + int err; + pthread_mutexattr_t attr; + int i,j; + void* addr,*locks_addr; + va_list pa; + va_start(pa,lock_id); + + pcilib_lock_init_flags_t flag; + flag=va_arg(pa,pcilib_lock_init_flags_t); + va_end(pa); + + if(strlen(lock_id)>PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)) pcilib_error("the entered protocol name is too long"); + if(((PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)%PCILIB_KMEM_PAGE_SIZE)!=0) pcilib_error("PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE should be a multiple of kmem page size"); + + addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,0); + if(flag & LOCK_INIT) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); + /* we search for the given lock if it was already initialized*/ + for(j=0;jlocks_handle,j); + while((*(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t))!=0) && (i +#include +#include "lock.h" + +/* + * this function clean all locks created by the pcitool program + */ +void pcilib_clean_all_locks(pcilib_t* ctx){ +int i,j; +void* addr; + i=0; + while(ilocks_handle,i); +for(j=0;jlocks_handle,PCILIB_KMEM_FLAG_REUSE); +} + +/* + * this function allocates the kernel memory for the locks for software registers + */ +int pcilib_init_locking(pcilib_t* ctx, ...){ +/*for future possible more args + va_list pa; + va_start(pa,ctx);*/ + pcilib_kmem_handle_t *handle; + int err; + pcilib_kmem_reuse_state_t reused; + + + if((err=flock(ctx->handle,LOCK_EX))==-1) pcilib_warning("can't get flock on /dev/fpga0"); + handle=pcilib_alloc_kernel_memory(ctx,PCILIB_KMEM_TYPE_PAGE,PCILIB_NUMBER_OF_LOCK_PAGES,PCILIB_KMEM_PAGE_SIZE,0,PCILIB_KMEM_USE(PCILIB_KMEM_USE_MUTEXES,0),PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); + + if (!handle) { + pcilib_error("Allocation of kernel memory for mutexes has failed"); + return 1; + } + + ctx->locks_handle=handle; + reused = pcilib_kmem_is_reused(ctx, handle); +//#define DEBUG_REUSE +#ifdef DEBUG_REUSE +reused=0; +#endif + if ((reused & PCILIB_KMEM_REUSE_REUSED) == 0) { + pcilib_register_t i; + + if (reused & PCILIB_KMEM_REUSE_PARTIAL) { + pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); + pcilib_clean_all_locks(ctx); + return 1; + } + for(i=0;ihandle,LOCK_UN))==-1) pcilib_warning("could not remove lock correctly on /dev/fpga0"); + + return 0; +} diff --git a/pcilib/locking.h b/pcilib/locking.h new file mode 100644 index 0000000..f7570f6 --- /dev/null +++ b/pcilib/locking.h @@ -0,0 +1,44 @@ +/** + * @file lock_global.h + * @brief this file is the header file for functions that touch all locks allocated for software registers. + * @details for more details about implementation choice, please read the file lock.h + */ +#define _XOPEN_SOURCE 700 + +#ifndef _LOCKING_ +#define _LOCKING_ + +#include + +/** number of maximum locks*/ +#define PCILIB_MAX_NUMBER_LOCKS 64 + +/**size of one lock, determine so the size of the protocol_name in the way locks are registered. 40 bytes are necessary for the mutex structure, so we have a protocol name of length LOCK_SIZE-40*/ +#define PCILIB_LOCK_SIZE 128 + +#define PCILIB_LOCKS_PER_PAGE PCILIB_KMEM_PAGE_SIZE/PCILIB_LOCK_SIZE + +#define PCILIB_NUMBER_OF_LOCK_PAGES (PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)/PCILIB_KMEM_PAGE_SIZE + + +/** +* new type to define a semaphore. It was made to differentiate from the library type. +*/ +typedef pthread_mutex_t pcilib_lock_t; + +/** + * this function destroy all locks created + *@param[in] ctx, the pcilib_t running + */ +void pcilib_clean_all_locks(pcilib_t* ctx); + +/** +* this function initialize the kmem pages containing locks +*@param[in] ctx the pcilib_t running +*/ +int pcilib_init_locking(pcilib_t* ctx, ...); + + +void pcilib_free_all_locks(pcilib_t* ctx); + +#endif /* _LOCK_GLOBAL_ */ diff --git a/pcilib/pci.c b/pcilib/pci.c index 3a18ccd..c7b86e8 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -1,4 +1,5 @@ //#define PCILIB_FILE_IO +#define _XOPEN_SOURCE 700 #define _BSD_SOURCE #define _POSIX_C_SOURCE 200809L @@ -24,6 +25,7 @@ #include "model.h" #include "plugin.h" #include "bar.h" +#include "locking.h" static int pcilib_detect_model(pcilib_t *ctx, const char *model) { int i, j; @@ -159,6 +161,12 @@ pcilib_t *pcilib_open(const char *device, const char *model) { ctx->model_info.protocols = ctx->protocols; ctx->model_info.ranges = ctx->ranges; + err=pcilib_init_locking(ctx); + if (err) { + pcilib_error("Error (%i) initializing locking\n", err); + pcilib_close(ctx); + return NULL; + } err = pcilib_init_register_banks(ctx); if (err) { diff --git a/pcilib/pci.h b/pcilib/pci.h index d176caf..a7b3d50 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -69,7 +69,7 @@ struct pcilib_s { pcilib_register_bank_context_t *bank_ctx[PCILIB_MAX_REGISTER_BANKS]; /**< Contexts for registers banks if required by register protocol */ pcilib_dma_context_t *dma_ctx; /**< DMA context */ pcilib_context_t *event_ctx; /**< Implmentation context */ - + void* locks_handle; /**< adress of the kernel memory use for locks from user space*/ #ifdef PCILIB_FILE_IO int file_io_handle; #endif /* PCILIB_FILE_IO */ diff --git a/pcitool/cli.c b/pcitool/cli.c index 9eeb046..a6224e3 100644 --- a/pcitool/cli.c +++ b/pcitool/cli.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 200112L #define _BSD_SOURCE @@ -37,6 +38,7 @@ #include "error.h" #include "debug.h" #include "model.h" +#include "locking.h" /* defines */ #define MAX_KBUF 14 @@ -89,7 +91,8 @@ typedef enum { MODE_ALLOC_KMEM, MODE_LIST_KMEM, MODE_READ_KMEM, - MODE_FREE_KMEM + MODE_FREE_KMEM, + MODE_FREE_LOCKS } MODE; typedef enum { @@ -167,7 +170,8 @@ typedef enum { OPT_VERIFY, OPT_WAIT, OPT_MULTIPACKET, - OPT_VERBOSE + OPT_VERBOSE, + OPT_FREE_LOCKS } OPTIONS; static struct option long_options[] = { @@ -219,6 +223,7 @@ static struct option long_options[] = { {"multipacket", no_argument, 0, OPT_MULTIPACKET }, {"wait", no_argument, 0, OPT_WAIT }, {"help", no_argument, 0, OPT_HELP }, + {"free-locks", no_argument, 0, OPT_FREE_LOCKS}, { 0, 0, 0, 0 } }; @@ -272,6 +277,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " block is specified as: use:block_number\n" " --alloc-kernel-memory - Allocate kernel buffers (DANGEROUS)\n" " --free-kernel-memory - Cleans lost kernel space buffers (DANGEROUS)\n" +" --free-locks - Cleans locks allocated during pcitool program use(dangerous in a concurrential model)\n" " dma - Remove all buffers allocated by DMA subsystem\n" " #number - Remove all buffers with the specified use id\n" "\n" @@ -2570,6 +2576,9 @@ int main(int argc, char **argv) { event = stmp; } break; + case OPT_FREE_LOCKS: + mode=MODE_FREE_LOCKS; + break; case OPT_TRIGGER: if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_TRIGGER))) Usage(argc, argv, "Multiple operations are not supported"); @@ -2949,7 +2958,6 @@ int main(int argc, char **argv) { model_info = pcilib_get_model_description(handle); dma_info = pcilib_get_dma_description(handle); - switch (mode) { case MODE_WRITE: if (((argc - optind) == 1)&&(*argv[optind] == '*')) { @@ -3137,6 +3145,9 @@ int main(int argc, char **argv) { } switch (mode) { + case MODE_FREE_LOCKS: + pcilib_clean_all_locks(handle); + break; case MODE_INFO: Info(handle, model_info); break; diff --git a/protocols/software.c b/protocols/software.c index 5534dc7..5170583 100644 --- a/protocols/software.c +++ b/protocols/software.c @@ -1,38 +1,44 @@ +#define _XOPEN_SOURCE 700 + #include #include #include #include #include - #include "model.h" #include "error.h" #include "kmem.h" #include "pcilib.h" #include "pci.h" +#include "lock.h" typedef struct pcilib_software_register_bank_context_s pcilib_software_register_bank_context_t; +/** + * new context to save all needed informations for software registers + */ struct pcilib_software_register_bank_context_s { - pcilib_register_bank_context_t bank_ctx; + pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers*/ - pcilib_kmem_handle_t *kmem; - void *addr; + pcilib_kmem_handle_t *kmem; /**< the kernel memory for software registers */ + void *addr; /**< the base adress of the allocated kernel memory*/ }; /** * pcilib_software_registers_close * this function clear the kernel memory space that could have been allocated for software registers + *@param[in] ctx the pcilib_t running * @param[in] bank_ctx the bank context running that we get from the initialisation function */ void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx) { if (((pcilib_software_register_bank_context_t*)bank_ctx)->kmem) - pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE); + pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE); free(bank_ctx); } /** * pcilib_software_registers_open - * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. It the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used + * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. If the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used. The initialization is protected by the locking mechanisms of lock files. * @param[in] ctx the pcilib_t structure running * @param[in] bank the bank index that will permits to get the bank we want registers from * @param[in] model not used @@ -43,6 +49,7 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc pcilib_software_register_bank_context_t *bank_ctx; pcilib_kmem_handle_t *handle; pcilib_kmem_reuse_state_t reused; + pcilib_lock_t* semId=NULL; const pcilib_register_bank_description_t *bank_desc = ctx->banks + bank; @@ -52,8 +59,12 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc } bank_ctx = calloc(1, sizeof(pcilib_software_register_bank_context_t)); + + /* prtoection against several kernel memory allocation*/ + semId=pcilib_init_lock(ctx,"thisatest2"); + pcilib_lock(semId,MUTEX_LOCK); - handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); + handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); /**< get the kernel memory*/ if (!handle) { pcilib_error("Allocation of kernel memory for software registers has failed"); pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); @@ -75,11 +86,18 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc for (i = 0; ctx->model_info.registers[i].name != NULL; i++) { if ((ctx->model_info.registers[i].bank == ctx->banks[bank].addr)&&(ctx->model_info.registers[i].type == PCILIB_REGISTER_STANDARD)) { - *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue; + + /*initialization here*/ + + *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue; + + + } } } - + pcilib_unlock(semId); + return (pcilib_register_bank_context_t*)bank_ctx; } @@ -93,11 +111,12 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc * @return 0 in case of success */ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value){ + if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) { pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } - + /* the following reading is considered atomic operation, so not protected, may change*/ *value = *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr); return 0; } @@ -116,7 +135,7 @@ int pcilib_software_registers_write(pcilib_t *ctx, pcilib_register_bank_context_ pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } - + /* the following writing is considered atomic operation, so not protected, may change*/ *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr) = value; return 0; } -- cgit v1.2.3 From fe821c4f1b85d2a2d358da098f85327d41212dc3 Mon Sep 17 00:00:00 2001 From: zilio nicolas Date: Tue, 7 Jul 2015 15:38:14 +0200 Subject: modified for last remarks --- pcilib/lock.c | 40 ++++++++++++++++++++++------------------ pcilib/locking.c | 4 ++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/pcilib/lock.c b/pcilib/lock.c index 8715d21..b99ecfc 100644 --- a/pcilib/lock.c +++ b/pcilib/lock.c @@ -6,7 +6,7 @@ #include "error.h" #include "lock.h" #include "pci.h" - +#include /* * this function will take the lock for the semaphore pointed by semId */ @@ -18,32 +18,32 @@ void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ if(flags & MUTEX_LOCK){ err=pthread_mutex_lock(lock_ctx);/**< we try to lock here*/ - if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); /** if the lock haven't been acquired and errno==EOWNERDEAD, it means the previous application that got the lock crashed, we have to remake the lock "consistent" so*/ else if(errno==EOWNERDEAD){ pthread_mutex_consistent(lock_ctx); pthread_mutex_lock(lock_ctx); - if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + if(err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); } } else if(flags & MUTEX_TRYLOCK){ err=pthread_mutex_trylock(lock_ctx);/**< we try to lock here*/ - if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); else if(errno==EOWNERDEAD){ pthread_mutex_consistent(lock_ctx); pthread_mutex_lock(lock_ctx); - if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + if(err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); } } else if(flags & MUTEX_TIMEDLOCK){ time=va_arg(pa,struct timespec*); va_end(pa); err=pthread_mutex_timedlock(lock_ctx, time);/**< we try to lock here*/ - if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, errni %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); else if(errno==EOWNERDEAD){ pthread_mutex_consistent(lock_ctx); pthread_mutex_timedlock(lock_ctx, time); - if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)), errno); + if(err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)), errno); } } else pcilib_error("wrong flag for pcilib_lock"); @@ -54,7 +54,7 @@ void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ */ void pcilib_unlock(pcilib_lock_t* lock_ctx){ int err; - if((err=pthread_mutex_unlock(lock_ctx))!=0) pcilib_error("can't unlock semaphore\n"); + if((err=pthread_mutex_unlock(lock_ctx))!=0) pcilib_error("can't unlock mutex: errno %i",errno); } /** @@ -71,21 +71,25 @@ pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, char* lock_id, ...){ va_list pa; va_start(pa,lock_id); + char* temp; + temp=malloc((strlen(lock_id)+strlen("bank_register_"))*sizeof(char)); + sprintf(temp,"bank_register_%s",lock_id); + pcilib_lock_init_flags_t flag; flag=va_arg(pa,pcilib_lock_init_flags_t); va_end(pa); - if(strlen(lock_id)>PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)) pcilib_error("the entered protocol name is too long"); + if(strlen(temp)>PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)) pcilib_error("the entered protocol name is too long"); if(((PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)%PCILIB_KMEM_PAGE_SIZE)!=0) pcilib_error("PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE should be a multiple of kmem page size"); addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,0); - if(flag & LOCK_INIT) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); + if((flag & LOCK_INIT)==0) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); /* we search for the given lock if it was already initialized*/ for(j=0;jlocks_handle,j); while((*(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t))!=0) && (ilocks_handle=handle; reused = pcilib_kmem_is_reused(ctx, handle); -//#define DEBUG_REUSE + #define DEBUG_REUSE #ifdef DEBUG_REUSE reused=0; #endif @@ -57,7 +57,7 @@ reused=0; pcilib_register_t i; if (reused & PCILIB_KMEM_REUSE_PARTIAL) { - pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); + pcilib_error("Inconsistent memory for locks was found (only part of required buffers is available)"); pcilib_clean_all_locks(ctx); return 1; } -- cgit v1.2.3 From edd5ccf24c146915ee475bd223e2ad695520a241 Mon Sep 17 00:00:00 2001 From: zilio nicolas Date: Fri, 10 Jul 2015 10:52:06 +0200 Subject: last modification+comments update --- pcilib/lock.c | 32 ++++++++++++++------------------ pcilib/lock.h | 25 +++++++++++++++++-------- pcilib/locking.c | 15 +++++++++++---- pcilib/locking.h | 7 ++++++- protocols/software.c | 2 +- 5 files changed, 49 insertions(+), 32 deletions(-) diff --git a/pcilib/lock.c b/pcilib/lock.c index b99ecfc..b92b11d 100644 --- a/pcilib/lock.c +++ b/pcilib/lock.c @@ -7,6 +7,7 @@ #include "lock.h" #include "pci.h" #include + /* * this function will take the lock for the semaphore pointed by semId */ @@ -21,6 +22,7 @@ void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); /** if the lock haven't been acquired and errno==EOWNERDEAD, it means the previous application that got the lock crashed, we have to remake the lock "consistent" so*/ else if(errno==EOWNERDEAD){ + /* one question is "is pthread_mutex_consistent protected in case we call twice it?", it seems to not make any importance in fact regarding man pages, but we have to survey it in future applications*/ pthread_mutex_consistent(lock_ctx); pthread_mutex_lock(lock_ctx); if(err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); @@ -31,7 +33,7 @@ void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); else if(errno==EOWNERDEAD){ pthread_mutex_consistent(lock_ctx); - pthread_mutex_lock(lock_ctx); + pthread_mutex_trylock(lock_ctx); if(err!=0) pcilib_error("can't acquire lock %s, errno %i",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); } } @@ -58,43 +60,37 @@ void pcilib_unlock(pcilib_lock_t* lock_ctx){ } /** - * pcilib_init_lock * this function initialize a new semaphore in the kernel if it's not already initialized given the key that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore - * @param[out] lock_ctx the pointer that will points to the semaphore for other functions - * @param[in] keysem the integer that permits to define to what the semaphore is attached */ -pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, char* lock_id, ...){ +pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, pcilib_lock_init_flags_t flag, char* lock_id, ...){ int err; pthread_mutexattr_t attr; int i,j; void* addr,*locks_addr; + char buffer[PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)]; + /* here lock_id is the format string for vsprintf, the lock name will so be put in adding arguments*/ va_list pa; va_start(pa,lock_id); - - char* temp; - temp=malloc((strlen(lock_id)+strlen("bank_register_"))*sizeof(char)); - sprintf(temp,"bank_register_%s",lock_id); - - pcilib_lock_init_flags_t flag; - flag=va_arg(pa,pcilib_lock_init_flags_t); + err=vsprintf(buffer,lock_id,pa); va_end(pa); - if(strlen(temp)>PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)) pcilib_error("the entered protocol name is too long"); + if(err<0) pcilib_error("error in obtaining the lock name"); if(((PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)%PCILIB_KMEM_PAGE_SIZE)!=0) pcilib_error("PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE should be a multiple of kmem page size"); addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,0); - if((flag & LOCK_INIT)==0) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); + if((flag & PCILIB_NO_LOCK)==0) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); /* we search for the given lock if it was already initialized*/ for(j=0;jlocks_handle,j); while((*(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t))!=0) && (ilocks_handle,i); for(j=0;jlocks_handle,PCILIB_KMEM_FLAG_REUSE); @@ -38,8 +42,9 @@ int pcilib_init_locking(pcilib_t* ctx, ...){ int err; pcilib_kmem_reuse_state_t reused; - + /* we flock() to make sure to not have two initialization in the same time (possible long time to init)*/ if((err=flock(ctx->handle,LOCK_EX))==-1) pcilib_warning("can't get flock on /dev/fpga0"); + handle=pcilib_alloc_kernel_memory(ctx,PCILIB_KMEM_TYPE_PAGE,PCILIB_NUMBER_OF_LOCK_PAGES,PCILIB_KMEM_PAGE_SIZE,0,PCILIB_KMEM_USE(PCILIB_KMEM_USE_MUTEXES,0),PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); if (!handle) { @@ -49,10 +54,11 @@ int pcilib_init_locking(pcilib_t* ctx, ...){ ctx->locks_handle=handle; reused = pcilib_kmem_is_reused(ctx, handle); - #define DEBUG_REUSE +//#define DEBUG_REUSE #ifdef DEBUG_REUSE reused=0; #endif +/* verification about the handling memory got, first use or not, and integrity*/ if ((reused & PCILIB_KMEM_REUSE_REUSED) == 0) { pcilib_register_t i; @@ -61,10 +67,11 @@ reused=0; pcilib_clean_all_locks(ctx); return 1; } + /* if we get here so this is the first initialization (after some free or new), we so set kernel pages to 0 and initialize then the first lock that will be used when we create other locks*/ for(i=0;iname,"software_register"); pcilib_lock(semId,MUTEX_LOCK); handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); /**< get the kernel memory*/ -- cgit v1.2.3