スポンサードリンク

Linux の pthread のデフォルトスタックサイズについて

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;

rsyncでローカルのデータの同期

rsyncってrシリーズなのでリモートのホストとの同期しかできないかと思っていたけど、ローカルディレクトリの同期もできるんだね。

そもそも、同期が何で必要かと言うと、嫁さんが、「友達の家で、写真とかビデオとかのデータが壊れた。バックアップもしていない」という話を聞いた。その後、友達は「夫がバックアップしておかないから、離婚も考えた」とか言うもんだから、我が家にある写真などのデータを外付けHDDにも定期的に同期してバックアップしておこうと考え、rsyncを使うようになった。

Linuxのバックアップツールを探していたときに、tar -u も考えたんだけど、更新が無くてもディスクアクセスが半端なく多いので、今回の用途としては rsync の方が向いていると考えた。

linux (Centos)マシンをhostapdでAP化

我が家のLinuxのサーバであるFMV-7090MT4には、PCカードスット×1とCFカードスロット×1が付いている。PCカードはEthernetカードを入れてあり、CFカードにはPSPとDSのために WLI2-CF-S11 をhostap 機能でAP(アクセスポイント)化してある。サーバのHDDがポシゃったため、再インストールしてから構築する時にメモが無く苦労したので、ここに残しておく。

  • カーネルの再構築:
    drivers/net/wireless/hostap/hostap_cs.c の 810行目あたりに以下を追加する。もしかしたらソースに記載しなくてもいいのかもしれないけれど良くわからないので追加した。当然ながら、hostap と、wireless lan 自体を使えるようにしておくこと

    PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI2-CF-S11", 0x2decece3, 0x3beea320),
    
  • hostapd のコンパイル:
    ドライバは hostp にてコンパイルすること。
  • hostpad の設定
    以下のとおり、hostapd.conf を設定した。

    interface=wlan0
    driver=hostap
    logger_syslog=-1
    logger_syslog_level=2
    logger_stdout=-1
    logger_stdout_level=0
    dump_file=/tmp/hostapd.dump
    ctrl_interface=/var/run/hostapd
    ssid=##SSID
    ignore_broadcast_ssid=2
    country_code=JP
    ieee80211d=1
    hw_mode=b
    channel=2
    beacon_int=100
    dtim_period=2
    max_num_sta=255
    rts_threshold=2347
    fragm_threshold=2346
    macaddr_acl=1
    accept_mac_file=/usr/local/hostapd/etc/mac.accept # ← 当然PSP,DSの無線LANのMACアドレスを記載しておく
    deny_mac_file=/usr/local/hostapd/etc/mac.deny
    auth_algs=3
    wep_default_key=0
    wep_key0=##WEPのキー
    
  • wlan0の設定
    /etc/sysconfig/network-scripts/ifcfg-wlan0 の内容が dhcp で取得する内容となっていたので、静的に割当てるように変更する。

    # BUFFALO WLI2-CF-S11
    DEVICE=wlan0
    BOOTPROTO=static
    ONBOOT=yes
    IPADDR=##IPアドレス
    NETMASK=##サブネットマスク
    HWADDR=##MACアドレス
    
  • hostapd の起動
    起動は起動スクリプトから行なうこと!(ここで大分ハマった)。
    起動スクリプトでは起動だけでなく、iwconfig により、wep keyの設定を行なっている。そのため、hostapd を単体で起動させても wep キーが設定されず、うまく繋らない。
  • iptablesの設定
    wlan0 はDS,PSPのネット接続が目的であるため wep という脆弱な暗号化しかかけられない。そのため、iptables でネットに出ていく方向のみ許可するようなルールを追加しておく

XCreateFontSet のメモリリーク

にハマる。

まーとりあえず、それは回避して X11 でも日本語出るようになりました。

参考:
XCreateFontSet()/XFreeFontSet()によりメモリリークが発生する。

HDDのアクセスが妙に遅く感じるときは

HDDのアクセスが妙に遅く感じるときは

メモ。このマシンも大分速くなった。

てっきり、DMA なんかデフォで効いていると思っていたけど……。