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