WasmLinux: スレッド生成に対応する
 okuoku
okuokuシグナルの前哨戦って事で。。
Muslは __clone 関数をarch毎に実装することを求めている。生の clone3 はそもそもarch毎に実装が違う。で、この __clone は posix_spawn と スレッドの生成専用となっている。
この __clone はglibcのラッパ( clone(2) に言及がある)の仕様になっている。このwrapper自体はMuslにも実装されている:
従来のfork実装は fork や旧 clone を直接使っている。
 okuoku
okuoku
 __clone 呼ぶ準備
とりあえず glibc ラッパと同様の機能性をランタイム側に作り込むことにする。簡単のために、可変長引数の部分はMusl内部で事前に展開しておく。
 okuoku
okuoku機能性の確認(pthread_create)
Muslが pthread_create で指定してくるCLONEのフラグは以下:
スレッドで常識的に必要なもの: CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM これらは要するに新規スレッドの常識的なパラメタと言える。全てを呼出し元と共有する。これらはこのまま渡す。
CLONE_CHILD_CLEARTID はfutex起床をセットする(引数 ctid)。 これはランタイムでエミュレートする。 一旦カーネルに渡してみる。
CLONE_PARENT_SETTID は呼出し元に tid を返却する(引数 ptid)。 これもランタイムでエミュレートする。 一旦カーネルに渡してみる。
CLONE_SETTLS は新規スレッドにTLSポインタをセットする。データは TP_ADJ マクロの返値、つまり struct pthread へのポインタになる。LKL的なTLSにセットするとかで良いのかな。カーネルに渡す必要は無いはず。設定したデータを返却する __get_tp は今stubしてるので実装する必要がある。
CLONE_DETACHED は今は効果が無い。
 okuoku
okuoku
 mmap に失敗する
...まぁnommuだしな。。いや MAP_ANON は出来るはず。。
* thread #28, name = 'runner', stop reason = breakpoint 2.1
    frame #0: 0x000000000269cf42 runner`w2c_user_0x5F_mmap(instance=0x00000000029b0260, var_p0=0, var_p1=0, var_p2=3, var_p3=34, var_p4=4294967295, var_p5=0) at user.c:11227:7
引数が、 0, 0, 3, 34, -1, 0 。
size がゼロって事は、 __default_stacksize がおかしい。。?でもステップ実行する限りはちゃんとデフォルトの1MiBになっている:
Process 21692 stopped
* thread #28, name = 'runner', stop reason = step over
    frame #0: 0x000000000269fab8 runner`w2c_user_0x5F_pthread_create(instance=0x00000000029b0260, var_p0=1042546660, var_p1=0, var_p2=3, var_p3=0) at user.c:12227:39
   12224          var_i2 = 3000u; // ★ このオフセットに __default_stacksize がある
   12225          var_i1 += var_i2;
   12226          var_i1 = i32_load(instance->w2c_env_memory, (u64)(var_i1));
-> 12227          i32_store(instance->w2c_env_memory, (u64)(var_i0) + 168, var_i1);
   12228          var_i0 = var_l4;
   12229          var_i1 = var_l5;
   12230          var_i2 = 3004u;
(lldb) p var_i1
(u32) $3 = 131072
どうも PAGESIZE を設定していないとこうなるようだ。。というわけで設定しておいた。というかARMはPagesizeがABIで固定されてないのか。。(なので変数を見ている)
ついでに、 __get_tp() も実装しておいた。
ここまでで、 pthread_create(3) で clone(2) してくるところまでは動作確認できた。
 okuoku
okuokuとりあえず動いた

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
static void*
thr_test(void* bogus){
    int counter;
    counter = 0;
    for(;;){
        fprintf(stderr, "Print from worker thread... %d\n", counter);
        counter++;
        sleep(2);
        if(counter == 2){
            //return 0;
        }
    }
    return 0;
}
int
__original_main(int ac, char** av, char** envp){
    int count = 0;
    fprintf(stderr, "Hello, world!\n");
    int r;
    void* p;
    pthread_t thr;
    r = pthread_create(&thr, 0, thr_test, 0);
    //pthread_join(thr, &p);
    for(;;){
        fprintf(stderr, "Sleep...%d\n", count);
        count++;
        sleep(1);
    }
    return 0;
}
ただし pthread_join を掛けるとfutex呼びまくってデバッグできなくなる。