pthread_createで作成したスレッドのデフォルトのスタックサイズは何バイトであろうか?
ググってみると、以下の記載を見つけた。
NPTL の実装では以下の点についても注意すること: – スタックサイズのリソースのソフト・リミット (setrlimit(2) の RLIMIT_STACK の説明を参照) が unlimited 以外の値に設定されている場合、ソフト・リミットの値が 新しいスレッドのデフォルトのスタックサイズとなる。 設定を有効にするためには、プログラムを実行する前にリミット値を 設定しておかなければならない。たいていは、シェルの組み込みコマンドの ulimit -s (C シェルでは limit stacksize) を使って設定する。
ちなみに、CentOS 5.5 で、”man -s 7 pthreads” としても上記の情報は出て来ない。また、スレッドとスタック – memologue という記事も見つけ、ulimit -s の値が使用される、という点については間違いが無さそうだ。
ということで、実験してみた。
実験①:スレッドを作成した後に pmap で確認する。
以下のソースファイルをコンパイルして実行する。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <sys/time.h> static void *thread_main(void *_p); int main(void) { pthread_t pth; int ret; pthread_create( &pth, NULL, thread_main, NULL ); pthread_join(pth, NULL); return 0; } static void *thread_main(void *_p) { usleep(100 * 1000 * 1000); // 100s }
結果は以下のとおりとなった。
恐らく、8200K で [anon]になっている領域がスレッドスタック領域で、ulimit -s の値が設定されていそうである。
[fumi@unryu tmp]$ ulimit -s 8192 [fumi@unryu tmp]$ ./a.out & [1] 27055 [fumi@unryu tmp]$ pmap 27055 27055: ./a.out 08048000 4K r-x-- /tmp/a.out 08049000 4K rw--- /tmp/a.out 0804a000 132K rw--- [ anon ] 4712a000 108K r-x-- /lib/ld-2.5.so 47145000 4K r---- /lib/ld-2.5.so 47146000 4K rw--- /lib/ld-2.5.so 47149000 1356K r-x-- /lib/libc-2.5.so 4729c000 8K r---- /lib/libc-2.5.so 4729e000 4K rw--- /lib/libc-2.5.so 4729f000 12K rw--- [ anon ] 472d6000 84K r-x-- /lib/libpthread-2.5.so 472eb000 4K r---- /lib/libpthread-2.5.so 472ec000 4K rw--- /lib/libpthread-2.5.so 472ed000 8K rw--- [ anon ] b7034000 4K ----- [ anon ] b7035000 8200K rw--- [ anon ] b7846000 4K r-x-- [ anon ] bfd4b000 132K rw--- [ stack ] total 10076K [fumi@unryu tmp]$
実験②:pthread_createする前にsetrlimitでスタックサイズを設定したらどうなるか?
最上部に引用した ubuntu のマニュアルには、以下のようにあるが、「pthread_create する前」でなく「プロセス実行前」ということに疑問を持ち実験。
設定を有効にするためには、プログラムを実行する前にリミット値を 設定しておかなければならない。たいていは、シェルの組み込みコマンドの ulimit -s (C シェルでは limit stacksize) を使って設定する。
上記ソースにsetrlimitを追加。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <sys/time.h> #include <sys/resource.h> static void *thread_main(void *_p); int main(void) { pthread_t pth; int ret; struct rlimit rlim; rlim.rlim_cur = 2 * 1024 * 1024 ; // 2M rlim.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_STACK, &rlim); pthread_create( &pth, NULL, thread_main, NULL ); pthread_join(pth, NULL); return 0; } static void *thread_main(void *_p) { usleep(100 * 1000 * 1000); // 100s }
結果は変わらかったので。8Mのスタックが確保されていた。この理由についてググってもあまり良い情報が見つけられなかったので、glibc のソースファイルを眺めてみることにした。
pthread ライブラリをリンクしたプログラムを動かした場合、
nptl/sysdeps/pthread/pt-initfini.c の以下の _init 関数が .init セクションに配置されるため main 関数より先に実行される。
SECTION (".init"); extern void __attribute__ ((section (".init"))) _init (void); void _init (void)
その延長で、nptl/nptl-init.c の __pthread_initialize_minimal_internal関数が呼び出され、その中で、以下のように __default_stacksize というグローバル変数に値を設定していたため、main 関数内で、setrlimit で設定しても意味を持たない。
/* Determine the default allowed stack size. This is the size used in case the user does not specify one. */ struct rlimit limit; if (getrlimit (RLIMIT_STACK, &limit) != 0 || limit.rlim_cur == RLIM_INFINITY) /* The system limit is not usable. Use an architecture-specific default. */ limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE; else if (limit.rlim_cur < PTHREAD_STACK_MIN) /* The system limit is unusably small. Use the minimal size acceptable. */ limit.rlim_cur = PTHREAD_STACK_MIN; /* Make sure it meets the minimum size that allocate_stack (allocatestack.c) will demand, which depends on the page size. */ const uintptr_t pagesz = __sysconf (_SC_PAGESIZE); const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK; if (limit.rlim_cur < minstack) limit.rlim_cur = minstack; /* Round the resource limit up to page size. */ limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz; __default_stacksize = limit.rlim_cur;