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 #define SRC_LOC_DEFINED 1
28 
29 #include <kfc/extern.h>
30 #include <kfc/tstate.h>
31 #include <kfc/rsrc.h>
32 #include <kfc/ctx.h>
33 #include <kfc/except.h>
34 #include <kfc/rc.h>
35 #include <kfc/xc.h>
36 #include <kfc/xcdefs.h>
37 
38 #include <klib/time.h>
39 #include <klib/text.h>
40 #include <klib/printf.h>
41 #include <klib/rc.h>
42 #include <sysalloc.h>
43 
44 #include <stdio.h>
45 #include <string.h>
46 #include <assert.h>
47 
48 
49 /*--------------------------------------------------------------------------
50  * forwards
51  */
52 typedef struct KThreadEvent KThreadEvent;
53 typedef struct KThreadEvtNode KThreadEvtNode;
54 
55 
56 /*--------------------------------------------------------------------------
57  * ts_alloc
58  */
59 static
ts_alloc(size_t bytes,bool clear)60 void * ts_alloc ( size_t bytes, bool clear )
61 {
62     void * mem = clear ? calloc ( 1, bytes ) : malloc ( bytes );
63     if ( mem == NULL )
64         exit ( -1 );
65     return mem;
66 }
67 
68 
69 /*--------------------------------------------------------------------------
70  * xc to rc
71  */
72 static
extract_rc_xobj(const XCObj * xobj)73 rc_t extract_rc_xobj ( const XCObj * xobj )
74 {
75     while ( xobj -> dad != NULL )
76         xobj = xobj -> dad;
77     return SILENT_RC ( 0, 0, 0, xobj -> rc_obj, 0 );
78 }
79 
80 
81 static
extract_rc_xstate(const XCState * xstate)82 rc_t extract_rc_xstate ( const XCState * xstate )
83 {
84     while ( xstate -> dad != NULL )
85         xstate = xstate -> dad;
86     return SILENT_RC ( 0, 0, 0, 0, xstate -> rc_state );
87 }
88 
89 static
extract_rc_xerr(const XCErr * xc)90 rc_t extract_rc_xerr ( const XCErr * xc )
91 {
92     rc_t rc_obj, rc_state;
93 
94     /* get to root xc */
95     while ( xc -> dad != NULL )
96         xc = xc -> dad;
97 
98     /* retrieve components */
99     rc_obj = extract_rc_xobj ( xc -> obj );
100     rc_state = extract_rc_xstate ( xc -> state );
101 
102     return rc_obj | rc_state;
103 }
104 
105 static
extract_rc(const KFuncLoc * loc,const void * xc)106 rc_t extract_rc ( const KFuncLoc * loc, const void * xc )
107 {
108     rc_t rc_err = extract_rc_xerr ( xc );
109     return loc -> rc_context | rc_err;
110 }
111 
112 
113 /*--------------------------------------------------------------------------
114  * xc to string
115  */
116 static
extract_desc_xobj(const XCErr * xc)117 const char * extract_desc_xobj ( const XCErr * xc )
118 {
119     const XCObj * xobj;
120 
121     while ( xc -> dad != NULL )
122         xc = xc -> dad;
123 
124     xobj = xc -> obj;
125     while ( xobj -> desc == NULL && xobj -> dad != NULL )
126         xobj = xobj -> dad;
127 
128     return xobj -> desc;
129 }
130 
131 
132 static
extract_desc_xstate(const XCErr * xc)133 const char * extract_desc_xstate ( const XCErr * xc )
134 {
135     const XCState * xstate;
136 
137     while ( xc -> dad != NULL )
138         xc = xc -> dad;
139 
140     xstate = xc -> state;
141     while ( xstate -> desc == NULL && xstate -> dad != NULL )
142         xstate = xstate -> dad;
143 
144     return xstate -> desc;
145 }
146 
147 
148 /*--------------------------------------------------------------------------
149  * KThreadEvtNode
150  *  exection state belonging to the current thread
151  */
152 struct KThreadEvtNode
153 {
154     KThreadEvtNode * parent;
155     KThreadEvtNode * next;
156     KThreadEvtNode * child;
157 
158     const KFuncLoc * loc;
159     KThreadEvent * evt;
160     uint32_t zdepth;              /* root node has zdepth == 0 */
161 };
162 
163 
164 /*--------------------------------------------------------------------------
165  * KThreadEvent
166  *  describes a particular event
167  */
168 struct KThreadEvent
169 {
170     KThreadEvtNode * node;
171     KThreadEvent * next;
172 
173     const XCErr * xc;
174     KTime_t timestamp;
175     String message;
176     xc_sev_t severity;
177     xc_org_t origin;
178     uint32_t lineno;
179 };
180 
181 /* Dump
182  */
183 static
KThreadEventDump(ctx_t ctx,KTime_t timestamp,const KFuncLoc * loc,uint32_t lineno,xc_sev_t severity,xc_org_t origin,const void * xc_param,const char * msg,const KThreadEvtNode * node)184 void KThreadEventDump ( ctx_t ctx, KTime_t timestamp, const KFuncLoc * loc,
185     uint32_t lineno, xc_sev_t severity, xc_org_t origin, const void * xc_param,
186     const char * msg, const KThreadEvtNode * node )
187 {
188     const XCErr * xc = xc_param;
189 
190     size_t pre_size, sz;
191     char pre [ 4096 ];
192 
193 #if _DEBUGGING
194     const char *fname;
195 #endif
196 
197     static const char * err_strings [ 3 ] [ 4 ] =
198     {
199         { "NOTE", "WARNING", "SYSTEM ERROR", "FATAL SYSTEM ERROR" },
200         { "NOTE", "WARNING", "INTERNAL ERROR", "FATAL INTERNAL ERROR" },
201         { "NOTE", "WARNING", "USER ERROR", "FATAL USER ERROR" }
202     };
203 
204     KTime tm;
205     KTimeLocal ( & tm, timestamp );
206     string_printf ( pre, sizeof pre, & pre_size
207                     , "%04u-%02u-%02uT%02u:%02u:%02u "
208                     , tm . year
209                     , tm . month + 1
210                     , tm . day
211                     , tm . hour
212                     , tm . minute
213                     , tm . second
214         );
215 
216 #if _DEBUGGING
217     string_printf ( & pre [ pre_size ], sizeof pre - pre_size, & sz
218                     , "%.*s/%s/%s.%s:%u:"
219                     , sizeof __FILE__ -
220                       sizeof __mod__  -
221                       sizeof __file__ -
222                       sizeof __fext__ -
223                       1
224                     , __FILE__
225                     , loc -> src -> mod
226                     , loc -> src -> file
227                     , loc -> src -> ext
228                     , lineno
229                     , loc -> func
230         );
231     pre_size += sz;
232 
233     /* function name */
234     fname = loc -> func;
235 
236     /* remove leading "Java_" from jni names */
237     if ( memcmp ( loc -> func, "Java_", sizeof "Java_" - 1 ) == 0 )
238         fname += sizeof "Java_" - 1;
239 
240     /* print it into buffer */
241     string_printf ( & pre [ pre_size ], sizeof pre - pre_size, & sz
242                     , "%s - "
243                     , fname
244         );
245 
246     /* convert jni names into Java fqn */
247     if ( fname != loc -> func )
248     {
249         size_t i;
250         for ( i = 0; i < sz; ++ i )
251         {
252             if ( pre [ pre_size + i ] == '_' )
253                 pre [ pre_size + i ] = '.';
254         }
255     }
256     pre_size += sz;
257 #endif
258 
259     string_printf ( & pre [ pre_size ], sizeof pre - pre_size, & sz
260                     , "%s: "
261                     , err_strings [ origin ] [ severity ]
262         );
263     pre_size += sz;
264 
265 #if _DEBUGGING
266     string_printf ( & pre [ pre_size ], sizeof pre - pre_size, & sz
267                     , "( %s ) "
268                     , xc -> name
269         );
270     pre_size += sz;
271 #endif
272 
273     string_printf ( & pre [ pre_size ], sizeof pre - pre_size, & sz
274                     , "%s %s"
275                     , extract_desc_xobj ( xc )
276                     , extract_desc_xstate ( xc )
277         );
278     pre_size += sz;
279 
280     if ( msg == NULL || msg [ 0 ] == 0 )
281         fprintf ( stderr, "%s.\n", pre );
282     else
283         fprintf ( stderr, "%s - %s.\n", pre, msg );
284 
285 #if _DEBUGGING
286     if ( node != NULL )
287     {
288         fprintf ( stderr, "Stack Trace:\n" );
289         do
290         {
291             fprintf ( stderr
292                       , "    %s/%s.%s:%s\n"
293                       , node -> loc -> src -> mod
294                       , node -> loc -> src -> file
295                       , node -> loc -> src -> ext
296                       , node -> loc -> func
297                 );
298             node = node -> parent;
299         }
300         while ( node != NULL );
301     }
302     else if ( ctx != NULL )
303     {
304         fprintf ( stderr, "Stack Trace:\n" );
305         do
306         {
307             fprintf ( stderr
308                       , "    %s/%s.%s:%s\n"
309                       , ctx -> loc -> src -> mod
310                       , ctx -> loc -> src -> file
311                       , ctx -> loc -> src -> ext
312                       , ctx -> loc -> func
313                 );
314             ctx = ctx -> caller;
315         }
316         while ( ctx != NULL );
317     }
318 #endif
319 }
320 
321 /* Whack
322  */
323 static
KThreadEventWhack(KThreadEvent * self)324 KThreadEvent * KThreadEventWhack ( KThreadEvent * self )
325 {
326     KThreadEvent * next = self -> next;
327 
328     /* dump event to log */
329     KThreadEventDump ( NULL, self -> timestamp, self -> node -> loc,
330        self -> lineno, self -> severity, self -> origin,
331        self -> xc, self -> message . addr, self -> node );
332 
333     free ( self );
334     return next;
335 }
336 
337 static
KThreadEventWhackAll(KThreadEvent * self)338 void KThreadEventWhackAll ( KThreadEvent * self )
339 {
340     do
341         self = KThreadEventWhack ( self );
342     while ( self != NULL );
343 }
344 
345 /* Clear
346  */
347 static
KThreadEventClear(KThreadEvent * self)348 void KThreadEventClear ( KThreadEvent * self )
349 {
350     if ( self -> next != NULL )
351         KThreadEventClear ( self -> next );
352     free ( self );
353 }
354 
355 /* Make
356  */
357 static
KThreadEventMake(ctx_t ctx,uint32_t lineno,xc_sev_t severity,xc_org_t origin,xc_t xc,const char * msg,va_list args)358 KThreadEvent * KThreadEventMake ( ctx_t ctx,
359     uint32_t lineno, xc_sev_t severity, xc_org_t origin,
360     xc_t xc, const char * msg, va_list args )
361 {
362     KThreadEvent * evt;
363     KTime_t ts = KTimeStamp ();
364 
365     char * c;
366     size_t num_writ;
367     char msg_buffer [ 4096 ];
368     rc_t rc = string_vprintf ( msg_buffer, sizeof msg_buffer, & num_writ, msg, args );
369     if ( rc != 0 || num_writ >= sizeof msg_buffer )
370         string_printf ( msg_buffer, sizeof msg_buffer, & num_writ, "** BAD MESSAGE STRING **" );
371 
372     if ( num_writ > 0 && msg_buffer [ num_writ - 1 ] == '.' )
373         msg_buffer [ -- num_writ ] = 0;
374 
375     evt = malloc ( sizeof * evt + num_writ + 1 );
376     if ( evt == NULL )
377     {
378         /* ATTEMPT TO DUMP TO LOG */
379         KThreadEventDump ( ctx, ts, ctx -> loc, lineno, severity, origin, xc, msg_buffer, NULL );
380         exit ( -1 );
381     }
382 
383     evt -> node = NULL;
384     evt -> next = NULL;
385 
386     evt -> xc = ( const XCErr * ) xc;
387     evt -> timestamp = ts;
388     evt -> severity = severity;
389     evt -> origin = origin;
390     evt -> lineno = lineno;
391 
392     c = ( char* ) ( evt + 1 );
393     memmove ( c, msg_buffer, num_writ + 1 );
394     StringInit ( & evt -> message, c, num_writ, string_len ( c, num_writ ) );
395 
396     return evt;
397 }
398 
399 
400 /*--------------------------------------------------------------------------
401  * KThreadEvtNode
402  *  exection state belonging to the current thread
403  */
404 
405 
406 /* Whack
407  */
408 static
KThreadEvtNodeWhackAll(KThreadEvtNode * self)409 void KThreadEvtNodeWhackAll ( KThreadEvtNode * self )
410 {
411     if ( self -> evt )
412         KThreadEventWhackAll ( self -> evt );
413 
414     if ( self -> child )
415         KThreadEvtNodeWhackAll ( self -> child );
416 
417     if ( self -> next )
418         KThreadEvtNodeWhackAll ( self -> next );
419 
420     free ( self );
421 }
422 
423 
424 /* Clear
425  */
426 static
KThreadEvtNodeClear(KThreadEvtNode * self)427 void KThreadEvtNodeClear ( KThreadEvtNode * self )
428 {
429     if ( self -> evt )
430         KThreadEventClear ( self -> evt );
431 
432     if ( self -> child )
433         KThreadEvtNodeClear ( self -> child );
434 
435     if ( self -> next )
436         KThreadEvtNodeClear ( self -> next );
437 
438     free ( self );
439 }
440 
441 /* Make
442  */
443 static
KThreadEvtNodeMake(ctx_t ctx)444 KThreadEvtNode * KThreadEvtNodeMake ( ctx_t ctx )
445 {
446     KThreadEvtNode * node = ts_alloc ( sizeof * node, true );
447     node -> loc = ctx -> loc;
448     node -> zdepth = ctx -> zdepth;
449     return node;
450 }
451 
452 
453 /* AddChild
454  */
455 static
KThreadEvtNodeAddChild(KThreadEvtNode * self,KThreadEvtNode * child)456 KThreadEvtNode * KThreadEvtNodeAddChild ( KThreadEvtNode * self, KThreadEvtNode * child )
457 {
458     KThreadEvtNode * existing = self -> child;
459     if ( existing == NULL )
460         self -> child = child;
461     else
462     {
463         while ( existing -> next != NULL )
464             existing = existing -> next;
465         existing -> next = child;
466     }
467     child -> parent = self;
468     return self;
469 }
470 
471 
472 /* AddEvent
473  */
474 static
KThreadEvtNodeAddEvent(KThreadEvtNode * self,KThreadEvent * evt)475 void KThreadEvtNodeAddEvent ( KThreadEvtNode * self, KThreadEvent * evt )
476 {
477     KThreadEvent * existing = self -> evt;
478     if ( existing == NULL )
479         self -> evt = evt;
480     else
481     {
482         while ( existing -> next != NULL )
483             existing = existing -> next;
484         existing -> next = evt;
485     }
486     evt -> node = self;
487 }
488 
489 
490 /* Unlink
491  */
492 static
KThreadEvtNodeUnlink(KThreadEvtNode * self)493 void KThreadEvtNodeUnlink ( KThreadEvtNode * self )
494 {
495     KThreadEvtNode * par, * sib;
496 
497     par = self -> parent;
498     assert ( par != NULL );
499     sib = par -> child;
500 
501     if ( sib == self )
502         par -> child = self -> next;
503     else
504     {
505         while ( sib -> next != self )
506         {
507             assert ( sib -> next != NULL );
508             sib = sib -> next;
509         }
510         sib -> next = self -> next;
511     }
512 
513     self -> parent = NULL;
514     self -> next = NULL;
515 }
516 
517 
518 /* Locate
519  */
520 static
KThreadEvtNodeLocate(KThreadEvtNode * self,uint32_t zdepth)521 KThreadEvtNode * KThreadEvtNodeLocate ( KThreadEvtNode * self, uint32_t zdepth )
522 {
523     assert ( zdepth <= self -> zdepth );
524     while ( zdepth < self -> zdepth )
525     {
526         assert ( self -> parent != NULL );
527         self = self -> parent;
528     }
529     return self;
530 }
531 
532 
533 /* FindDominant
534  */
535 static
KThreadEvtNodeFindDominant(const KThreadEvtNode * self,const KThreadEvtNode * prune,KThreadEvent * dom)536 KThreadEvent * KThreadEvtNodeFindDominant ( const KThreadEvtNode * self, const KThreadEvtNode * prune, KThreadEvent * dom )
537 {
538     /* scan events within this node */
539     KThreadEvent * evt = self -> evt;
540     while ( evt != NULL )
541     {
542         if ( dom == NULL )
543             dom = evt;
544         else if ( evt -> severity > dom -> severity )
545             dom = evt;
546         evt = evt -> next;
547     }
548 
549     /* scan child events */
550     self = self -> child;
551     while ( self != NULL )
552     {
553         if ( self != prune )
554             dom = KThreadEvtNodeFindDominant ( self, NULL, dom );
555         self = self -> next;
556     }
557 
558     return dom;
559 }
560 
561 
562 /*--------------------------------------------------------------------------
563  * KThreadState
564  *  exection state belonging to the current thread
565  */
566 struct KThreadState
567 {
568     KThreadEvtNode * eroot;
569 };
570 
571 
572 /* Whack
573  */
KThreadStateWhack(KThreadState * self)574 void KThreadStateWhack ( KThreadState * self )
575 {
576     if ( self != NULL )
577     {
578         if ( self -> eroot != NULL )
579             KThreadEvtNodeWhackAll ( self -> eroot );
580         free ( self );
581     }
582 }
583 
584 
585 /* MakeThreadState
586  *  creates state for a newly created thread
587  *  called from the new thread
588  */
KProcMgrMakeThreadState(struct KProcMgr const * self)589 KThreadState * KProcMgrMakeThreadState ( struct KProcMgr const * self )
590 {
591     if ( self != NULL )
592     {
593         KThreadState * tstate = ts_alloc ( sizeof * tstate, true );
594         return tstate;
595     }
596 
597     return NULL;
598 }
599 
600 
601 /* CaptureEvent
602  *  records an event from the exception mechanism
603  */
KThreadStateEvent(KThreadState * self,ctx_t ctx,uint32_t lineno,xc_sev_t severity,xc_org_t origin,xc_t xc,const char * msg,va_list args)604 void KThreadStateEvent ( KThreadState * self, ctx_t ctx,
605     uint32_t lineno, xc_sev_t severity, xc_org_t origin,
606     xc_t xc, const char * msg, va_list args )
607 {
608     KThreadEvtNode * node, * par;
609     KThreadEvent * evt = KThreadEventMake ( ctx, lineno, severity, origin, xc, msg, args );
610 
611     /* prepare an RC for this event */
612     rc_t rc = 0;
613     if ( severity > xc_sev_warn )
614     {
615         rc = extract_rc ( ctx -> loc, xc );
616         assert ( rc != 0 );
617     }
618 
619     /* handle early errors before managers */
620     if ( self == NULL )
621     {
622         KThreadEventDump ( ctx, evt -> timestamp, ctx -> loc,
623             lineno, severity, origin, xc, evt -> message . addr, NULL );
624         free ( evt );
625         return;
626     }
627 
628     /* CASES:
629 
630        1. the thread has no existing event state
631           - create new node for call stack
632           - add event to the node
633           - propagate the event and rc up the ctx stack
634           - capture stack trace as node chain
635           - record root node
636 
637        2. the current stack frame already has an event
638           - find the corresponding node in stack trace
639           - add event to this node
640           - propagate up call chain while severity > caller.severity
641 
642        3. the current stack frame is clear, but some caller has state
643           - create new node for call stack
644           - add event to the node
645           - propagate the event and rc up the ctx stack until frame has event
646           - capture stack trace as node chain
647           - find the corresponding node in stack trace
648           - add node from child frame to common parent node
649           - continue to propagate up call chain while severity > caller.severity
650 
651     */
652 
653 
654     /* case 1 - just propagate up the stack */
655     if ( self -> eroot == NULL )
656     {
657         assert ( ctx -> evt == NULL );
658         assert ( ctx -> rc == 0 );
659 
660         /* create a new event node */
661         node = KThreadEvtNodeMake ( ctx );
662 
663         /* add the event */
664         KThreadEvtNodeAddEvent ( node, evt );
665         ( ( KCtx * ) ctx ) -> evt = evt;
666         ( ( KCtx * ) ctx ) -> rc = rc;
667 
668         /* propagate up the stack */
669         while ( ctx -> caller != NULL )
670         {
671             /* bump up */
672             ctx = ctx -> caller;
673             par = KThreadEvtNodeMake ( ctx );
674 
675             /* link */
676             node = KThreadEvtNodeAddChild ( par, node );
677 
678             /* record the event */
679             ( ( KCtx * ) ctx ) -> evt = evt;
680             ( ( KCtx * ) ctx ) -> rc = rc;
681         }
682 
683         /* record root node */
684         self -> eroot = node;
685     }
686 
687     /* cases 2 & 3 - will need to merge */
688     else
689     {
690         KThreadEvent * existing = ctx -> evt;
691 
692         /* case 2 - current frame has an event */
693         if ( ctx -> evt != NULL )
694         {
695             /* NB - this may not be so simple, if
696                a canonical ordering is to be achieved.
697                this code falls through to normal propagation,
698                that only favors the new event over existing
699                if it is more severe in nature.
700 
701                canonical ordering would be:
702                a) events originating in a frame always
703                   order before child events
704                b) dominant event should be selected
705                   first by severity and second by order
706 
707                as it stands, the code allows a previous child
708                event of the same severity to remain dominant.
709 
710             */
711 
712             node = KThreadEvtNodeLocate ( existing -> node, ctx -> zdepth );
713             KThreadEvtNodeAddEvent ( node, evt );
714         }
715 
716         /* case 3 - current frame is clear */
717         else
718         {
719             assert ( ctx -> rc == 0 );
720 
721             /* create a new event node */
722             node = KThreadEvtNodeMake ( ctx );
723 
724             /* add the event */
725             KThreadEvtNodeAddEvent ( node, evt );
726             ( ( KCtx * ) ctx ) -> evt = evt;
727             ( ( KCtx * ) ctx ) -> rc = rc;
728 
729             /* bump up */
730             assert ( ctx -> caller != NULL );
731             ctx = ctx -> caller;
732 
733             /* propagate up the stack */
734             while ( ctx -> evt == NULL )
735             {
736                 /* make node for this frame */
737                 par = KThreadEvtNodeMake ( ctx );
738 
739                 /* link */
740                 node = KThreadEvtNodeAddChild ( par, node );
741 
742                 /* record the event */
743                 ( ( KCtx * ) ctx ) -> evt = evt;
744                 ( ( KCtx * ) ctx ) -> rc = rc;
745 
746                 /* bump up */
747                 assert ( ctx -> caller != NULL );
748                 ctx = ctx -> caller;
749             }
750 
751             /* found nearest existing event */
752             existing = ctx -> evt;
753 
754             /* locate common parent node */
755             par = KThreadEvtNodeLocate ( existing -> node, ctx -> zdepth );
756             node = KThreadEvtNodeAddChild ( par, node );
757         }
758 
759         /* cases 2 & 3 - propagate event while severity > existing */
760         while ( severity > existing -> severity )
761         {
762             do
763             {
764                 /* overwrite prior */
765                 ( ( KCtx * ) ctx ) -> evt = evt;
766                 ( ( KCtx * ) ctx ) -> rc = rc;
767 
768                 /* bump up */
769                 ctx = ctx -> caller;
770                 if ( ctx == NULL )
771                     return;
772             }
773             while ( ctx -> evt == ( void * ) existing );
774 
775             assert ( ctx -> evt != NULL );
776             existing = ctx -> evt;
777         }
778     }
779 
780     if ( severity == xc_sev_fatal )
781         exit ( -1 );
782 }
783 
784 
785 /* ClearEvents
786  *  clears events from a particular point in the callchain
787  *  down toward lower points.
788  */
KThreadStateClearEvents(KThreadState * self,ctx_t ctx)789 void KThreadStateClearEvents ( KThreadState * self, ctx_t ctx )
790 {
791     if ( self != NULL )
792     {
793         assert ( ctx != NULL );
794         if ( ctx -> evt != NULL )
795         {
796             /* the recorded event */
797             KThreadEvent * evt = ctx -> evt;
798 
799             /* locate the node for this frame */
800             KThreadEvtNode * node = KThreadEvtNodeLocate ( evt -> node, ctx -> zdepth );
801 
802             /* douse it and everything below it */
803             if ( node == self -> eroot )
804             {
805                 self -> eroot = NULL;
806                 KThreadEvtNodeClear ( node );
807 
808                 do
809                 {
810                     ( ( KCtx * ) ctx ) -> evt = NULL;
811                     ( ( KCtx * ) ctx ) -> rc = 0;
812 
813                     ctx = ctx -> caller;
814                 }
815                 while ( ctx != NULL );
816             }
817             else
818             {
819                 KThreadEvtNode * par = node -> parent;
820 
821                 KThreadEvtNodeUnlink ( node );
822                 KThreadEvtNodeClear ( node );
823 
824                 /* WARNING - "evt" and "node" are now dangling! */
825 
826                 ( ( KCtx * ) ctx ) -> evt = NULL;
827                 ( ( KCtx * ) ctx ) -> rc = 0;
828 
829                 assert ( ctx -> caller != NULL );
830                 ctx = ctx -> caller;
831 
832                 /* look for nodes with no more events */
833                 for ( node = par; node != NULL; node = par )
834                 {
835                     if ( node -> child != NULL || node -> evt != NULL )
836                         break;
837 
838                     par = node -> parent;
839                     if ( par == NULL )
840                         self -> eroot = NULL;
841                     else
842                         KThreadEvtNodeUnlink ( node );
843                     KThreadEvtNodeClear ( node );
844 
845                     assert ( ctx != NULL );
846                     assert ( ctx -> evt == ( void * ) evt );
847                     ( ( KCtx * ) ctx ) -> evt = NULL;
848                     ( ( KCtx * ) ctx ) -> rc = 0;
849 
850                     ctx = ctx -> caller;
851                 }
852 
853                 assert ( node == NULL || ctx != NULL );
854 
855                 /* see if it was cleared all the way to root */
856                 if ( node == NULL )
857                     self -> eroot = NULL;
858 
859                 /* see if the dominant evt from the cleared node
860                    had propagated higher up and needs to be reset */
861                 else if ( ctx -> evt == ( void* ) evt )
862                 {
863                     rc_t rc = 0;
864                     KThreadEvent * dom;
865                     KThreadEvtNode * par;
866 
867                     assert ( ctx != NULL );
868 
869                     /* AT THIS POINT:
870 
871                        the current "node", a parent of the node
872                        originally being cleared, either has its
873                        own event(s) or has children that do.
874 
875                        the dominant event of the node we just
876                        cleared ( dangling pointer in "evt" ) had
877                        been propagated as the dominant event of
878                        this ( and possibly further ) parents.
879 
880                        we need to establish a new dominant event.
881                        this will be accomplished by visiting the
882                        current node and all of its children to find
883                        the node with the highest severity as first
884                        key, and first in order as second key.
885 
886                        NB - we may need to review the code to ensure
887                        there is a canonical ordering in all cases.
888 
889                      */
890 
891                     dom = KThreadEvtNodeFindDominant ( node, NULL, NULL );
892                     assert ( dom != NULL );
893                     if ( dom -> severity > xc_sev_warn )
894                         rc = extract_rc ( node -> loc, dom -> xc );
895 
896                     ( ( KCtx * ) ctx ) -> evt = dom;
897                     ( ( KCtx * ) ctx ) -> rc = rc;
898 
899                     par = node -> parent;
900                     ctx = ctx -> caller;
901 
902                     while ( par != NULL )
903                     {
904                         KThreadEvent * dom2;
905 
906                         /* early exit optimization */
907                         if ( ctx -> evt != ( void * ) evt )
908                             break;
909 
910                         /* compete for dominance */
911                         dom2 = KThreadEvtNodeFindDominant ( par, node, dom );
912                         if ( dom2 != dom )
913                         {
914                             rc = 0;
915                             if ( dom2 -> severity > xc_sev_warn )
916                                 rc = extract_rc ( node -> loc, dom2 -> xc );
917                             dom = dom2;
918                         }
919 
920                         /* update context */
921                         ( ( KCtx * ) ctx ) -> evt = dom;
922                         ( ( KCtx * ) ctx ) -> rc = rc;
923 
924                         /* bump up */
925                         par = node -> parent;
926                         ctx = ctx -> caller;
927                     }
928                 }
929             }
930         }
931     }
932 }
933 
934 
935 /* GetMessage
936  *  retrieve current event message
937  */
KThreadStateGetMessage(const KThreadState * self,ctx_t ctx)938 const char * KThreadStateGetMessage ( const KThreadState * self, ctx_t ctx )
939 {
940     if ( self != NULL )
941     {
942         assert ( ctx != NULL );
943         if ( ctx -> evt != NULL )
944         {
945             KThreadEvent * evt = ctx -> evt;
946             return evt -> message . addr;
947         }
948     }
949 
950     return "";
951 }
952 
953 
954 /* IsXCErr
955  */
KThreadStateIsXCErr(const KThreadState * self,ctx_t ctx,xc_t xc)956 bool KThreadStateIsXCErr ( const KThreadState * self, ctx_t ctx, xc_t xc )
957 {
958     if ( self != NULL )
959     {
960         assert ( ctx != NULL );
961         if ( ctx -> evt != NULL )
962         {
963             KThreadEvent * evt = ctx -> evt;
964             const XCErr * err = evt -> xc;
965             do
966             {
967                 if ( err == ( const XCErr * ) xc )
968                     return true;
969 
970                 err = err -> dad;
971             }
972             while ( err != NULL );
973         }
974     }
975 
976     return false;
977 }
978 
979 /* IsXCObj
980  */
KThreadStateIsXCObj(const KThreadState * self,ctx_t ctx,xobj_t xo)981 bool KThreadStateIsXCObj ( const KThreadState * self, ctx_t ctx, xobj_t xo )
982 {
983     if ( self != NULL )
984     {
985         assert ( ctx != NULL );
986         if ( ctx -> evt != NULL )
987         {
988             KThreadEvent * evt = ctx -> evt;
989             const XCErr * err = evt -> xc;
990             const XCObj * obj;
991 
992             while ( err -> dad != NULL )
993                 err = err -> dad;
994 
995             obj = err -> obj;
996 
997             do
998             {
999                 if ( obj == ( const XCObj * ) xo )
1000                     return true;
1001 
1002                 obj = obj -> dad;
1003             }
1004             while ( obj != NULL );
1005         }
1006     }
1007 
1008     return false;
1009 }
1010 
1011 /* IsXCState
1012  */
KThreadStateIsXCState(const KThreadState * self,ctx_t ctx,xstate_t xs)1013 bool KThreadStateIsXCState ( const KThreadState * self, ctx_t ctx, xstate_t xs )
1014 {
1015     if ( self != NULL )
1016     {
1017         assert ( ctx != NULL );
1018         if ( ctx -> evt != NULL )
1019         {
1020             KThreadEvent * evt = ctx -> evt;
1021             const XCErr * err = evt -> xc;
1022             const XCState * state;
1023 
1024             while ( err -> dad != NULL )
1025                 err = err -> dad;
1026 
1027             state = err -> state;
1028 
1029             do
1030             {
1031                 if ( state == ( const XCState * ) xs )
1032                     return true;
1033 
1034                 state = state -> dad;
1035             }
1036             while ( state != NULL );
1037         }
1038     }
1039 
1040     return false;
1041 }
1042