/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
277.1.1 by zilio nicolas
clean version for locks
1
#define _GNU_SOURCE
2
#define _XOPEN_SOURCE 600
3
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
4
#include "config.h"
5
6
#include <stdio.h>
277.1.1 by zilio nicolas
clean version for locks
7
#include <string.h>
8
#include <stdint.h>
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
9
#include <assert.h>
10
#include <pthread.h>
11
#include <stdint.h>
12
13
#ifdef HAVE_STDATOMIC_H
14
# include <stdatomic.h>
15
#endif /* HAVE_STDATOMIC_H */
16
277.1.1 by zilio nicolas
clean version for locks
17
#include "error.h"
18
#include "lock.h"
19
#include "pci.h"
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
20
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
21
/**
22
 * structure to define a lock
23
 */
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
24
struct pcilib_lock_s {
307 by Suren A. Chilingaryan
Finalyze XML support and provide initial support for views (only descriptions so far)
25
  pthread_mutex_t mutex; 		/**< the pthread robust mutex */
26
  pcilib_lock_flags_t flags; 		/**< flags to define the type of the mutex */
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
27
#ifdef HAVE_STDATOMIC_H
307 by Suren A. Chilingaryan
Finalyze XML support and provide initial support for views (only descriptions so far)
28
  volatile atomic_uint refs; 		/**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */ 
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
29
#else /* HAVE_STDATOMIC_H */
307 by Suren A. Chilingaryan
Finalyze XML support and provide initial support for views (only descriptions so far)
30
    volatile uint32_t refs;		/**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
31
#endif /* HAVE_STDATOMIC_H */
307 by Suren A. Chilingaryan
Finalyze XML support and provide initial support for views (only descriptions so far)
32
  char name[]; 				/**< lock identifier */
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
33
};
34
277.1.1 by zilio nicolas
clean version for locks
35
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
36
int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char *lock_id) {
37
    int err;
38
    pthread_mutexattr_t attr;
39
40
    assert(lock);
41
    assert(lock_id);
42
43
    memset(lock, 0, PCILIB_LOCK_SIZE);
44
45
    if (strlen(lock_id) >= (PCILIB_LOCK_SIZE - offsetof(struct pcilib_lock_s, name))) {
46
	pcilib_error("The supplied lock id (%s) is too long...", lock_id);
47
	return PCILIB_ERROR_INVALID_ARGUMENT;
48
    }
49
50
    if ((err = pthread_mutexattr_init(&attr))!=0) {
51
	pcilib_error("Can't initialize mutex attribute, errno %i", errno);
52
	return PCILIB_ERROR_FAILED;
53
    }
54
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
55
	/* we declare the mutex as possibly shared amongst different processes*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
56
    if ((err = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED))!=0) {
57
	pcilib_error("Can't configure a shared mutex attribute, errno %i", errno);
58
	return PCILIB_ERROR_FAILED;
59
    }
60
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
61
	/* we set the mutex as robust, so it would be automatically unlocked if the application crash*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
62
    if ((flags&PCILIB_LOCK_FLAG_PERSISTENT)==0) {
63
	if ((err = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST))!=0) {
64
	    pcilib_error("Can't configure a robust mutex attribute, errno: %i", errno);
65
	    return PCILIB_ERROR_FAILED;
277.1.1 by zilio nicolas
clean version for locks
66
	}
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
67
    }
68
69
    if ((err = pthread_mutex_init(&lock->mutex, &attr))!=0) {
70
	pcilib_error("Can't create mutex, errno : %i",errno);
71
	return PCILIB_ERROR_FAILED;
72
    }
73
74
    strcpy(lock->name, lock_id);
75
    lock->refs = 1;
76
    lock->flags = flags;
77
78
    return 0;
277.1.1 by zilio nicolas
clean version for locks
79
}
80
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
81
82
void pcilib_free_lock(pcilib_lock_t *lock) {
83
    int err;
84
85
    assert(lock);
86
87
//    if (lock->refs)
88
//	pcilib_error("Forbidding to destroy the referenced mutex...");
89
90
    if ((err = pthread_mutex_destroy(&lock->mutex))==-1)
91
	pcilib_warning("Can't destroy POSIX mutex, errno %i",errno);
92
}
93
94
95
void pcilib_lock_ref(pcilib_lock_t *lock) {
96
    assert(lock);
97
    
98
#ifdef HAVE_STDATOMIC_H
99
    atomic_fetch_add_explicit(&lock->refs, 1, memory_order_relaxed);
100
#else /* HAVE_STDATOMIC_H */
101
    lock->refs++;
102
#endif  /* HAVE_STDATOMIC_H */
103
}
104
105
void pcilib_lock_unref(pcilib_lock_t *lock) {
106
    assert(lock);
107
108
    if (!lock->refs) {
109
	pcilib_warning("Lock is not referenced");
110
	return;
111
    }
112
113
#ifdef HAVE_STDATOMIC_H
114
    atomic_fetch_sub_explicit(&lock->refs, 1, memory_order_relaxed);
115
#else /* HAVE_STDATOMIC_H */
116
    lock->refs--;
117
#endif  /* HAVE_STDATOMIC_H */
118
}
119
120
size_t pcilib_lock_get_refs(pcilib_lock_t *lock) {
121
    return lock->refs;
122
}
123
124
pcilib_lock_flags_t pcilib_lock_get_flags(pcilib_lock_t *lock) {
125
    return lock->flags;
126
}
127
128
const char *pcilib_lock_get_name(pcilib_lock_t *lock) {
129
    assert(lock);
130
131
    if (lock->name[0]) return lock->name;
132
    return NULL;
133
}
134
135
int pcilib_lock_custom(pcilib_lock_t *lock, pcilib_lock_flags_t flags, pcilib_timeout_t timeout) {
136
    int err;
137
285 by Suren A. Chilingaryan
Use global locks to protect kmem allocation to prevent race while allocating simmultaneously locking kmem pages and any other type of kmem
138
    if (!lock) {
139
	pcilib_error("The null lock pointer is passed to lock function");
140
	return PCILIB_ERROR_INVALID_ARGUMENT;
141
    }
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
142
143
    struct timespec tm;
144
145
    switch (timeout) {
146
     case PCILIB_TIMEOUT_INFINITE:
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
147
	/* the process will be hold till it can gain acquire the lock*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
148
        err = pthread_mutex_lock(&lock->mutex);
149
	break;
150
     case PCILIB_TIMEOUT_IMMEDIATE:
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
151
	/* the function returns immediatly if it can't acquire the lock*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
152
        err = pthread_mutex_trylock(&lock->mutex);
153
	break;
154
     default:
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
155
	/* the process will be hold till it can acquire the lock and timeout is not reached*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
156
        clock_gettime(CLOCK_REALTIME, &tm);
157
        tm.tv_nsec += 1000 * (timeout%1000000);
158
        if (tm.tv_nsec < 1000000000)
159
	    tm.tv_sec += timeout/1000000;
160
	else {
161
	    tm.tv_sec += 1 + timeout/1000000;
162
	    tm.tv_nsec -= 1000000000;
163
        } 
164
        err = pthread_mutex_timedlock(&lock->mutex, &tm);
165
    }
166
167
    if (!err)
168
	return 0;
169
170
    switch (err) {
171
     case EOWNERDEAD:
305.1.5 by zilio nicolas
reviewd old tasks comments for doxygen and update
172
	/*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.*/
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
173
        err = pthread_mutex_consistent(&lock->mutex);
174
        if (err) {
175
	    pcilib_error("Failed to mark mutex as consistent, errno %i", err);
291 by Suren A. Chilingaryan
Fix handling of inconsistent mutexes
176
	    break;
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
177
        }
291 by Suren A. Chilingaryan
Fix handling of inconsistent mutexes
178
        return 0;
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
179
     case ETIMEDOUT:
180
     case EBUSY:
181
        return PCILIB_ERROR_TIMEOUT;
182
     default:
183
        pcilib_error("Failed to obtain mutex, errno %i", err);
184
    }
185
186
    return PCILIB_ERROR_FAILED;
187
}
188
189
int pcilib_lock(pcilib_lock_t* lock) {
190
    return pcilib_lock_custom(lock, PCILIB_LOCK_FLAGS_DEFAULT, PCILIB_TIMEOUT_INFINITE);
191
}
192
289 by Suren A. Chilingaryan
Provide pcilib_try_lock call
193
int pcilib_try_lock(pcilib_lock_t* lock) {
194
    return pcilib_lock_custom(lock, PCILIB_LOCK_FLAGS_DEFAULT, PCILIB_TIMEOUT_IMMEDIATE);
195
}
196
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
197
void pcilib_unlock(pcilib_lock_t *lock) {
198
    int err;
199
200
    if (!lock)
201
	return;
202
291 by Suren A. Chilingaryan
Fix handling of inconsistent mutexes
203
    if ((err = pthread_mutex_unlock(&lock->mutex)) != 0) {
204
	switch (err) {
205
	 case EPERM:
206
	    pcilib_error("Trying to unlock not locked mutex (%s) or the mutex which was locked by a different thread", lock->name);
207
	    break;
208
	 default:
209
	    pcilib_error("Can't unlock mutex, errno %i", err);
210
	}
211
    }
280 by Suren A. Chilingaryan
Integrate locking subsystem from Nicolas Zilio
212
}