マイクロスレッド基本おさらい(3)
>果たしてこんなロジックで動くのか?
SH3+SH-Cで動かしてみますた*1。
mth_core.src
.EXPORT _exec .EXPORT _suspend .EXPORT _resume .SECTION P,CODE,ALIGN=4 ;*------------------------------------------------------------------------* ; <仮定> ; typedef struct t_ctx { ; size_t stksz; ; TStkElem* ssp; ; TStkElem stk[1]; ; } TCtx; ; TStkElem: スタックに格納されるデータのうち、整合の制限が最も強い型 ; (SH3ではlongが適切) ;*------------------------------------------------------------------------* ;*------------------------------------------------------------------------* ; void exec(TCtx* p_ctx, void (*bar)(void)) ;*------------------------------------------------------------------------* _exec: MOV.L R14,@-R15 MOV.L R13,@-R15 MOV.L R12,@-R15 MOV.L R11,@-R15 MOV.L R10,@-R15 MOV.L R9,@-R15 MOV.L R8,@-R15 STS.L PR,@-R15 ; p_ctx->ssp = p_ctx->stk + p_ctx->stksz MOV.L @(0,R4),R1 ; R1 = p_ctx->stksz MOV.L @(8,R4),R2 ; R2 = p_ctx->stk ADD R2,R1 ; R1 = (char*)stk + stksz MOV.L R1,@(4,R4) ; p_ctx->ssz = R1 (== (char*)stk + stksz) ; swap(SP, p_ctx->ssp) MOV R15,R1 MOV.L @(4,R4),R15 MOV.L R1,@(4,R4) ; LDS R5,PR ; PR = bar RTS NOP ;*------------------------------------------------------------------------* ; void suspend(TCtx* p_ctx) ;*------------------------------------------------------------------------* _suspend: MOV.L R14,@-R15 MOV.L R13,@-R15 MOV.L R12,@-R15 MOV.L R11,@-R15 MOV.L R10,@-R15 MOV.L R9,@-R15 MOV.L R8,@-R15 STS.L PR,@-R15 ; swap(SP, p_ctx->ssp) MOV R15,R1 MOV.L @(4,R4),R15 MOV.L R1,@(4,R4) ; LDS.L @R15+,PR MOV.L @R15+,R8 MOV.L @R15+,R9 MOV.L @R15+,R10 MOV.L @R15+,R11 MOV.L @R15+,R12 MOV.L @R15+,R13 MOV.L @R15+,R14 RTS NOP ;*------------------------------------------------------------------------* ; void resume(TCtx* p_ctx) ;*------------------------------------------------------------------------* _resume: BRA _suspend NOP .END
mth_sample.c
#includetypedef long TStkElem; typedef struct t_ctx { size_t stksz; TStkElem *ssp; TStkElem stk[4096/sizeof(TStkElem)]; } TCtx; extern void exec(TCtx *p_ctx, void (*bar)(void)); extern void suspend(TCtx *p_ctx); extern void resume(TCtx *p_ctx); TCtx ctx = { 4096 }; void bar(void); main(void) { exec(&ctx, bar); for (;;) { printf("Hello "); printf("World!\n"); resume(&ctx); } } void bar(void) { for (;;) { printf("This is "); printf("a pen.\n"); suspend(&ctx); } }
実行結果
This is a pen. Hello World! This is a pen. Hello World! This is a pen. Hello World! This is a pen. Hello World! (...以下略...)
上記mth_sample.cは、main()で"Hello "と"World!\n"を表示し、bar()で"This is "と"a pen.\n"を表示するプログラムである。表示は上記実行結果のように"This is a pen."と"Hello World!"が規則正しく交代し、決して"Hello a pen."になったり、"This is World!"になったりはしない。
main()が通常(非マイクロスレッド)コンテキスト、bar()がマイクロスレッドコンテキストで実行されている。