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 |
}
|