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