1 /*
2 * Mutex 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( WINAPI ) && ( WINVER >= 0x0602 )
29 #include <Synchapi.h>
30 #endif
31
32 #if defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
33 #include <pthread.h>
34 #endif
35
36 #include "libcthreads_libcerror.h"
37 #include "libcthreads_mutex.h"
38 #include "libcthreads_types.h"
39
40 #if !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT )
41
42 /* Creates a mutex
43 * Make sure the value mutex is referencing, is set to NULL
44 * Returns 1 if successful or -1 on error
45 */
libcthreads_mutex_initialize(libcthreads_mutex_t ** mutex,libcerror_error_t ** error)46 int libcthreads_mutex_initialize(
47 libcthreads_mutex_t **mutex,
48 libcerror_error_t **error )
49 {
50 libcthreads_internal_mutex_t *internal_mutex = NULL;
51 static char *function = "libcthreads_mutex_initialize";
52
53 #if defined( WINAPI ) && ( WINVER < 0x0600 )
54 DWORD error_code = 0;
55
56 #elif defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
57 int pthread_result = 0;
58 #endif
59
60 if( mutex == NULL )
61 {
62 libcerror_error_set(
63 error,
64 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
65 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
66 "%s: invalid mutex.",
67 function );
68
69 return( -1 );
70 }
71 if( *mutex != NULL )
72 {
73 libcerror_error_set(
74 error,
75 LIBCERROR_ERROR_DOMAIN_RUNTIME,
76 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
77 "%s: invalid mutex value already set.",
78 function );
79
80 return( -1 );
81 }
82 internal_mutex = memory_allocate_structure(
83 libcthreads_internal_mutex_t );
84
85 if( internal_mutex == NULL )
86 {
87 libcerror_error_set(
88 error,
89 LIBCERROR_ERROR_DOMAIN_MEMORY,
90 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91 "%s: unable to create mutex.",
92 function );
93
94 goto on_error;
95 }
96 if( memory_set(
97 internal_mutex,
98 0,
99 sizeof( libcthreads_internal_mutex_t ) ) == NULL )
100 {
101 libcerror_error_set(
102 error,
103 LIBCERROR_ERROR_DOMAIN_MEMORY,
104 LIBCERROR_MEMORY_ERROR_SET_FAILED,
105 "%s: unable to clear mutex.",
106 function );
107
108 memory_free(
109 internal_mutex );
110
111 return( -1 );
112 }
113 #if defined( WINAPI ) && ( WINVER >= 0x0600 )
114 InitializeCriticalSection(
115 &( internal_mutex->critical_section ) );
116
117 #elif defined( WINAPI )
118 internal_mutex->mutex_handle = CreateMutex(
119 NULL,
120 FALSE,
121 NULL );
122
123 if( internal_mutex->mutex_handle == NULL )
124 {
125 error_code = GetLastError();
126
127 libcerror_system_set_error(
128 error,
129 error_code,
130 LIBCERROR_ERROR_DOMAIN_RUNTIME,
131 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
132 "%s: unable to initialize mutex handle.",
133 function );
134
135 goto on_error;
136 }
137
138 #elif defined( HAVE_PTHREAD_H )
139 pthread_result = pthread_mutex_init(
140 &( internal_mutex->mutex ),
141 NULL );
142
143 switch( pthread_result )
144 {
145 case 0:
146 break;
147
148 case EAGAIN:
149 libcerror_error_set(
150 error,
151 LIBCERROR_ERROR_DOMAIN_RUNTIME,
152 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
153 "%s: unable to initialize mutex with error: Insufficient resources.",
154 function );
155
156 goto on_error;
157
158 default:
159 libcerror_system_set_error(
160 error,
161 pthread_result,
162 LIBCERROR_ERROR_DOMAIN_RUNTIME,
163 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
164 "%s: unable to initialize mutex.",
165 function );
166
167 goto on_error;
168 }
169 #endif
170 *mutex = (libcthreads_mutex_t *) internal_mutex;
171
172 return( 1 );
173
174 on_error:
175 if( internal_mutex != NULL )
176 {
177 memory_free(
178 internal_mutex );
179 }
180 return( -1 );
181 }
182
183 /* Frees a mutex
184 * Returns 1 if successful or -1 on error
185 */
libcthreads_mutex_free(libcthreads_mutex_t ** mutex,libcerror_error_t ** error)186 int libcthreads_mutex_free(
187 libcthreads_mutex_t **mutex,
188 libcerror_error_t **error )
189 {
190 libcthreads_internal_mutex_t *internal_mutex = NULL;
191 static char *function = "libcthreads_mutex_free";
192 int result = 1;
193
194 #if defined( WINAPI ) && ( WINVER < 0x0600 )
195 DWORD error_code = 0;
196
197 #elif defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
198 int pthread_result = 0;
199 #endif
200
201 if( mutex == NULL )
202 {
203 libcerror_error_set(
204 error,
205 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
206 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
207 "%s: invalid mutex.",
208 function );
209
210 return( -1 );
211 }
212 if( *mutex != NULL )
213 {
214 internal_mutex = (libcthreads_internal_mutex_t *) *mutex;
215 *mutex = NULL;
216
217 #if defined( WINAPI ) && ( WINVER >= 0x0600 )
218 DeleteCriticalSection(
219 &( internal_mutex->critical_section ) );
220
221 #elif defined( WINAPI )
222 if( CloseHandle(
223 internal_mutex->mutex_handle ) == 0 )
224 {
225 error_code = GetLastError();
226
227 libcerror_system_set_error(
228 error,
229 error_code,
230 LIBCERROR_ERROR_DOMAIN_RUNTIME,
231 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
232 "%s: unable to free mutex handle.",
233 function );
234
235 result = -1;
236 }
237
238 #elif defined( HAVE_PTHREAD_H )
239 pthread_result = pthread_mutex_destroy(
240 &( internal_mutex->mutex ) );
241
242 switch( pthread_result )
243 {
244 case 0:
245 break;
246
247 case EAGAIN:
248 libcerror_error_set(
249 error,
250 LIBCERROR_ERROR_DOMAIN_RUNTIME,
251 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
252 "%s: unable to destroy mutex with error: Insufficient resources.",
253 function );
254
255 result = -1;
256 break;
257
258 case EBUSY:
259 libcerror_error_set(
260 error,
261 LIBCERROR_ERROR_DOMAIN_RUNTIME,
262 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
263 "%s: unable to destroy mutex with error: Resource busy.",
264 function );
265
266 result = -1;
267 break;
268
269 default:
270 libcerror_system_set_error(
271 error,
272 pthread_result,
273 LIBCERROR_ERROR_DOMAIN_RUNTIME,
274 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
275 "%s: unable to destroy mutex.",
276 function );
277
278 result = -1;
279 break;
280 }
281 #endif
282 memory_free(
283 internal_mutex );
284 }
285 return( result );
286 }
287
288 /* Grabs a mutex
289 * Returns 1 if successful or -1 on error
290 */
libcthreads_mutex_grab(libcthreads_mutex_t * mutex,libcerror_error_t ** error)291 int libcthreads_mutex_grab(
292 libcthreads_mutex_t *mutex,
293 libcerror_error_t **error )
294 {
295 libcthreads_internal_mutex_t *internal_mutex = NULL;
296 static char *function = "libcthreads_mutex_grab";
297
298 #if defined( WINAPI ) && ( WINVER < 0x0600 )
299 DWORD error_code = 0;
300 DWORD wait_status = 0;
301
302 #elif defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
303 int pthread_result = 0;
304 #endif
305
306 if( mutex == NULL )
307 {
308 libcerror_error_set(
309 error,
310 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
311 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
312 "%s: invalid mutex.",
313 function );
314
315 return( -1 );
316 }
317 internal_mutex = (libcthreads_internal_mutex_t *) mutex;
318
319 #if defined( WINAPI ) && ( WINVER >= 0x0600 )
320 EnterCriticalSection(
321 &( internal_mutex->critical_section ) );
322
323 #elif defined( WINAPI )
324 wait_status = WaitForSingleObject(
325 internal_mutex->mutex_handle,
326 INFINITE );
327
328 if( wait_status == WAIT_FAILED )
329 {
330 error_code = GetLastError();
331
332 libcerror_system_set_error(
333 error,
334 error_code,
335 LIBCERROR_ERROR_DOMAIN_RUNTIME,
336 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
337 "%s: wait for mutex handle failed.",
338 function );
339
340 return( -1 );
341 }
342
343 #elif defined( HAVE_PTHREAD_H )
344 pthread_result = pthread_mutex_lock(
345 &( internal_mutex->mutex ) );
346
347 switch( pthread_result )
348 {
349 case 0:
350 break;
351
352 case EAGAIN:
353 libcerror_error_set(
354 error,
355 LIBCERROR_ERROR_DOMAIN_RUNTIME,
356 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
357 "%s: unable to lock mutex with error: Maximum number of locks exceeded.",
358 function );
359
360 return( -1 );
361
362 case EDEADLK:
363 libcerror_error_set(
364 error,
365 LIBCERROR_ERROR_DOMAIN_RUNTIME,
366 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
367 "%s: unable to lock mutex with error: Deadlock condition detected.",
368 function );
369
370 return( -1 );
371
372 default:
373 libcerror_system_set_error(
374 error,
375 pthread_result,
376 LIBCERROR_ERROR_DOMAIN_RUNTIME,
377 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
378 "%s: unable to lock mutex.",
379 function );
380
381 return( -1 );
382 }
383 #endif
384 return( 1 );
385 }
386
387 /* Tries to grabs a mutex
388 * Returns 1 if successful, 0 if not or -1 on error
389 */
libcthreads_mutex_try_grab(libcthreads_mutex_t * mutex,libcerror_error_t ** error)390 int libcthreads_mutex_try_grab(
391 libcthreads_mutex_t *mutex,
392 libcerror_error_t **error )
393 {
394 libcthreads_internal_mutex_t *internal_mutex = NULL;
395 static char *function = "libcthreads_mutex_try_grab";
396 int result = 1;
397
398 #if defined( WINAPI ) && ( WINVER < 0x0600 )
399 DWORD error_code = 0;
400 DWORD wait_status = 0;
401
402 #elif defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
403 int pthread_result = 0;
404 #endif
405
406 if( mutex == NULL )
407 {
408 libcerror_error_set(
409 error,
410 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
411 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
412 "%s: invalid mutex.",
413 function );
414
415 return( -1 );
416 }
417 internal_mutex = (libcthreads_internal_mutex_t *) mutex;
418
419 #if defined( WINAPI ) && ( WINVER >= 0x0600 )
420 if( TryEnterCriticalSection(
421 &( internal_mutex->critical_section ) ) != 0 )
422 {
423 result = 1;
424 }
425 else
426 {
427 result = 0;
428 }
429
430 #elif defined( WINAPI )
431 wait_status = WaitForSingleObject(
432 internal_mutex->mutex_handle,
433 0 );
434
435 if( wait_status == WAIT_TIMEOUT )
436 {
437 result = 0;
438 }
439 else if( wait_status == WAIT_FAILED )
440 {
441 error_code = GetLastError();
442
443 libcerror_system_set_error(
444 error,
445 error_code,
446 LIBCERROR_ERROR_DOMAIN_RUNTIME,
447 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
448 "%s: wait for mutex handle failed.",
449 function );
450
451 return( -1 );
452 }
453
454 #elif defined( HAVE_PTHREAD_H )
455 pthread_result = pthread_mutex_trylock(
456 &( internal_mutex->mutex ) );
457
458 switch( pthread_result )
459 {
460 case 0:
461 break;
462
463 case EBUSY:
464 result = 0;
465 break;
466
467 case EAGAIN:
468 libcerror_error_set(
469 error,
470 LIBCERROR_ERROR_DOMAIN_RUNTIME,
471 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
472 "%s: unable to try lock mutex with error: Maximum number of locks exceeded.",
473 function );
474
475 return( -1 );
476
477 case EDEADLK:
478 libcerror_error_set(
479 error,
480 LIBCERROR_ERROR_DOMAIN_RUNTIME,
481 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
482 "%s: unable to try lock mutex with error: Deadlock condition detected.",
483 function );
484
485 return( -1 );
486
487 default:
488 libcerror_system_set_error(
489 error,
490 pthread_result,
491 LIBCERROR_ERROR_DOMAIN_RUNTIME,
492 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
493 "%s: unable to try lock mutex.",
494 function );
495
496 return( -1 );
497 }
498 #endif
499 return( result );
500 }
501
502 /* Releases a mutex
503 * Returns 1 if successful or -1 on error
504 */
libcthreads_mutex_release(libcthreads_mutex_t * mutex,libcerror_error_t ** error)505 int libcthreads_mutex_release(
506 libcthreads_mutex_t *mutex,
507 libcerror_error_t **error )
508 {
509 libcthreads_internal_mutex_t *internal_mutex = NULL;
510 static char *function = "libcthreads_mutex_release";
511
512 #if defined( WINAPI ) && ( WINVER < 0x0600 )
513 DWORD error_code = 0;
514 BOOL result = 0;
515
516 #elif defined( HAVE_PTHREAD_H ) && !defined( WINAPI )
517 int pthread_result = 0;
518 #endif
519
520 if( mutex == NULL )
521 {
522 libcerror_error_set(
523 error,
524 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
525 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
526 "%s: invalid mutex.",
527 function );
528
529 return( -1 );
530 }
531 internal_mutex = (libcthreads_internal_mutex_t *) mutex;
532
533 #if defined( WINAPI ) && ( WINVER >= 0x0600 )
534 LeaveCriticalSection(
535 &( internal_mutex->critical_section ) );
536
537 #elif defined( WINAPI )
538 result = ReleaseMutex(
539 internal_mutex->mutex_handle );
540
541 if( result == 0 )
542 {
543 error_code = GetLastError();
544
545 libcerror_system_set_error(
546 error,
547 error_code,
548 LIBCERROR_ERROR_DOMAIN_RUNTIME,
549 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
550 "%s: unable to relates mutex handle.",
551 function );
552
553 return( -1 );
554 }
555
556 #elif defined( HAVE_PTHREAD_H )
557 pthread_result = pthread_mutex_unlock(
558 &( internal_mutex->mutex ) );
559
560 switch( pthread_result )
561 {
562 case 0:
563 break;
564
565 case EAGAIN:
566 libcerror_error_set(
567 error,
568 LIBCERROR_ERROR_DOMAIN_RUNTIME,
569 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
570 "%s: unable to unlock mutex with error: Maximum number of locks exceeded.",
571 function );
572
573 return( -1 );
574
575 case EDEADLK:
576 libcerror_error_set(
577 error,
578 LIBCERROR_ERROR_DOMAIN_RUNTIME,
579 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
580 "%s: unable to unlock mutex with error: Deadlock condition detected.",
581 function );
582
583 return( -1 );
584
585 default:
586 libcerror_system_set_error(
587 error,
588 pthread_result,
589 LIBCERROR_ERROR_DOMAIN_RUNTIME,
590 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
591 "%s: unable to unlock mutex.",
592 function );
593
594 return( -1 );
595 }
596 #endif
597 return( 1 );
598 }
599
600 #endif /* !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT ) */
601
602