1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <klib/rc.h>
28 #include <klib/out.h>
29 #include <klib/text.h>
30 #include <klib/printf.h>
31 #include <kfs/file.h>
32 #include <kfs/directory.h>
33 #include <kproc/lock.h>
34 #include <kproc/thread.h>
35
36 #include <atomic32.h>
37
38 #include "utils.h"
39
40 #include <sysalloc.h>
41 #include <stdio.h>
42 #include <sys/time.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include <signal.h>
46
47 /*))))
48 |||| XStats implementation
49 ((((*/
50
51 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
52
53 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
54
55 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
56
57 /*))
58 || XTmXXXX stuff
59 ((*/
60
61 /*)))
62 /// Mesuring time in ... microzecoidz from :
63 \\\ # date -d @1380000000
64 /// Tue Sep 24 01:20:00 EDT 2013
65 (((*/
66 const uint64_t _DateFrom = 1380000000;
67 const uint64_t _DateCoeff = 1000000;
68
69 uint64_t CC
XTmNow()70 XTmNow ()
71 {
72 struct timeval TV;
73 uint64_t RetVal;
74
75 gettimeofday ( & TV, NULL );
76 RetVal = ( ( TV.tv_sec - _DateFrom ) * _DateCoeff ) + TV.tv_usec;
77
78
79 return RetVal;
80 } /* XTmNow () */
81
82 /*))
83 || XStats struct
84 ((*/
85 struct XStats {
86 struct KLock * mutabor;
87
88 uint64_t start_time; /* Time of starting stat */
89
90 uint64_t qty; /* all Reads Qty */
91 uint64_t err_qty; /* bad Reads Qty */
92 uint64_t time; /* Time of Reads cumulative */
93 uint64_t size; /* all Reads Qty */
94 };
95
96 static rc_t CC _XStatsReset_NoLock ( const struct XStats * self );
97
98 rc_t CC
XStatsDispose(const struct XStats * self)99 XStatsDispose ( const struct XStats * self )
100 {
101 struct XStats * Stats = ( struct XStats * ) self;
102
103 if ( Stats != NULL ) {
104 if ( Stats -> mutabor != NULL ) {
105 KLockRelease ( Stats -> mutabor );
106 Stats -> mutabor = NULL;
107 }
108
109 _XStatsReset_NoLock ( self );
110
111 free ( Stats );
112 }
113
114 return 0;
115 } /* XStatDispose () */
116
117 rc_t CC
XStatsMake(const struct XStats ** Stats)118 XStatsMake ( const struct XStats ** Stats )
119 {
120 rc_t RCt;
121 struct XStats * Ret;
122
123 RCt = 0;
124 Ret = NULL;
125
126 if ( Stats != NULL ) {
127 * Stats = NULL;
128 }
129
130 Ret = calloc ( 1, sizeof ( struct XStats ) );
131 if ( Ret == NULL ) {
132 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcExhausted );
133 }
134 else {
135 RCt = KLockMake ( & ( Ret -> mutabor ) );
136 if ( RCt == 0 ) {
137 RCt = XStatsReset ( Ret );
138 if ( RCt == 0 ) {
139 * Stats = ( const struct XStats * ) Ret;
140 }
141 }
142 }
143
144 if ( RCt != 0 ) {
145 * Stats = NULL;
146
147 if ( Ret != NULL ) {
148 XStatsDispose ( Ret );
149 }
150 }
151
152 return RCt;
153 } /* XStatMake () */
154
155 static
156 rc_t CC
_XStatsReset_NoLock(const struct XStats * self)157 _XStatsReset_NoLock ( const struct XStats * self )
158 {
159 struct XStats * Stats = ( struct XStats * ) self;
160
161 if ( Stats != NULL ) {
162 Stats -> start_time = XTmNow ();
163
164 Stats -> qty = 0;
165 Stats -> err_qty = 0;
166 Stats -> time = 0;
167 Stats -> size = 0;
168 }
169
170 return 0;
171 } /* _XStatsReset_NoLock () */
172
173 rc_t CC
XStatsReset(const struct XStats * self)174 XStatsReset ( const struct XStats * self )
175 {
176 rc_t RCt = 0;
177
178 if ( self != NULL ) {
179 RCt = KLockAcquire ( self -> mutabor );
180 if ( RCt == 0 ) {
181 RCt = _XStatsReset_NoLock ( self );
182 KLockUnlock ( self -> mutabor );
183 }
184 }
185
186 return RCt;
187 } /* XStatReset () */
188
189 rc_t CC
XStatsGood(const struct XStats * self,uint64_t Size,uint64_t Time)190 XStatsGood ( const struct XStats * self, uint64_t Size, uint64_t Time )
191 {
192 rc_t RCt;
193 struct XStats * Stats;
194
195 RCt = 0;
196 Stats = ( struct XStats * ) self;
197
198 if ( Stats != NULL ) {
199 RCt = KLockAcquire ( Stats -> mutabor );
200 if ( RCt == 0 ) {
201 Stats -> qty ++;
202 Stats -> time += Time;
203 Stats -> size += Size;
204
205 KLockUnlock ( Stats -> mutabor );
206 }
207 }
208
209 return RCt;
210 } /* XStatDispose () */
211
212 rc_t CC
XStatsBad(const struct XStats * self)213 XStatsBad ( const struct XStats * self )
214 {
215 rc_t RCt;
216 struct XStats * Stats;
217
218 RCt = 0;
219 Stats = ( struct XStats * ) self;
220
221 if ( Stats != NULL ) {
222 RCt = KLockAcquire ( Stats -> mutabor );
223 if ( RCt == 0 ) {
224 Stats -> err_qty ++;
225
226 KLockUnlock ( Stats -> mutabor );
227 }
228 }
229
230 return RCt;
231 } /* XStatDispose () */
232
233 rc_t CC
XStatsReport(const struct XStats * self)234 XStatsReport ( const struct XStats * self )
235 {
236 rc_t RCt;
237 uint64_t Per;
238 uint64_t Tim;
239
240 RCt = 0;
241 Per = 0;
242 Tim = 0;
243
244 if ( self != NULL ) {
245 RCt = KLockAcquire ( self -> mutabor );
246 if ( RCt == 0 ) {
247 printf ( "<<== Read Stats\n" );
248 printf ( " READ QTY : %lu\n", self -> qty );
249 Per = self -> qty == 0 ? 0 : ( ( int ) ( ( ( float ) self -> err_qty * 100.0f ) / ( float ) ( self -> qty ) ) );
250 printf ( " ERRORS : %lu [%lu%%]\n", self -> err_qty, Per );
251 Tim = ( XTmNow () - self -> start_time ) / 1000000;
252 printf ( " TIME : %lu sec\n", Tim );
253 printf ( " ACC TIME : %lu sec\n", self -> time / 1000000 );
254 printf ( " READ SIZE : %lu but\n", self -> size );
255
256 Per = self -> time == 0 ? 0 : ( self -> size / Tim ) ;
257 printf ( " THOUGHOUT : %lu bit per sec\n", Per );
258
259 KLockUnlock ( self -> mutabor );
260 }
261 }
262
263 return RCt;
264 } /* XStatDispose () */
265
266
267 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
268
269 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
270
271 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
272 struct XTasker;
273
274 struct XTask {
275 const struct XTasker * tasker;
276
277 struct KThread * thread;
278
279 size_t task_no;
280
281 size_t buffer_size;
282 char * buffer;
283 };
284
285 struct XTasker {
286 size_t task_qty;
287 const struct XTask ** tasks;
288
289 atomic32_t iteration;
290 atomic32_t is_run;
291 atomic32_t is_done;
292
293 uint64_t stop_at;
294
295 const struct XStats * stat;
296
297 void * job_4_task_data;
298 Job4Task job_4_task;
299 };
300
301 rc_t CC _TaskStop ( const struct XTask * self );
302
303 static
304 rc_t CC
_TaskDispose(const struct XTask * self)305 _TaskDispose ( const struct XTask * self )
306 {
307 struct XTask * Task = ( struct XTask * ) self;
308
309 if ( Task != NULL ) {
310 if ( Task -> thread != NULL ) {
311 _TaskStop ( Task );
312 }
313
314 Task -> task_no = 0;
315
316 Task -> buffer_size = 0;
317 if ( Task -> buffer != NULL ) {
318 free ( Task -> buffer );
319 Task -> buffer = NULL;
320 }
321
322 Task -> tasker = NULL;
323 }
324
325 return 0;
326 } /* _TaskDispose () */
327
328 static
329 rc_t CC
_TaskMake(const struct XTask ** Task,const struct XTasker * Tasker,size_t TaskNo)330 _TaskMake (
331 const struct XTask ** Task,
332 const struct XTasker * Tasker,
333 size_t TaskNo
334 )
335 {
336 rc_t RCt;
337 struct XTask * Ret;
338
339 RCt = 0;
340 Ret = NULL;
341
342 if ( * Task != NULL ) {
343 * Task = NULL;
344 }
345
346 if ( Tasker == NULL || Task == NULL ) {
347 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
348 }
349
350 Ret = calloc ( 1, sizeof ( struct XTask ) );
351 if ( Ret == NULL ) {
352 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcExhausted );
353 }
354 else {
355 Ret -> tasker = Tasker;
356 Ret -> task_no = TaskNo;
357
358 * Task = ( const struct XTask * ) Ret;
359 }
360
361 if ( RCt != 0 ) {
362 * Task = NULL;
363
364 if ( Ret != NULL ) {
365 _TaskDispose ( Ret );
366 }
367 }
368
369 return RCt;
370 } /* _TaskMake () */
371
372 static
373 rc_t CC
_TaskRealloc(const struct XTask * self,size_t BufferSize)374 _TaskRealloc ( const struct XTask * self, size_t BufferSize )
375 {
376 struct XTask * Task = ( struct XTask * ) self;
377
378 if ( Task -> buffer_size < BufferSize ) {
379 if ( Task -> buffer != 0 ) {
380 free ( Task -> buffer );
381
382 Task -> buffer = NULL;
383 Task -> buffer_size = 0;
384 }
385
386 Task -> buffer_size = ( ( BufferSize / 1024 ) + 1 ) * 1024;
387 Task -> buffer = calloc (
388 Task -> buffer_size,
389 sizeof ( char )
390 );
391 if ( Task -> buffer == NULL ) {
392 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcExhausted );
393 }
394 }
395
396 return 0;
397 } /* _TaskRealloc () */
398
399
400 static
401 rc_t CC
_TaskRead(const struct XTask * self)402 _TaskRead ( const struct XTask * self )
403 {
404 rc_t RCt;
405 const char * Name;
406 uint64_t Offset;
407 size_t Size, NumRead;
408 struct KDirectory * Directory;
409 const struct KFile * File;
410 uint64_t Time;
411
412 RCt = 0;
413 Name = NULL;
414 Offset = 0;
415 Size = NumRead = 0;
416 Directory = NULL;
417 File = NULL;
418 Time = 0;
419
420 if ( self == NULL ) {
421 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
422 }
423
424 if ( self -> tasker == NULL ) {
425 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcInvalid );
426 }
427
428 RCt = XTaskerNewJob ( self -> tasker, & Name, & Offset, & Size );
429 if ( RCt == 0 ) {
430 if ( Name != NULL ) {
431 RCt = _TaskRealloc ( self, Size );
432 if ( RCt == 0 ) {
433 RCt = KDirectoryNativeDir ( & Directory );
434 if ( RCt == 0 ) {
435 RCt = KDirectoryOpenFileRead (
436 Directory,
437 & File,
438 Name
439 );
440 if ( RCt == 0 ) {
441 Time = XTmNow ();
442
443 RCt = KFileReadAll (
444 File,
445 Offset,
446 self -> buffer,
447 Size,
448 & NumRead
449 );
450 if ( RCt == 0 ) {
451 XStatsGood (
452 self -> tasker -> stat,
453 NumRead,
454 ( XTmNow () - Time )
455 );
456 }
457 else {
458 XStatsBad ( self -> tasker -> stat );
459 }
460
461 KFileRelease ( File );
462 }
463 KDirectoryRelease ( Directory );
464 }
465 }
466 }
467 }
468
469 return RCt;
470 } /* _TaskRead () */
471
472 static
473 bool CC
_TaskDone(const struct XTask * self)474 _TaskDone ( const struct XTask * self )
475 {
476 if ( self != NULL ) {
477 return XTaskerIsDoneSet ( self -> tasker );
478 }
479
480 return true;
481 } /* _TaskDone () */
482
483 static
484 rc_t CC
_TaskThreadProc(const struct KThread * Thread,void * Data)485 _TaskThreadProc ( const struct KThread * Thread, void * Data )
486 {
487 rc_t RCt;
488 struct XTask * Task;
489
490 RCt = 0;
491 Task = ( struct XTask * ) Data;
492
493 if ( Thread == NULL ) {
494 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
495 }
496
497 if ( Data == NULL ) {
498 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
499 }
500
501 while ( true ) {
502 /* We are ignoring the return code, cuz there is statistic */
503 /* RCt = */
504 _TaskRead ( Task );
505
506 if ( _TaskDone ( Task ) ) {
507 break;
508 }
509 }
510
511 atomic32_dec ( ( atomic32_t * ) & ( Task -> tasker -> is_run ) );
512
513 return RCt;
514 } /* _TaskThreadProc () */
515
516 static
517 rc_t CC
_TaskRun(const struct XTask * self)518 _TaskRun ( const struct XTask * self )
519 {
520 struct XTask * Task = ( struct XTask * ) self;
521
522 if ( self == NULL ) {
523 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
524 }
525
526 if ( self -> tasker == NULL ) {
527 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcInvalid );
528 }
529
530 if ( self -> thread != NULL ) {
531 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcInvalid );
532 }
533
534 atomic32_read_and_add (
535 ( atomic32_t * ) & ( Task -> tasker -> is_run ), 1
536 );
537
538 return KThreadMake ( & ( Task -> thread ), _TaskThreadProc, Task );
539 } /* _TaskRun () */
540
541 rc_t CC
_TaskStop(const struct XTask * self)542 _TaskStop ( const struct XTask * self )
543 {
544 rc_t RCt;
545 struct XTask * Task;
546
547 RCt = 0;
548 Task = ( struct XTask * ) self;
549
550 if ( self == NULL ) {
551 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
552 }
553
554 KThreadCancel ( Task -> thread );
555 KThreadWait ( Task -> thread, NULL );
556 KThreadRelease ( Task -> thread );
557
558 Task -> thread = NULL;
559
560 return RCt;
561 } /* TaskStop () */
562
563 rc_t CC
XTaskerDispose(const struct XTasker * self)564 XTaskerDispose ( const struct XTasker * self )
565 {
566 struct XTasker * Tasker;
567 size_t llp;
568
569 Tasker = ( struct XTasker * ) self;
570 llp = 0;
571
572 if ( Tasker != NULL ) {
573 if ( Tasker -> stat != NULL ) {
574 XStatsDispose ( Tasker -> stat );
575 Tasker -> stat = NULL;
576 }
577
578 if ( Tasker -> tasks != NULL ) {
579 for ( llp = 0; llp < Tasker -> task_qty; llp ++ ) {
580 if ( Tasker -> tasks [ llp ] != NULL ) {
581 _TaskDispose ( Tasker -> tasks [ llp ] );
582 Tasker -> tasks [ llp ] = NULL;
583 }
584 }
585 }
586 Tasker -> tasks = NULL;
587 Tasker -> task_qty = 0;
588
589 atomic32_set ( & ( Tasker -> iteration ), 0 );
590 atomic32_set ( & ( Tasker -> is_run ), 0 );
591 atomic32_set ( & ( Tasker -> is_done ), 0 );
592
593 Tasker -> stop_at = 0;
594
595 Tasker -> job_4_task_data = NULL;
596 Tasker -> job_4_task = NULL;
597
598 free ( Tasker );
599 }
600
601 return 0;
602 } /* XTaskerDispose () */
603
604 /* JOJOBA here will be variable part */
605 rc_t CC
XTaskerMake(const struct XTasker ** Tasker,size_t NumThreads,void * Data,Job4Task Jobber)606 XTaskerMake (
607 const struct XTasker ** Tasker,
608 size_t NumThreads,
609 void * Data,
610 Job4Task Jobber
611 )
612 {
613 rc_t RCt;
614 struct XTasker * Ret;
615 size_t llp;
616
617 RCt = 0;
618 Ret = NULL;
619 llp = 0;
620
621 if ( Tasker != NULL ) {
622 * Tasker = NULL;
623 }
624
625 if ( Tasker == NULL ) {
626 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
627 }
628
629 if ( Jobber == NULL ) {
630 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
631 }
632
633 if ( NumThreads == 0 ) {
634 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcInvalid );
635 }
636
637 Ret = calloc ( 1, sizeof ( struct XTasker ) );
638 if ( Ret == NULL ) {
639 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcExhausted );
640 }
641 else {
642 Ret -> tasks = calloc ( NumThreads, sizeof ( struct XTask * ) );
643 if ( Ret -> tasks == NULL ) {
644 RCt = RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcExhausted );
645 }
646 else {
647 if ( RCt == 0 ) {
648 Ret -> task_qty = NumThreads;
649 for ( llp = 0; llp < NumThreads; llp ++ ) {
650 RCt = _TaskMake ( Ret -> tasks + llp, Ret, llp );
651 if ( RCt != 0 ) {
652 break;
653 }
654 }
655 if ( RCt == 0 ) {
656 RCt = XStatsMake ( & ( Ret -> stat ) );
657 if ( RCt == 0 ) {
658 atomic32_set ( & ( Ret -> iteration ), 0 );
659 atomic32_set ( & ( Ret -> is_run ), 0 );
660 atomic32_set ( & ( Ret -> is_done ), 0 );
661 Ret -> stop_at = 0;
662 Ret -> job_4_task_data = Data;
663 Ret -> job_4_task = Jobber;
664
665 * Tasker = Ret;
666 }
667 }
668 }
669 }
670 }
671
672 if ( RCt != 0 ) {
673 * Tasker = NULL;
674
675 if ( Ret != NULL ) {
676 XTaskerDispose ( Ret );
677 }
678 }
679
680 return RCt;
681 } /* XTaskerMake () */
682
683 rc_t CC
XTaskerRun(const struct XTasker * self,size_t Seconds)684 XTaskerRun ( const struct XTasker * self, size_t Seconds )
685 {
686 rc_t RCt;
687 size_t llp;
688
689 RCt = 0;
690 llp = 0;
691
692 if ( self == NULL ) {
693 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
694 }
695
696 if ( self -> tasks == NULL || self -> task_qty == 0 ) {
697 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcInvalid );
698 }
699
700 ( ( struct XTasker * ) self ) -> stop_at =
701 XTmNow () + ( Seconds * 1000000 );
702
703 for ( llp = 0; llp < self -> task_qty; llp ++ ) {
704 if ( self -> tasks [ llp ] != NULL ) {
705 RCt = _TaskRun ( self -> tasks [ llp ] );
706 }
707
708 if ( RCt != 0 ) {
709 break;
710 }
711 }
712
713 RCt = XTaskerWait ( self );
714
715 return RCt;
716 } /* XTaskerRun () */
717
718 bool CC
XTaskerIsRunning(const struct XTasker * self)719 XTaskerIsRunning ( const struct XTasker * self )
720 {
721 if ( self != NULL ) {
722 return atomic32_read ( & ( self -> is_run ) ) != 0;
723 }
724
725 return false;
726 } /* XTaskerIsRunning () */
727
728 rc_t CC
XTaskerNewJob(const struct XTasker * self,const char ** FileName,uint64_t * Offset,size_t * Size)729 XTaskerNewJob (
730 const struct XTasker * self,
731 const char ** FileName,
732 uint64_t * Offset,
733 size_t * Size
734 )
735 {
736 int Iteration = 0;
737
738 if ( FileName != NULL ) {
739 * FileName = NULL;
740 }
741
742 if ( Offset != NULL ) {
743 * Offset = 0;
744 }
745
746 if ( Size != NULL ) {
747 * Size = 0;
748 }
749
750 if ( self == NULL || FileName == NULL || Offset == NULL || Size == NULL ) {
751 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
752 }
753
754 Iteration = atomic32_read_and_add (
755 ( atomic32_t * ) & ( self -> iteration ),
756 1
757 );
758
759 if ( XTaskerIsDoneSet ( self ) ) {
760 return 0;
761 }
762
763 return self -> job_4_task (
764 self -> job_4_task_data,
765 Iteration,
766 FileName,
767 Offset,
768 Size
769 );
770 } /* XTaskerNewJob () */
771
772 rc_t CC
XTaskerSetDone(const struct XTasker * self)773 XTaskerSetDone ( const struct XTasker * self )
774 {
775 if ( self == NULL ) {
776 return RC ( rcExe, rcNoTarg, rcProcessing, rcParam, rcNull );
777 }
778
779 atomic32_set ( ( atomic32_t * ) & ( self -> is_done ), 1 );
780
781 return 0;
782 } /* XTaskerSetDone () */
783
784 bool CC
XTaskerIsDoneSet(const struct XTasker * self)785 XTaskerIsDoneSet ( const struct XTasker * self )
786 {
787 if ( self != NULL ) {
788 return atomic32_read ( & ( self -> is_done ) ) != 0;
789 }
790
791 return false;
792 } /* XTaskerIsDoneSet () */
793
794 bool CC
XTaskerIsDone(const struct XTasker * self)795 XTaskerIsDone ( const struct XTasker * self )
796 {
797 return XTaskerIsDoneSet ( self ) && ! XTaskerIsRunning ( self );
798 } /* XTaskerIsDone () */
799
800 static bool _sSigIntHandled = false;
801
802 void CC
XTaskerSigIntHandler(int SigNo)803 XTaskerSigIntHandler ( int SigNo )
804 {
805 if ( SigNo == SIGINT ) {
806 printf ( "SIGINT handled, ignored, but we will exit\n" );
807
808 _sSigIntHandled = true;
809 }
810 } /* XTaskerSigIntHandler () */
811
812 rc_t CC
XTaskerWait(const struct XTasker * self)813 XTaskerWait ( const struct XTasker * self )
814 {
815 uint64_t Next = 0;
816 uint64_t Now = 0;
817 size_t llp = 0;
818 uint64_t Pardon = 600 * 1000000;
819 struct timespec t_spec;
820 struct timespec t_rem;
821
822 t_spec . tv_sec = 0;
823 t_spec . tv_nsec = 100000;
824
825 t_rem . tv_sec = 0;
826 t_rem . tv_nsec = 0;
827
828 if ( XTaskerIsRunning ( self ) ) {
829 Next = XTmNow () + Pardon;
830
831 while ( true ) {
832 nanosleep ( & t_spec, & t_rem );
833
834 if ( _sSigIntHandled ) {
835 XTaskerSetDone ( self );
836 }
837
838 Now = XTmNow ();
839
840 if ( self -> stop_at < Now ) {
841 if ( ! XTaskerIsDoneSet ( self ) ) {
842 XTaskerSetDone ( self );
843 }
844 }
845
846 if ( XTaskerIsDone ( self ) ) {
847 break;
848 }
849
850 if ( Next < Now ) {
851 Next += Pardon;
852
853 XStatsReport ( self -> stat );
854 }
855 }
856
857 XStatsReport ( self -> stat );
858
859 for ( llp = 0; llp < self -> task_qty; llp ++ ) {
860 if ( self -> tasks [ llp ] != NULL ) {
861 _TaskStop ( self -> tasks [ llp ] );
862 }
863 }
864 }
865
866 return 0;
867 } /* XTaskerWait () */
868