summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pcilib/lock.c32
-rw-r--r--pcilib/lock.h25
-rw-r--r--pcilib/locking.c15
-rw-r--r--pcilib/locking.h7
-rw-r--r--protocols/software.c2
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 <stdio.h>
+
/*
* 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;j<PCILIB_NUMBER_OF_LOCK_PAGES;j++){
i=0;
locks_addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,j);
while((*(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t))!=0) && (i<PCILIB_LOCKS_PER_PAGE)){
- if(strcmp(temp,(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)))==0){
+ if(strcmp(buffer,(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)))==0){
return (pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE);}
i++;
}
if(i<PCILIB_LOCKS_PER_PAGE) break;
}
+ /* the kernel space could be full*/
if(i==PCILIB_LOCKS_PER_PAGE) pcilib_error("no more free space for a new lock\n");
/* if not, we create a new one*/
if((err= pthread_mutexattr_init(&attr))!=0) pcilib_error("can't initialize mutex attribute, errno %i",errno);
@@ -103,15 +99,15 @@ pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, char* lock_id, ...){
if((err=pthread_mutex_init((pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE),&attr))!=0) pcilib_error("can't set attributes to mutex, errno : %i",errno);
pthread_mutexattr_destroy(&attr);
- strcpy((char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)),temp);
+ strcpy((char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)),buffer);
- if((flag & LOCK_INIT)==0) pcilib_unlock((pcilib_lock_t*)addr);
+ if((flag & PCILIB_NO_LOCK)==0) pcilib_unlock((pcilib_lock_t*)addr);
return (pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE);
}
/*
- * pcilib_lock_free does nothing for now, as we don't want to erase possible locks in the kernel memory (or at any erasing, we should rearrange the locks to have no free space between locks). A thing i think of would be to use chained lists in kernel memory, but how?
+ * we uninitialize a mutex and set its name to 0 pointed by lock_ctx with this function. setting name to is the real destroying operation, but we need to unitialize the lock to initialize it again after
*/
void pcilib_free_lock(pcilib_lock_t *lock_ctx){
int err;
diff --git a/pcilib/lock.h b/pcilib/lock.h
index 53da543..ec69737 100644
--- a/pcilib/lock.h
+++ b/pcilib/lock.h
@@ -5,21 +5,29 @@
* @details the use of pthread robust mutexes was chosen due to the fact we privilege security over fastness, and that pthread mutexes permits to recover semaphores even with crash ,and that it does not require access to resources that can be easily accessible from extern usage as flock file locking mechanism. A possible other locking mechanism could be the sysv semaphores, but we have a problem of how determine a perfect hash for the init function, and more, benchmarks proves that sysv semaphore aren't that stable and that with more than 10 locks/unlocks, pthread is better in performance, so that should suits more to the final pcitool program.
* We considered that mutex implmentation is enough compared to a reader/writer implementation. If it should change, please go to sysv semaphore.
* Basic explanation on how semaphores here work: a semaphore here is a positive integer, thus that can't go below zero, which is initiated with a value. when a process want access to the critical resource, it asks to decrement the value of the semaphore, and when it has finished, it reincrements it.basically, when the semaphore is equal to zero, any process must have to wait for it to be reincremented before decrementing it again. Here are defined two types of access to the semaphore corresponding to the reader/writer problem : an exclusive lock, which means that no other process than the one who have the resource can access it; a shared lock, which means that other processes who want to access to the resource with a shared lock can have the access, but a concurrent process who want to access the semaphore with an exclusive lock won't be able to.
+ * explanation on locks here : here locks are registered in kernel memory, where they are defined by a pthread_mutex_t and a name, which corresponds to a register or processus. The iterations like searching a lock are done on names.
*/
#ifndef _LOCK_
#define _LOCK_
-#include "locking.h"
+#include "lock_global.h"
+/**
+ * type that defines possible flags when locking a lock by calling pcilib_lock
+ */
typedef enum{
MUTEX_LOCK=1,
MUTEX_TRYLOCK=2,
MUTEX_TIMEDLOCK=4
} pcilib_lock_flags_t;
+/**
+ * type that defines flags for the pcilib_init function
+ */
typedef enum{
- LOCK_INIT=16
+ PCILIB_LOCK=0,
+ PCILIB_NO_LOCK=16
}pcilib_lock_init_flags_t;
@@ -27,27 +35,28 @@ typedef enum{
/**
* this function initialize a new semaphore in the kernel given a name that corresponds to a specific processus if the semaphore is not already initialized given the name 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[in] ctx the pcilib_t running
- * @param[in] id_protocol_name the name of the protocol that permits to define to what the semaphore is attached. It suppose that there is one semaphore by protocol, but if it's not the case, create one semaphore by each sub-protocol name.
+ * @param [in] flag the flag that let(s us to know if we have to lock during the creation of a new lock
+ * @param[in] lock_id the format string that will contains the supplement args
*@return a mutex for the given protocol name
*/
-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, ...);
/**
- * this function does nothing for the moment, as we don't want to destroy the locks put in kernel memory.
- * @param[in] lock_ctx the pointer that points to the semaphore set.
+ * this function uninitialize a lock in kernel memory and set the corresponding name to 0
+ * @param[in] lock_ctx the pointer that points to the lock.
*/
void pcilib_free_lock(pcilib_lock_t *lock_ctx);
/**
* this function will take a lock for the mutex pointed by lock_ctx
* @param[in] lock_ctx the pointer to the mutex
- * @param[in] lock_flags define the type of lock wanted : MUTEX_LOCK (normal lock), MUTEX_TRYLOCK (will return if it can't acquire lock), MUTEX_TIMEDLOCK (will wait if it can't acquire lock for a given time, after it returns)
+ * @param[in] lock_flags define the type of lock wanted : MUTEX_LOCK (normal lock), MUTEX_TRYLOCK (will return if it can't acquire lock), MUTEX_TIMEDLOCK (will wait if it can't acquire lock for a given time, after it returns) and in this last case, we need to provide a timespec structure as supplementary argument
*
*/
void pcilib_lock(pcilib_lock_t* lock_ctx,pcilib_lock_flags_t flags, ...);
/**
- * this function will unlock the semaphore pointed by lock_ctx
+ * this function will unlock the lock pointed by lock_ctx
* @param[in] lock_ctx the integer that points to the semaphore
*/
void pcilib_unlock(pcilib_lock_t* lock_ctx);
diff --git a/pcilib/locking.c b/pcilib/locking.c
index 1d6b51e..cbe9533 100644
--- a/pcilib/locking.c
+++ b/pcilib/locking.c
@@ -7,12 +7,13 @@
#include "lock.h"
/*
- * this function clean all locks created by the pcitool program
+ * this function destroys all locks without touching at kernel memory directly
*/
void pcilib_clean_all_locks(pcilib_t* ctx){
int i,j;
void* addr;
i=0;
+ /* iteration on all locks*/
while(i<PCILIB_NUMBER_OF_LOCK_PAGES){
addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,i);
for(j=0;j<PCILIB_LOCKS_PER_PAGE;j++)
@@ -22,6 +23,9 @@ for(j=0;j<PCILIB_LOCKS_PER_PAGE;j++)
}
+/*
+ * this functions destroy all locks and then free the kernel memory allocated for them
+ */
void pcilib_free_locking(pcilib_t* ctx){
pcilib_clean_all_locks(ctx);
pcilib_free_kernel_memory(ctx,ctx->locks_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;i<PCILIB_NUMBER_OF_LOCK_PAGES;i++){
memset(pcilib_kmem_get_block_ua(ctx,handle,i),0,PCILIB_KMEM_PAGE_SIZE);
}
- pcilib_init_lock(ctx,"pcilib_locking",LOCK_INIT);
+ pcilib_init_lock(ctx,PCILIB_NO_LOCK,"%s","pcilib_first_locking");
}
diff --git a/pcilib/locking.h b/pcilib/locking.h
index f7570f6..3727380 100644
--- a/pcilib/locking.h
+++ b/pcilib/locking.h
@@ -16,8 +16,10 @@
/**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
+/** number of locks per page of kernel memory*/
#define PCILIB_LOCKS_PER_PAGE PCILIB_KMEM_PAGE_SIZE/PCILIB_LOCK_SIZE
+/** number of pages allocated for locks in kernel memory*/
#define PCILIB_NUMBER_OF_LOCK_PAGES (PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)/PCILIB_KMEM_PAGE_SIZE
@@ -38,7 +40,10 @@ void pcilib_clean_all_locks(pcilib_t* ctx);
*/
int pcilib_init_locking(pcilib_t* ctx, ...);
-
+/**
+ * this function destroys all locks and then free the kernel memory allocated for them before
+ * @param[in] ctx the pcilib_t running
+ */
void pcilib_free_all_locks(pcilib_t* ctx);
#endif /* _LOCK_GLOBAL_ */
diff --git a/protocols/software.c b/protocols/software.c
index 5170583..4b75277 100644
--- a/protocols/software.c
+++ b/protocols/software.c
@@ -61,7 +61,7 @@ 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");
+ semId=pcilib_init_lock(ctx,PCILIB_LOCK,"%s_%s",bank_desc->name,"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*/