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