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