123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- #define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #include "config.h"
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <assert.h>
- #include <pthread.h>
- #include <stdint.h>
- #ifdef HAVE_STDATOMIC_H
- # include <stdatomic.h>
- #endif /* HAVE_STDATOMIC_H */
- #include "error.h"
- #include "lock.h"
- #include "pci.h"
- /**
- * structure to define a lock
- */
- struct pcilib_lock_s {
- pthread_mutex_t mutex; /**< the pthread robust mutex */
- pcilib_lock_flags_t flags; /**< flags to define the type of the mutex */
- #ifdef HAVE_STDATOMIC_H
- volatile atomic_uint refs; /**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */
- #else /* HAVE_STDATOMIC_H */
- volatile uint32_t refs; /**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */
- #endif /* HAVE_STDATOMIC_H */
- char name[]; /**< lock identifier */
- };
- int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char *lock_id) {
- int err;
- pthread_mutexattr_t attr;
- assert(lock);
- assert(lock_id);
- memset(lock, 0, PCILIB_LOCK_SIZE);
- if (strlen(lock_id) >= (PCILIB_LOCK_SIZE - offsetof(struct pcilib_lock_s, name))) {
- pcilib_error("The supplied lock id (%s) is too long...", lock_id);
- return PCILIB_ERROR_INVALID_ARGUMENT;
- }
- if ((err = pthread_mutexattr_init(&attr))!=0) {
- pcilib_error("Can't initialize mutex attribute, errno %i", errno);
- return PCILIB_ERROR_FAILED;
- }
- /* we declare the mutex as possibly shared amongst different processes*/
- if ((err = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED))!=0) {
- pcilib_error("Can't configure a shared mutex attribute, errno %i", errno);
- return PCILIB_ERROR_FAILED;
- }
- /* we set the mutex as robust, so it would be automatically unlocked if the application crash*/
- if ((flags&PCILIB_LOCK_FLAG_PERSISTENT)==0) {
- if ((err = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST))!=0) {
- pcilib_error("Can't configure a robust mutex attribute, errno: %i", errno);
- return PCILIB_ERROR_FAILED;
- }
- }
- if ((err = pthread_mutex_init(&lock->mutex, &attr))!=0) {
- pcilib_error("Can't create mutex, errno : %i",errno);
- return PCILIB_ERROR_FAILED;
- }
- strcpy(lock->name, lock_id);
- lock->refs = 1;
- lock->flags = flags;
- return 0;
- }
- void pcilib_free_lock(pcilib_lock_t *lock) {
- int err;
- assert(lock);
- // if (lock->refs)
- // pcilib_error("Forbidding to destroy the referenced mutex...");
- if ((err = pthread_mutex_destroy(&lock->mutex))==-1)
- pcilib_warning("Can't destroy POSIX mutex, errno %i",errno);
- }
- void pcilib_lock_ref(pcilib_lock_t *lock) {
- assert(lock);
-
- #ifdef HAVE_STDATOMIC_H
- atomic_fetch_add_explicit(&lock->refs, 1, memory_order_relaxed);
- #else /* HAVE_STDATOMIC_H */
- lock->refs++;
- #endif /* HAVE_STDATOMIC_H */
- }
- void pcilib_lock_unref(pcilib_lock_t *lock) {
- assert(lock);
- if (!lock->refs) {
- pcilib_warning("Lock is not referenced");
- return;
- }
- #ifdef HAVE_STDATOMIC_H
- atomic_fetch_sub_explicit(&lock->refs, 1, memory_order_relaxed);
- #else /* HAVE_STDATOMIC_H */
- lock->refs--;
- #endif /* HAVE_STDATOMIC_H */
- }
- size_t pcilib_lock_get_refs(pcilib_lock_t *lock) {
- return lock->refs;
- }
- pcilib_lock_flags_t pcilib_lock_get_flags(pcilib_lock_t *lock) {
- return lock->flags;
- }
- const char *pcilib_lock_get_name(pcilib_lock_t *lock) {
- assert(lock);
- if (lock->name[0]) return lock->name;
- return NULL;
- }
- int pcilib_lock_custom(pcilib_lock_t *lock, pcilib_lock_flags_t flags, pcilib_timeout_t timeout) {
- int err;
- if (!lock) {
- pcilib_error("The null lock pointer is passed to lock function");
- return PCILIB_ERROR_INVALID_ARGUMENT;
- }
- struct timespec tm;
- switch (timeout) {
- case PCILIB_TIMEOUT_INFINITE:
- /* the process will be hold till it can gain acquire the lock*/
- err = pthread_mutex_lock(&lock->mutex);
- break;
- case PCILIB_TIMEOUT_IMMEDIATE:
- /* the function returns immediatly if it can't acquire the lock*/
- err = pthread_mutex_trylock(&lock->mutex);
- break;
- default:
- /* the process will be hold till it can acquire the lock and timeout is not reached*/
- clock_gettime(CLOCK_REALTIME, &tm);
- tm.tv_nsec += 1000 * (timeout%1000000);
- if (tm.tv_nsec < 1000000000)
- tm.tv_sec += timeout/1000000;
- else {
- tm.tv_sec += 1 + timeout/1000000;
- tm.tv_nsec -= 1000000000;
- }
- err = pthread_mutex_timedlock(&lock->mutex, &tm);
- }
- if (!err)
- return 0;
- switch (err) {
- case EOWNERDEAD:
- /*in the case an application with a lock acquired crashes, this lock becomes inconsistent. we have so to make it consistent again to use it again.*/
- err = pthread_mutex_consistent(&lock->mutex);
- if (err) {
- pcilib_error("Failed to mark mutex as consistent, errno %i", err);
- break;
- }
- return 0;
- case ETIMEDOUT:
- case EBUSY:
- return PCILIB_ERROR_TIMEOUT;
- default:
- pcilib_error("Failed to obtain mutex, errno %i", err);
- }
- return PCILIB_ERROR_FAILED;
- }
- int pcilib_lock(pcilib_lock_t* lock) {
- return pcilib_lock_custom(lock, PCILIB_LOCK_FLAGS_DEFAULT, PCILIB_TIMEOUT_INFINITE);
- }
- int pcilib_try_lock(pcilib_lock_t* lock) {
- return pcilib_lock_custom(lock, PCILIB_LOCK_FLAGS_DEFAULT, PCILIB_TIMEOUT_IMMEDIATE);
- }
- void pcilib_unlock(pcilib_lock_t *lock) {
- int err;
- if (!lock)
- return;
- if ((err = pthread_mutex_unlock(&lock->mutex)) != 0) {
- switch (err) {
- case EPERM:
- pcilib_error("Trying to unlock not locked mutex (%s) or the mutex which was locked by a different thread", lock->name);
- break;
- default:
- pcilib_error("Can't unlock mutex, errno %i", err);
- }
- }
- }
|