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;

コメントを残す

メールアドレスが公開されることはありません。