/* * sThreadsDynamicEnvironment.c -- stubbed out PCR, based on * Mike Agostino's pseudoPCR */ #include #include XR_DynFrame SPCR_dynEnv = 0; static int XR_unwindFrameKeyValueIsMyAddress; XR_Pointer XR_UnwindFrameKey = (XR_Pointer) (&XR_unwindFrameKeyValueIsMyAddress); XR_DynFrame XR_GetDynamicEnvironment() { return (SPCR_dynEnv); } XR_DynFrame XR_GetDynamicEnvironmentOf(thread) XR_Thread thread; { if (thread != XR_currThread) { SPCR_error("XR_GetDynamicEnvironmentOf(bad thread)"); } return (SPCR_dynEnv); } void XR_SetDynamicEnvironment(f) XR_DynFrame f; { SPCR_dynEnv = f; } XR_DynFrame XR_LookupInDynamicEnvironment(key, de) XR_Pointer key; XR_DynFrame de; { XR_DynFrame f; for (f = de; f != NIL; f = f->df_link) { if (((unsigned) f) & 0x3) { SPCR_error("link on dynamic chain was not 4-byte aligned ptr"); } if (f->df_key == key) return f; } return NIL; } static unsigned EnvironmentLength(de) XR_DynFrame de; { unsigned len = 0; while (de != NIL) { len++; de = de->df_link; } return len; } XR_DynFrame XR_FirstCommonParent(de1, de2) XR_DynFrame de1, de2; { unsigned len1 = EnvironmentLength(de1); unsigned len2 = EnvironmentLength(de2); while (len1 > len2) { de1 = de1->df_link; len1--; }; while (len2 > len1) { de2 = de2->df_link; len2--; }; /* de1 and de2 are now the same length */ while (de1 != de2) { de1 = de1->df_link; de2 = de2->df_link; }; return de1; } int XR_UnwindTo(target) XR_DynFrame target; { XR_Pointer myKey = XR_UnwindFrameKey; XR_DynFrame de = XR_GetDynamicEnvironment(); XR_DynFrame f; for (f = de; (f != NIL) && (f != target); f = f->df_link) ; if (f == NIL) return -1; for (f = de; f != target; f = f->df_link) { if (f->df_key == myKey) { XR_UnwindFrame uf = (XR_UnwindFrame) f; XR_MesaProc unwinder = uf->uf_unwinder; if (unwinder != NIL) { XR_SetDynamicEnvironment(uf->uf_link); (*(unwinder->mp_proc))(unwinder); } } } XR_SetDynamicEnvironment(target); return 0; } int XR_RewindTo(target) XR_DynFrame target; { extern void DoRewind(/* end, f, key */); XR_DynFrame de = XR_GetDynamicEnvironment(); XR_DynFrame f; for (f = target; (f != NIL) && (f != de); f = f->df_link) ; if (f == NIL) return -1; DoRewind(de, target, XR_UnwindFrameKey); XR_SetDynamicEnvironment(target); return 0; } #define REWIND_BATCH 32 static void DoRewind(end, f, key) /* call all rewinders in (end..f] in that order */ XR_DynFrame end, f; XR_Pointer key; { XR_DynFrame stack[REWIND_BATCH]; int i = 0; for(;;) { if( f == NIL ) XR_Panic("DoRewind 0"); if( f == end ) break; if( f->df_key == key ) { if( i == REWIND_BATCH ) { DoRewind(end, f, key); break; } else { stack[i] = f; i++; } } f = f->df_link; } while( i > 0 ) { XR_UnwindFrame uf; XR_MesaProc rewinder; i -= 1; uf = (XR_UnwindFrame)(stack[i]); if( (rewinder = uf->uf_rewinder) != NIL ) { XR_SetDynamicEnvironment(uf->uf_link); (*(rewinder->mp_proc))(rewinder); } } }