1 /*
2 * Lock functions
3 *
4 * Copyright (C) 2012-2020, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25
26 #include <errno.h>
27
28 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
29 #include <pthread.h>
30 #endif
31
32 #include "libcthreads_libcerror.h"
33 #include "libcthreads_lock.h"
34 #include "libcthreads_types.h"
35
36 #if !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT )
37
38 /* Creates a lock
39 * Make sure the value lock is referencing, is set to NULL
40 * Returns 1 if successful or -1 on error
41 */
libcthreads_lock_initialize(libcthreads_lock_t ** lock,libcerror_error_t ** error)42 int libcthreads_lock_initialize(
43 libcthreads_lock_t **lock,
44 libcerror_error_t **error )
45 {
46 libcthreads_internal_lock_t *internal_lock = NULL;
47 static char *function = "libcthreads_lock_initialize";
48
49 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
50 int pthread_result = 0;
51 #endif
52
53 if( lock == NULL )
54 {
55 libcerror_error_set(
56 error,
57 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59 "%s: invalid lock.",
60 function );
61
62 return( -1 );
63 }
64 if( *lock != NULL )
65 {
66 libcerror_error_set(
67 error,
68 LIBCERROR_ERROR_DOMAIN_RUNTIME,
69 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70 "%s: invalid lock value already set.",
71 function );
72
73 return( -1 );
74 }
75 internal_lock = memory_allocate_structure(
76 libcthreads_internal_lock_t );
77
78 if( internal_lock == NULL )
79 {
80 libcerror_error_set(
81 error,
82 LIBCERROR_ERROR_DOMAIN_MEMORY,
83 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84 "%s: unable to create lock.",
85 function );
86
87 goto on_error;
88 }
89 if( memory_set(
90 internal_lock,
91 0,
92 sizeof( libcthreads_internal_lock_t ) ) == NULL )
93 {
94 libcerror_error_set(
95 error,
96 LIBCERROR_ERROR_DOMAIN_MEMORY,
97 LIBCERROR_MEMORY_ERROR_SET_FAILED,
98 "%s: unable to clear lock.",
99 function );
100
101 memory_free(
102 internal_lock );
103
104 return( -1 );
105 }
106 #if defined( WINAPI )
107 InitializeCriticalSection(
108 &( internal_lock->critical_section ) );
109
110 #elif defined( HAVE_PTHREAD_H )
111 pthread_result = pthread_mutex_init(
112 &( internal_lock->mutex ),
113 NULL );
114
115 switch( pthread_result )
116 {
117 case 0:
118 break;
119
120 case EAGAIN:
121 libcerror_error_set(
122 error,
123 LIBCERROR_ERROR_DOMAIN_RUNTIME,
124 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
125 "%s: unable to initialize mutex with error: Insufficient resources.",
126 function );
127
128 goto on_error;
129
130 default:
131 libcerror_system_set_error(
132 error,
133 pthread_result,
134 LIBCERROR_ERROR_DOMAIN_RUNTIME,
135 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
136 "%s: unable to initialize mutex.",
137 function );
138
139 goto on_error;
140 }
141 #endif
142 *lock = (libcthreads_lock_t *) internal_lock;
143
144 return( 1 );
145
146 on_error:
147 if( internal_lock != NULL )
148 {
149 memory_free(
150 internal_lock );
151 }
152 return( -1 );
153 }
154
155 /* Frees a lock
156 * Returns 1 if successful or -1 on error
157 */
libcthreads_lock_free(libcthreads_lock_t ** lock,libcerror_error_t ** error)158 int libcthreads_lock_free(
159 libcthreads_lock_t **lock,
160 libcerror_error_t **error )
161 {
162 libcthreads_internal_lock_t *internal_lock = NULL;
163 static char *function = "libcthreads_lock_free";
164 int result = 1;
165
166 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
167 int pthread_result = 0;
168 #endif
169
170 if( lock == NULL )
171 {
172 libcerror_error_set(
173 error,
174 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
175 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
176 "%s: invalid lock.",
177 function );
178
179 return( -1 );
180 }
181 if( *lock != NULL )
182 {
183 internal_lock = (libcthreads_internal_lock_t *) *lock;
184 *lock = NULL;
185
186 #if defined( WINAPI )
187 DeleteCriticalSection(
188 &( internal_lock->critical_section ) );
189
190 #elif defined( HAVE_PTHREAD_H )
191 pthread_result = pthread_mutex_destroy(
192 &( internal_lock->mutex ) );
193
194 switch( pthread_result )
195 {
196 case 0:
197 break;
198
199 case EAGAIN:
200 libcerror_error_set(
201 error,
202 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
204 "%s: unable to destroy mutex with error: Insufficient resources.",
205 function );
206
207 result = -1;
208 break;
209
210 case EBUSY:
211 libcerror_error_set(
212 error,
213 LIBCERROR_ERROR_DOMAIN_RUNTIME,
214 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
215 "%s: unable to destroy mutex with error: Resource busy.",
216 function );
217
218 result = -1;
219 break;
220
221 default:
222 libcerror_system_set_error(
223 error,
224 pthread_result,
225 LIBCERROR_ERROR_DOMAIN_RUNTIME,
226 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
227 "%s: unable to destroy mutex.",
228 function );
229
230 result = -1;
231 break;
232 }
233 #endif
234 memory_free(
235 internal_lock );
236 }
237 return( result );
238 }
239
240 /* Grabs a lock
241 * Returns 1 if successful or -1 on error
242 */
libcthreads_lock_grab(const libcthreads_lock_t * lock,libcerror_error_t ** error)243 int libcthreads_lock_grab(
244 const libcthreads_lock_t *lock,
245 libcerror_error_t **error )
246 {
247 libcthreads_internal_lock_t *internal_lock = NULL;
248 static char *function = "libcthreads_lock_grab";
249
250 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
251 int pthread_result = 0;
252 #endif
253
254 if( lock == NULL )
255 {
256 libcerror_error_set(
257 error,
258 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
260 "%s: invalid lock.",
261 function );
262
263 return( -1 );
264 }
265 internal_lock = (libcthreads_internal_lock_t *) lock;
266
267 #if defined( WINAPI )
268 EnterCriticalSection(
269 &( internal_lock->critical_section ) );
270
271 #elif defined( HAVE_PTHREAD_H )
272 pthread_result = pthread_mutex_lock(
273 &( internal_lock->mutex ) );
274
275 switch( pthread_result )
276 {
277 case 0:
278 break;
279
280 case EAGAIN:
281 libcerror_error_set(
282 error,
283 LIBCERROR_ERROR_DOMAIN_RUNTIME,
284 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
285 "%s: unable to lock mutex with error: Maximum number of locks exceeded.",
286 function );
287
288 return( -1 );
289
290 case EDEADLK:
291 libcerror_error_set(
292 error,
293 LIBCERROR_ERROR_DOMAIN_RUNTIME,
294 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
295 "%s: unable to lock mutex with error: Deadlock condition detected.",
296 function );
297
298 return( -1 );
299
300 default:
301 libcerror_system_set_error(
302 error,
303 pthread_result,
304 LIBCERROR_ERROR_DOMAIN_RUNTIME,
305 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
306 "%s: unable to lock mutex.",
307 function );
308
309 return( -1 );
310 }
311 #endif
312 return( 1 );
313 }
314
315 /* Releases a lock
316 * Returns 1 if successful or -1 on error
317 */
libcthreads_lock_release(const libcthreads_lock_t * lock,libcerror_error_t ** error)318 int libcthreads_lock_release(
319 const libcthreads_lock_t *lock,
320 libcerror_error_t **error )
321 {
322 libcthreads_internal_lock_t *internal_lock = NULL;
323 static char *function = "libcthreads_lock_release";
324
325 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
326 int pthread_result = 0;
327 #endif
328
329 if( lock == NULL )
330 {
331 libcerror_error_set(
332 error,
333 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
334 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
335 "%s: invalid lock.",
336 function );
337
338 return( -1 );
339 }
340 internal_lock = (libcthreads_internal_lock_t *) lock;
341
342 #if defined( WINAPI )
343 LeaveCriticalSection(
344 &( internal_lock->critical_section ) );
345
346 #elif defined( HAVE_PTHREAD_H )
347 pthread_result = pthread_mutex_unlock(
348 &( internal_lock->mutex ) );
349
350 switch( pthread_result )
351 {
352 case 0:
353 break;
354
355 case EAGAIN:
356 libcerror_error_set(
357 error,
358 LIBCERROR_ERROR_DOMAIN_RUNTIME,
359 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
360 "%s: unable to unlock mutex with error: Maximum number of locks exceeded.",
361 function );
362
363 return( -1 );
364
365 case EDEADLK:
366 libcerror_error_set(
367 error,
368 LIBCERROR_ERROR_DOMAIN_RUNTIME,
369 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
370 "%s: unable to unlock mutex with error: Deadlock condition detected.",
371 function );
372
373 return( -1 );
374
375 default:
376 libcerror_system_set_error(
377 error,
378 pthread_result,
379 LIBCERROR_ERROR_DOMAIN_RUNTIME,
380 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
381 "%s: unable to unlock mutex.",
382 function );
383
384 return( -1 );
385 }
386 #endif
387 return( 1 );
388 }
389
390 #endif /* !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT ) */
391
392