1 /*
2  * Queue 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 "libcthreads_condition.h"
27 #include "libcthreads_definitions.h"
28 #include "libcthreads_libcerror.h"
29 #include "libcthreads_mutex.h"
30 #include "libcthreads_queue.h"
31 #include "libcthreads_types.h"
32 
33 #if !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT )
34 
35 /* Creates a queue
36  * Make sure the value queue is referencing, is set to NULL
37  * Returns 1 if successful or -1 on error
38  */
libcthreads_queue_initialize(libcthreads_queue_t ** queue,int maximum_number_of_values,libcerror_error_t ** error)39 int libcthreads_queue_initialize(
40      libcthreads_queue_t **queue,
41      int maximum_number_of_values,
42      libcerror_error_t **error )
43 {
44 	libcthreads_internal_queue_t *internal_queue = NULL;
45 	static char *function                        = "libcthreads_queue_initialize";
46 	size_t values_array_size                     = 0;
47 
48 	if( queue == NULL )
49 	{
50 		libcerror_error_set(
51 		 error,
52 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 		 "%s: invalid queue.",
55 		 function );
56 
57 		return( -1 );
58 	}
59 	if( *queue != NULL )
60 	{
61 		libcerror_error_set(
62 		 error,
63 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 		 "%s: invalid queue value already set.",
66 		 function );
67 
68 		return( -1 );
69 	}
70 	if( maximum_number_of_values < 0 )
71 	{
72 		libcerror_error_set(
73 		 error,
74 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75 		 LIBCERROR_ARGUMENT_ERROR_VALUE_LESS_THAN_ZERO,
76 		 "%s: invalid maximum number of values value less than zero.",
77 		 function );
78 
79 		return( -1 );
80 	}
81 #if SIZEOF_INT <= SIZEOF_SIZE_T
82 	if( (size_t) maximum_number_of_values > (size_t) ( SSIZE_MAX / sizeof( intptr_t * ) ) )
83 #else
84 	if( maximum_number_of_values > (int) ( SSIZE_MAX / sizeof( intptr_t * ) ) )
85 #endif
86 	{
87 		libcerror_error_set(
88 		 error,
89 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
90 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
91 		 "%s: invalid maximum number of values value exceeds maximum.",
92 		 function );
93 
94 		return( -1 );
95 	}
96 	values_array_size = sizeof( intptr_t * ) * maximum_number_of_values;
97 
98 	if( values_array_size > (size_t) SSIZE_MAX )
99 	{
100 		libcerror_error_set(
101 		 error,
102 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
103 		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
104 		 "%s: invalid values array size value exceeds maximum.",
105 		 function );
106 
107 		goto on_error;
108 	}
109 	internal_queue = memory_allocate_structure(
110 	                  libcthreads_internal_queue_t );
111 
112 	if( internal_queue == NULL )
113 	{
114 		libcerror_error_set(
115 		 error,
116 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
117 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
118 		 "%s: unable to create queue.",
119 		 function );
120 
121 		goto on_error;
122 	}
123 	if( memory_set(
124 	     internal_queue,
125 	     0,
126 	     sizeof( libcthreads_internal_queue_t ) ) == NULL )
127 	{
128 		libcerror_error_set(
129 		 error,
130 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
131 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
132 		 "%s: unable to clear queue.",
133 		 function );
134 
135 		memory_free(
136 		 internal_queue );
137 
138 		return( -1 );
139 	}
140 	internal_queue->values_array = (intptr_t **) memory_allocate(
141 	                                              values_array_size );
142 
143 	if( internal_queue->values_array == NULL )
144 	{
145 		libcerror_error_set(
146 		 error,
147 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
148 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
149 		 "%s: unable to create values array.",
150 		 function );
151 
152 		goto on_error;
153 	}
154 	if( memory_set(
155 	     internal_queue->values_array,
156 	     0,
157 	     values_array_size ) == NULL )
158 	{
159 		libcerror_error_set(
160 		 error,
161 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
162 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
163 		 "%s: unable to clear values array.",
164 		 function );
165 
166 		goto on_error;
167 	}
168 	internal_queue->allocated_number_of_values = maximum_number_of_values;
169 
170 	if( libcthreads_mutex_initialize(
171 	     &( internal_queue->condition_mutex ),
172 	     error ) != 1 )
173 	{
174 		libcerror_error_set(
175 		 error,
176 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
177 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
178 		 "%s: unable to create condition mutex.",
179 		 function );
180 
181 		goto on_error;
182 	}
183 	if( libcthreads_condition_initialize(
184 	     &( internal_queue->empty_condition ),
185 	     error ) != 1 )
186 	{
187 		libcerror_error_set(
188 		 error,
189 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
190 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
191 		 "%s: unable to create empty condition.",
192 		 function );
193 
194 		goto on_error;
195 	}
196 	if( libcthreads_condition_initialize(
197 	     &( internal_queue->full_condition ),
198 	     error ) != 1 )
199 	{
200 		libcerror_error_set(
201 		 error,
202 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
204 		 "%s: unable to create full condition.",
205 		 function );
206 
207 		goto on_error;
208 	}
209 	*queue = (libcthreads_queue_t *) internal_queue;
210 
211 	return( 1 );
212 
213 on_error:
214 	if( internal_queue != NULL )
215 	{
216 		if( internal_queue->empty_condition != NULL )
217 		{
218 			libcthreads_condition_free(
219 			 &( internal_queue->empty_condition ),
220 			 NULL );
221 		}
222 		if( internal_queue->condition_mutex != NULL )
223 		{
224 			libcthreads_mutex_free(
225 			 &( internal_queue->condition_mutex ),
226 			 NULL );
227 		}
228 		if( internal_queue->values_array != NULL )
229 		{
230 			memory_free(
231 			 internal_queue->values_array );
232 		}
233 		memory_free(
234 		 internal_queue );
235 	}
236 	return( -1 );
237 }
238 
239 /* Frees a queue
240  * Uses the value_free_function to free the value
241  * Returns 1 if successful or -1 on error
242  */
libcthreads_queue_free(libcthreads_queue_t ** queue,int (* value_free_function)(intptr_t ** value,libcerror_error_t ** error),libcerror_error_t ** error)243 int libcthreads_queue_free(
244      libcthreads_queue_t **queue,
245      int (*value_free_function)(
246             intptr_t **value,
247             libcerror_error_t **error ),
248      libcerror_error_t **error )
249 {
250 	libcthreads_internal_queue_t *internal_queue = NULL;
251 	static char *function                        = "libcthreads_queue_free";
252 	int result                                   = 1;
253 	int value_index                              = 0;
254 
255 	if( queue == NULL )
256 	{
257 		libcerror_error_set(
258 		 error,
259 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
260 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
261 		 "%s: invalid queue.",
262 		 function );
263 
264 		return( -1 );
265 	}
266 	if( *queue != NULL )
267 	{
268 		internal_queue = (libcthreads_internal_queue_t *) *queue;
269 		*queue         = NULL;
270 
271 		if( value_free_function != NULL )
272 		{
273 			for( value_index = 0;
274 			     value_index < internal_queue->number_of_values;
275 			     value_index++ )
276 			{
277 				if( value_free_function(
278 				     &( internal_queue->values_array[ value_index ] ),
279 				     error ) != 1 )
280 				{
281 					libcerror_error_set(
282 					 error,
283 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
284 					 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
285 					 "%s: unable to free value: %d.",
286 					 function,
287 					 value_index );
288 
289 					result = -1;
290 				}
291 			}
292 		}
293 		memory_free(
294 		 internal_queue->values_array );
295 
296 		if( libcthreads_condition_free(
297 		     &( internal_queue->full_condition ),
298 		     error ) != 1 )
299 		{
300 			libcerror_error_set(
301 			 error,
302 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
303 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
304 			 "%s: unable to free full condition.",
305 			 function );
306 
307 			result = -1;
308 		}
309 		if( libcthreads_condition_free(
310 		     &( internal_queue->empty_condition ),
311 		     error ) != 1 )
312 		{
313 			libcerror_error_set(
314 			 error,
315 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
316 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
317 			 "%s: unable to free empty condition.",
318 			 function );
319 
320 			result = -1;
321 		}
322 		if( libcthreads_mutex_free(
323 		     &( internal_queue->condition_mutex ),
324 		     error ) != 1 )
325 		{
326 			libcerror_error_set(
327 			 error,
328 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
329 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
330 			 "%s: unable to free condition mutex.",
331 			 function );
332 
333 			result = -1;
334 		}
335 		memory_free(
336 		 internal_queue );
337 	}
338 	return( result );
339 }
340 
341 /* Empties a queue
342  * Returns 1 if successful or -1 on error
343  */
libcthreads_queue_empty(libcthreads_queue_t * queue,libcerror_error_t ** error)344 int libcthreads_queue_empty(
345      libcthreads_queue_t *queue,
346      libcerror_error_t **error )
347 {
348 	libcthreads_internal_queue_t *internal_queue = NULL;
349 	static char *function                        = "libcthreads_queue_empty";
350 	int result                                   = 1;
351 
352 	if( queue == NULL )
353 	{
354 		libcerror_error_set(
355 		 error,
356 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
357 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
358 		 "%s: invalid queue.",
359 		 function );
360 
361 		return( -1 );
362 	}
363 	internal_queue = (libcthreads_internal_queue_t *) queue;
364 
365 	if( internal_queue->values_array == NULL )
366 	{
367 		libcerror_error_set(
368 		 error,
369 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
370 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
371 		 "%s: invalid queue - missing values array.",
372 		 function );
373 
374 		return( -1 );
375 	}
376 	if( libcthreads_mutex_grab(
377 	     internal_queue->condition_mutex,
378 	     error ) != 1 )
379 	{
380 		libcerror_error_set(
381 		 error,
382 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
383 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
384 		 "%s: unable to grab condition mutex.",
385 		 function );
386 
387 		return( -1 );
388 	}
389 	while( internal_queue->number_of_values != 0 )
390 	{
391 		if( libcthreads_condition_wait(
392 		     internal_queue->full_condition,
393 		     internal_queue->condition_mutex,
394 		     error ) != 1 )
395 		{
396 			libcerror_error_set(
397 			 error,
398 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
399 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
400 			 "%s: unable to wait for full condition.",
401 			 function );
402 
403 			goto on_error;
404 		}
405 	}
406 	if( libcthreads_mutex_release(
407 	     internal_queue->condition_mutex,
408 	     error ) != 1 )
409 	{
410 		libcerror_error_set(
411 		 error,
412 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
413 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
414 		 "%s: unable to release condition mutex.",
415 		 function );
416 
417 		return( -1 );
418 	}
419 	return( result );
420 
421 on_error:
422 	libcthreads_mutex_release(
423 	 internal_queue->condition_mutex,
424 	 NULL );
425 
426 	return( -1 );
427 }
428 
429 /* Tries to pop a value off the queue
430  * Returns 1 if successful, 0 if not or -1 on error
431  */
libcthreads_queue_try_pop(libcthreads_queue_t * queue,intptr_t ** value,libcerror_error_t ** error)432 int libcthreads_queue_try_pop(
433      libcthreads_queue_t *queue,
434      intptr_t **value,
435      libcerror_error_t **error )
436 {
437 	libcthreads_internal_queue_t *internal_queue = NULL;
438 	static char *function                        = "libcthreads_queue_try_pop";
439 	int result                                   = 1;
440 
441 	if( queue == NULL )
442 	{
443 		libcerror_error_set(
444 		 error,
445 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
446 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
447 		 "%s: invalid queue.",
448 		 function );
449 
450 		return( -1 );
451 	}
452 	internal_queue = (libcthreads_internal_queue_t *) queue;
453 
454 	if( internal_queue->values_array == NULL )
455 	{
456 		libcerror_error_set(
457 		 error,
458 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
459 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
460 		 "%s: invalid queue - missing values array.",
461 		 function );
462 
463 		return( -1 );
464 	}
465 	if( value == NULL )
466 	{
467 		libcerror_error_set(
468 		 error,
469 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
470 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
471 		 "%s: invalid value.",
472 		 function );
473 
474 		return( -1 );
475 	}
476 	if( libcthreads_mutex_grab(
477 	     internal_queue->condition_mutex,
478 	     error ) != 1 )
479 	{
480 		libcerror_error_set(
481 		 error,
482 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
483 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
484 		 "%s: unable to grab condition mutex.",
485 		 function );
486 
487 		return( -1 );
488 	}
489 	if( internal_queue->number_of_values == 0 )
490 	{
491 		result = 0;
492 	}
493 	else
494 	{
495 		*value = internal_queue->values_array[ internal_queue->pop_index ];
496 
497 		internal_queue->pop_index++;
498 
499 		if( internal_queue->pop_index >= internal_queue->allocated_number_of_values )
500 		{
501 			internal_queue->pop_index = 0;
502 		}
503 		internal_queue->number_of_values--;
504 
505 		/* The condition broadcast must be protected by the mutex for the WINAPI version
506 		 */
507 		if( libcthreads_condition_broadcast(
508 		     internal_queue->full_condition,
509 		     error ) != 1 )
510 		{
511 			libcerror_error_set(
512 			 error,
513 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
514 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
515 			 "%s: unable to broadcast full condition.",
516 			 function );
517 
518 			goto on_error;
519 		}
520 	}
521 	if( libcthreads_mutex_release(
522 	     internal_queue->condition_mutex,
523 	     error ) != 1 )
524 	{
525 		libcerror_error_set(
526 		 error,
527 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
528 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
529 		 "%s: unable to release condition mutex.",
530 		 function );
531 
532 		return( -1 );
533 	}
534 	return( result );
535 
536 on_error:
537 	libcthreads_mutex_release(
538 	 internal_queue->condition_mutex,
539 	 NULL );
540 
541 	return( -1 );
542 }
543 
544 /* Pops a value off the queue
545  * Returns 1 if successful or -1 on error
546  */
libcthreads_queue_pop(libcthreads_queue_t * queue,intptr_t ** value,libcerror_error_t ** error)547 int libcthreads_queue_pop(
548      libcthreads_queue_t *queue,
549      intptr_t **value,
550      libcerror_error_t **error )
551 {
552 	libcthreads_internal_queue_t *internal_queue = NULL;
553 	static char *function                        = "libcthreads_queue_pop";
554 
555 	if( queue == NULL )
556 	{
557 		libcerror_error_set(
558 		 error,
559 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
560 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
561 		 "%s: invalid queue.",
562 		 function );
563 
564 		return( -1 );
565 	}
566 	internal_queue = (libcthreads_internal_queue_t *) queue;
567 
568 	if( internal_queue->values_array == NULL )
569 	{
570 		libcerror_error_set(
571 		 error,
572 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
573 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
574 		 "%s: invalid queue - missing values array.",
575 		 function );
576 
577 		return( -1 );
578 	}
579 	if( value == NULL )
580 	{
581 		libcerror_error_set(
582 		 error,
583 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
584 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
585 		 "%s: invalid value.",
586 		 function );
587 
588 		return( -1 );
589 	}
590 	if( libcthreads_mutex_grab(
591 	     internal_queue->condition_mutex,
592 	     error ) != 1 )
593 	{
594 		libcerror_error_set(
595 		 error,
596 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
597 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
598 		 "%s: unable to grab condition mutex.",
599 		 function );
600 
601 		return( -1 );
602 	}
603 	while( internal_queue->number_of_values == 0 )
604 	{
605 		if( libcthreads_condition_wait(
606 		     internal_queue->empty_condition,
607 		     internal_queue->condition_mutex,
608 		     error ) != 1 )
609 		{
610 			libcerror_error_set(
611 			 error,
612 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
613 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
614 			 "%s: unable to wait for empty condition.",
615 			 function );
616 
617 			goto on_error;
618 		}
619 	}
620 	*value = internal_queue->values_array[ internal_queue->pop_index ];
621 
622 	internal_queue->pop_index++;
623 
624 	if( internal_queue->pop_index >= internal_queue->allocated_number_of_values )
625 	{
626 		internal_queue->pop_index = 0;
627 	}
628 	internal_queue->number_of_values--;
629 
630 	/* The condition broadcast must be protected by the mutex for the WINAPI version
631 	 */
632 	if( libcthreads_condition_broadcast(
633 	     internal_queue->full_condition,
634 	     error ) != 1 )
635 	{
636 		libcerror_error_set(
637 		 error,
638 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
639 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
640 		 "%s: unable to broadcast full condition.",
641 		 function );
642 
643 		goto on_error;
644 	}
645 	if( libcthreads_mutex_release(
646 	     internal_queue->condition_mutex,
647 	     error ) != 1 )
648 	{
649 		libcerror_error_set(
650 		 error,
651 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
652 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
653 		 "%s: unable to release condition mutex.",
654 		 function );
655 
656 		return( -1 );
657 	}
658 	return( 1 );
659 
660 on_error:
661 	libcthreads_mutex_release(
662 	 internal_queue->condition_mutex,
663 	 NULL );
664 
665 	return( -1 );
666 }
667 
668 /* Tries to push a value onto the queue
669  * Returns 1 if successful, 0 if not or -1 on error
670  */
libcthreads_queue_try_push(libcthreads_queue_t * queue,intptr_t * value,libcerror_error_t ** error)671 int libcthreads_queue_try_push(
672      libcthreads_queue_t *queue,
673      intptr_t *value,
674      libcerror_error_t **error )
675 {
676 	libcthreads_internal_queue_t *internal_queue = NULL;
677 	static char *function                        = "libcthreads_queue_try_push";
678 	int result                                   = 1;
679 
680 	if( queue == NULL )
681 	{
682 		libcerror_error_set(
683 		 error,
684 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
685 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
686 		 "%s: invalid queue.",
687 		 function );
688 
689 		return( -1 );
690 	}
691 	internal_queue = (libcthreads_internal_queue_t *) queue;
692 
693 	if( internal_queue->values_array == NULL )
694 	{
695 		libcerror_error_set(
696 		 error,
697 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
698 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
699 		 "%s: invalid queue - missing values array.",
700 		 function );
701 
702 		return( -1 );
703 	}
704 	if( value == NULL )
705 	{
706 		libcerror_error_set(
707 		 error,
708 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
709 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
710 		 "%s: invalid value.",
711 		 function );
712 
713 		return( -1 );
714 	}
715 	if( libcthreads_mutex_grab(
716 	     internal_queue->condition_mutex,
717 	     error ) != 1 )
718 	{
719 		libcerror_error_set(
720 		 error,
721 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
722 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
723 		 "%s: unable to grab condition mutex.",
724 		 function );
725 
726 		return( -1 );
727 	}
728 	if( internal_queue->number_of_values == internal_queue->allocated_number_of_values )
729 	{
730 		result = 0;
731 	}
732 	else
733 	{
734 		internal_queue->values_array[ internal_queue->push_index ] = value;
735 
736 		internal_queue->push_index++;
737 
738 		if( internal_queue->push_index >= internal_queue->allocated_number_of_values )
739 		{
740 			internal_queue->push_index = 0;
741 		}
742 		internal_queue->number_of_values++;
743 
744 		/* The condition broadcast must be protected by the mutex for the WINAPI version
745 		 */
746 		if( libcthreads_condition_broadcast(
747 		     internal_queue->empty_condition,
748 		     error ) != 1 )
749 		{
750 			libcerror_error_set(
751 			 error,
752 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
753 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
754 			 "%s: unable to broadcast empty condition.",
755 			 function );
756 
757 			goto on_error;
758 		}
759 	}
760 	if( libcthreads_mutex_release(
761 	     internal_queue->condition_mutex,
762 	     error ) != 1 )
763 	{
764 		libcerror_error_set(
765 		 error,
766 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
767 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
768 		 "%s: unable to release condition mutex.",
769 		 function );
770 
771 		return( -1 );
772 	}
773 	return( result );
774 
775 on_error:
776 	libcthreads_mutex_release(
777 	 internal_queue->condition_mutex,
778 	 NULL );
779 
780 	return( -1 );
781 }
782 
783 /* Pushes a value onto the queue
784  * Returns 1 if successful or -1 on error
785  */
libcthreads_queue_push(libcthreads_queue_t * queue,intptr_t * value,libcerror_error_t ** error)786 int libcthreads_queue_push(
787      libcthreads_queue_t *queue,
788      intptr_t *value,
789      libcerror_error_t **error )
790 {
791 	libcthreads_internal_queue_t *internal_queue = NULL;
792 	static char *function                        = "libcthreads_queue_push";
793 
794 	if( queue == NULL )
795 	{
796 		libcerror_error_set(
797 		 error,
798 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
799 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
800 		 "%s: invalid queue.",
801 		 function );
802 
803 		return( -1 );
804 	}
805 	internal_queue = (libcthreads_internal_queue_t *) queue;
806 
807 	if( internal_queue->values_array == NULL )
808 	{
809 		libcerror_error_set(
810 		 error,
811 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
812 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
813 		 "%s: invalid queue - missing values array.",
814 		 function );
815 
816 		return( -1 );
817 	}
818 	if( value == NULL )
819 	{
820 		libcerror_error_set(
821 		 error,
822 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
823 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
824 		 "%s: invalid value.",
825 		 function );
826 
827 		return( -1 );
828 	}
829 	if( libcthreads_mutex_grab(
830 	     internal_queue->condition_mutex,
831 	     error ) != 1 )
832 	{
833 		libcerror_error_set(
834 		 error,
835 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
836 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
837 		 "%s: unable to grab condition mutex.",
838 		 function );
839 
840 		return( -1 );
841 	}
842 	while( internal_queue->number_of_values == internal_queue->allocated_number_of_values )
843 	{
844 		if( libcthreads_condition_wait(
845 		     internal_queue->full_condition,
846 		     internal_queue->condition_mutex,
847 		     error ) != 1 )
848 		{
849 			libcerror_error_set(
850 			 error,
851 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
852 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
853 			 "%s: unable to wait for full condition.",
854 			 function );
855 
856 			goto on_error;
857 		}
858 	}
859 	internal_queue->values_array[ internal_queue->push_index ] = value;
860 
861 	internal_queue->push_index++;
862 
863 	if( internal_queue->push_index >= internal_queue->allocated_number_of_values )
864 	{
865 		internal_queue->push_index = 0;
866 	}
867 	internal_queue->number_of_values++;
868 
869 	/* The condition broadcast must be protected by the mutex for the WINAPI version
870 	 */
871 	if( libcthreads_condition_broadcast(
872 	     internal_queue->empty_condition,
873 	     error ) != 1 )
874 	{
875 		libcerror_error_set(
876 		 error,
877 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
878 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
879 		 "%s: unable to broadcast empty condition.",
880 		 function );
881 
882 		goto on_error;
883 	}
884 	if( libcthreads_mutex_release(
885 	     internal_queue->condition_mutex,
886 	     error ) != 1 )
887 	{
888 		libcerror_error_set(
889 		 error,
890 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
891 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
892 		 "%s: unable to release condition mutex.",
893 		 function );
894 
895 		return( -1 );
896 	}
897 	return( 1 );
898 
899 on_error:
900 	libcthreads_mutex_release(
901 	 internal_queue->condition_mutex,
902 	 NULL );
903 
904 	return( -1 );
905 }
906 
907 /* Pushes a value onto the queue in sorted order
908  *
909  * Uses the value_compare_function to determine the similarity of the values
910  * The value_compare_function should return LIBCTHREADS_COMPARE_LESS,
911  * LIBCTHREADS_COMPARE_EQUAL, LIBCTHREADS_COMPARE_GREATER if successful or -1 on error
912  *
913  * Returns 1 if successful, 0 if the value already exists or -1 on error
914  */
libcthreads_queue_push_sorted(libcthreads_queue_t * queue,intptr_t * value,int (* value_compare_function)(intptr_t * first_value,intptr_t * second_value,libcerror_error_t ** error),uint8_t sort_flags,libcerror_error_t ** error)915 int libcthreads_queue_push_sorted(
916      libcthreads_queue_t *queue,
917      intptr_t *value,
918      int (*value_compare_function)(
919             intptr_t *first_value,
920             intptr_t *second_value,
921             libcerror_error_t **error ),
922      uint8_t sort_flags,
923      libcerror_error_t **error )
924 {
925 	libcthreads_internal_queue_t *internal_queue = NULL;
926 	static char *function                        = "libcthreads_queue_push_sorted";
927 	int compare_result                           = 0;
928 	int pop_index                                = 0;
929 	int previous_push_index                      = 0;
930 	int push_index                               = 0;
931 	int result                                   = 1;
932 	int value_index                              = 0;
933 
934 	if( queue == NULL )
935 	{
936 		libcerror_error_set(
937 		 error,
938 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
939 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
940 		 "%s: invalid queue.",
941 		 function );
942 
943 		return( -1 );
944 	}
945 	internal_queue = (libcthreads_internal_queue_t *) queue;
946 
947 	if( internal_queue->values_array == NULL )
948 	{
949 		libcerror_error_set(
950 		 error,
951 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
952 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
953 		 "%s: invalid queue - missing values array.",
954 		 function );
955 
956 		return( -1 );
957 	}
958 	if( value == NULL )
959 	{
960 		libcerror_error_set(
961 		 error,
962 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
963 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
964 		 "%s: invalid value.",
965 		 function );
966 
967 		return( -1 );
968 	}
969 	if( value_compare_function == NULL )
970 	{
971 		libcerror_error_set(
972 		 error,
973 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
974 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
975 		 "%s: invalid value compare function.",
976 		 function );
977 
978 		return( -1 );
979 	}
980 	if( ( sort_flags & ~( LIBCTHREADS_SORT_FLAG_UNIQUE_VALUES ) ) != 0 )
981 	{
982 		libcerror_error_set(
983 		 error,
984 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
985 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
986 		 "%s: unsupported sort flags: 0x%02" PRIx8 ".",
987 		 function,
988 		 sort_flags );
989 
990 		return( -1 );
991 	}
992 	if( libcthreads_mutex_grab(
993 	     internal_queue->condition_mutex,
994 	     error ) != 1 )
995 	{
996 		libcerror_error_set(
997 		 error,
998 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
999 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1000 		 "%s: unable to grab condition mutex.",
1001 		 function );
1002 
1003 		return( -1 );
1004 	}
1005 	while( internal_queue->number_of_values == internal_queue->allocated_number_of_values )
1006 	{
1007 		if( libcthreads_condition_wait(
1008 		     internal_queue->full_condition,
1009 		     internal_queue->condition_mutex,
1010 		     error ) != 1 )
1011 		{
1012 			libcerror_error_set(
1013 			 error,
1014 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1015 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1016 			 "%s: unable to wait for full condition.",
1017 			 function );
1018 
1019 			goto on_error;
1020 		}
1021 	}
1022 	pop_index = internal_queue->pop_index;
1023 
1024 	for( value_index = 0;
1025 	     value_index < internal_queue->number_of_values;
1026 	     value_index++ )
1027 	{
1028 		compare_result = value_compare_function(
1029 		                  value,
1030 		                  internal_queue->values_array[ pop_index ],
1031 		                  error );
1032 
1033 		if( compare_result == -1 )
1034 		{
1035 			libcerror_error_set(
1036 			 error,
1037 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1038 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1039 			 "%s: unable to compare value: %d.",
1040 			 function,
1041 			 value_index );
1042 
1043 			goto on_error;
1044 		}
1045 		else if( compare_result == LIBCTHREADS_COMPARE_EQUAL )
1046 		{
1047 			if( ( sort_flags & LIBCTHREADS_SORT_FLAG_UNIQUE_VALUES ) != 0 )
1048 			{
1049 				result = 0;
1050 
1051 				break;
1052 			}
1053 		}
1054 		else if( compare_result == LIBCTHREADS_COMPARE_LESS )
1055 		{
1056 			result = 1;
1057 
1058 			break;
1059 		}
1060 		else if( compare_result != LIBCTHREADS_COMPARE_GREATER )
1061 		{
1062 			libcerror_error_set(
1063 			 error,
1064 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1065 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1066 			 "%s: unsupported value compare function return value: %d.",
1067 			 function,
1068 			 compare_result );
1069 
1070 			goto on_error;
1071 		}
1072 		pop_index++;
1073 
1074 		if( pop_index >= internal_queue->allocated_number_of_values )
1075 		{
1076 			pop_index = 0;
1077 		}
1078 	}
1079 	if( result != 0 )
1080 	{
1081 		push_index = internal_queue->push_index;
1082 
1083 		if( compare_result == LIBCTHREADS_COMPARE_LESS )
1084 		{
1085 			previous_push_index = push_index - 1;
1086 
1087 			while( push_index != pop_index )
1088 			{
1089 				if( previous_push_index < 0 )
1090 				{
1091 					previous_push_index = internal_queue->allocated_number_of_values - 1;
1092 				}
1093 				internal_queue->values_array[ push_index ] = internal_queue->values_array[ previous_push_index ];
1094 
1095 				push_index = previous_push_index;
1096 
1097 				previous_push_index--;
1098 			}
1099 		}
1100 		internal_queue->values_array[ push_index ] = value;
1101 
1102 		internal_queue->push_index++;
1103 
1104 		if( internal_queue->push_index >= internal_queue->allocated_number_of_values )
1105 		{
1106 			internal_queue->push_index = 0;
1107 		}
1108 		internal_queue->number_of_values++;
1109 
1110 		/* The condition broadcast must be protected by the mutex for the WINAPI version
1111 		 */
1112 		if( libcthreads_condition_broadcast(
1113 		     internal_queue->empty_condition,
1114 		     error ) != 1 )
1115 		{
1116 			libcerror_error_set(
1117 			 error,
1118 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1119 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1120 			 "%s: unable to broadcast empty condition.",
1121 			 function );
1122 
1123 			goto on_error;
1124 		}
1125 	}
1126 	if( libcthreads_mutex_release(
1127 	     internal_queue->condition_mutex,
1128 	     error ) != 1 )
1129 	{
1130 		libcerror_error_set(
1131 		 error,
1132 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1133 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1134 		 "%s: unable to release condition mutex.",
1135 		 function );
1136 
1137 		return( -1 );
1138 	}
1139 	return( result );
1140 
1141 on_error:
1142 	libcthreads_mutex_release(
1143 	 internal_queue->condition_mutex,
1144 	 NULL );
1145 
1146 	return( -1 );
1147 }
1148 
1149 #endif /* !defined( HAVE_LOCAL_LIBCTHREADS ) || defined( HAVE_MULTI_THREAD_SUPPORT ) */
1150 
1151