Open4

WasmLinux: スレッドが正常に終了しない問題

okuokuokuoku

pthreadで作成したスレッドから return してもスレッドが消えてくれず、しかも何かスケジューラが狂う。

とりあえず do_task_dead から戻ってしまっているっぽいので、その理由をstep実行で追う。

okuokuokuoku

最後のswitch toで暴走が始まる

backtrace的には __switch_tosem_down の箇所に居る。このまま thread_exit まで走るのが期待値だが、downしたまま帰ってきていない。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/arch/lkl/kernel/threads.c#L111-L116

... そもそも arch_free_task_stack が呼ばれてないな。。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/arch/lkl/kernel/threads.c#L53-L70

ユーザスレッドを実装するためには、この辺の実装の補完が必要っぽい。

(lldb) bt
* thread #29, name = 'runner'
  * frame #0: 0x00007ffff7b2cb4d libc.so.6`syscall + 29
    frame #1: 0x00000000026a6f8b runner`void std::__detail::__platform_wait<int>(__addr=0x00007ffd78000bc0, __val=0) at atomic_wait.h:112:21
    frame #2: 0x00000000026a705c runner`void std::__atomic_wait_address_bare<std::__atomic_semaphore::_M_acquire()::'lambda'()>(__addr=0x00007ffd78000bc0, __pred=(unnamed struct) @ 0x00007ffd7fffe4e0) at atomic_wait.h:448:29
    frame #3: 0x00000000026a73af runner`std::counting_semaphore<2147483647l>::acquire() [inlined] std::__atomic_semaphore::_M_acquire(this=0x00007ffd78000bc0) at semaphore_base.h:215:38
    frame #4: 0x00000000026a7394 runner`std::counting_semaphore<2147483647l>::acquire(this=0x00007ffd78000bc0) at semaphore:74:26
    frame #5: 0x00000000026a5230 runner`mod_syncobjects(in=0x00007ffe38e81c58, out=0x00007ffdf7a22000) at runner.cpp:606:41
    frame #6: 0x00000000026a6824 runner`w2c_env_nccc_call64(env=0x0000000000000000, inptr=1095105616, outptr=0) at runner.cpp:1182:28
    frame #7: 0x0000000001374889 runner`w2c_kernel_host_sem_down(instance=0x00007ffd74000b70, var_p0=62) at lin.c:1704678
    frame #8: 0x000000000120065e runner`w2c_kernel_0x5F_switch_to(instance=0x00007ffd74000b70, var_p0=458636, var_p1=258) at lin.c:1560848
    frame #9: 0x00000000010aec3e runner`w2c_kernel_0x5F_schedule(instance=0x00007ffd74000b70, var_p0=943677440) at lin.c:1427291
    frame #10: 0x00000000010ad492 runner`w2c_kernel_do_task_dead(instance=0x00007ffd74000b70) at lin.c:1426837
    frame #11: 0x0000000000f17dfc runner`w2c_kernel_do_exit(instance=0x00007ffd74000b70, var_p0=1095106264) at lin.c:1269310
    frame #12: 0x0000000000f18e67 runner`w2c_kernel_do_group_exit(instance=0x00007ffd74000b70, var_p0=0) at lin.c:1269701
    frame #13: 0x0000000000f18eb6 runner`w2c_kernel_0x5F_se_sys_exit_group(instance=0x00007ffd74000b70, var_p0=0) at lin.c:1269714
    frame #14: 0x0000000001350988 runner`w2c_kernel_lkl_syscall(instance=0x00007ffd74000b70, var_p0=94, var_p1=1, var_p2=948842128) at lin.c:1692095
    frame #15: 0x000000000137395c runner`w2c_kernel_syscall_0(instance=0x00007ffd74000b70, var_p0=94, var_p1=1, var_p2=948842128) at lin.c:1704248
    frame #16: 0x0000000000403f37 runner`w2c_kernel_syscall(instance=0x00007ffd74000b70, var_p0=94, var_p1=1, var_p2=948842128) at lin.c:191103:10
    frame #17: 0x00000000026a46db runner`runsyscall32(no=94, nargs=1, in=948842128) at runner.cpp:257:30
    frame #18: 0x00000000026a4878 runner`w2c_env_wasmlinux_syscall32(env=0x0000000000000000, argc=1, no=94, args=948842128) at runner.cpp:330:24
    frame #19: 0x0000000002684941 runner`w2c_user_0x5FExit(instance=0x00007ffd74000bc0, var_p0=0) at user.c:2868:12
    frame #20: 0x0000000002684c24 runner`w2c_user_exit(instance=0x00007ffd74000bc0, var_p0=0) at user.c:2930:3
    frame #21: 0x000000000269ea1f runner`w2c_user_0x5F_pthread_exit(instance=0x00007ffd74000bc0, var_p0=1059458288) at user.c:11878:3
    frame #22: 0x00000000026a150a runner`w2c_user_start(instance=0x00007ffd74000bc0, var_p0=948842352) at user.c:12855:3
    frame #23: 0x00000000026a4e8f runner`thr_uthr(args=0x0000000000000000) at runner.cpp:521:10
    frame #24: 0x00000000026a95b6 runner`void std::__invoke_impl<void, void (*)(userthr_args*), userthr_args*>((null)=__invoke_other @ 0x00007ffd7fffeb10, __f=0x00007ffd78000d40, (null)=0x00007ffd78000d38) at invoke.h:61:36
    frame #25: 0x00000000026a9303 runner`std::__invoke_result<void (*)(userthr_args*), userthr_args*>::type std::__invoke<void (*)(userthr_args*), userthr_args*>(__fn=0x00007ffd78000d40, (null)=0x00007ffd78000d38) at invoke.h:96:40
    frame #26: 0x00000000026a903d runner`void std::thread::_Invoker<std::tuple<void (*)(userthr_args*), userthr_args*>>::_M_invoke<0ul, 1ul>(this=0x00007ffd78000d38, (null)=_Index_tuple<0, 1> @ 0x00007ffd7fffeb70) at std_thread.h:292:26
    frame #27: 0x00000000026a8edc runner`std::thread::_Invoker<std::tuple<void (*)(userthr_args*), userthr_args*>>::operator()(this=0x00007ffd78000d38) at std_thread.h:299:20
    frame #28: 0x00000000026a8e4e runner`std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(userthr_args*), userthr_args*>>>::_M_run(this=0x00007ffd78000d30) at std_thread.h:244:20
    frame #29: 0x00007ffff7ce31b3 libstdc++.so.6`execute_native_thread_routine + 19
    frame #30: 0x00007ffff7aae947 libc.so.6`start_thread + 759
    frame #31: 0x00007ffff7b34860 libc.so.6`__clone3 + 48

そもそも、 sys_exit_group なのも間違ってるな。。libcがスレッド対応になっていないっぽい。

okuokuokuoku

急にexitしてくるのは clone のvararg処理ミスだった

このミスによりTLSが設定されない → pthread_self() が誤動作する → 自分が最後のスレッドだと勘違いして exit する のコンボが決まっていた。

https://github.com/okuoku/wasmlinux-musl/commit/e47d3118e450da7ebd842f0e993ae3fa4198c5fe

... CLEARの方を見ないとダメだったね。。

ここまでで、 pthread_createpthread_exitpthread_join まで確認できたので、とりあえずスレッドの基本的な挙動は実現できていると思う。さぁシグナルだ。。