pthread_once()について

pthread_once()の使い方がよくわからなかったので調べてみた。 このページ(*)が分り易かったからまとめておく。

1. 用途

-初期化に使う --通常初期化はプログラムの開始時に実施*1 --でも、できない場合もある ---例えば、ライブラリを作成する場合、初期化してもらえるかわからん ---仕方ないから呼ばれた時に呼ばれた側で初期化しよう ---エントリポイントのすべてで初期化されたかを判定して初期化処理を書くのは馬鹿らしい --一回だけ実行する仕組みを作ろうぜ

→ pthread_once()

2. 定義

int pthread_once( pthread_once_t * once_control, void (*init_routine)(void));
once_control:制御変数。PTHREAD_ONCE_INIT で初期化。
init_routine:1回だけ呼ばれる初期化用関数。

3. 使い方の例

(*)にあるプログラムを実行しようと思ったんだけど、once_main.cが見つからなかったので、書いてみた。

#include <stdio.h>
#include <pthread.h>

extern void *thread_func1(void *);
extern void *thread_func2(void *);
extern void *thread_func3(void *);
extern void *thread_func4(void *);

int main(void)
{
        int i = 0, j = 0;
        int ret;
        pthread_t th[4];

        fprintf(stderr, "main starts!\n");

        ret = pthread_create(&th[i], NULL, thread_func1, NULL);
        if (ret != 0) {
                perror("pthread_create");
                goto out;
        }

        ret = pthread_create(&th[++i], NULL, thread_func2, NULL);
        if (ret != 0) {
                perror("pthread_create");
                goto out;
        }

        ret = pthread_create(&th[++i], NULL, thread_func3, NULL);
        if (ret != 0) {
                perror("pthread_create");
                goto out;
        }

        ret = pthread_create(&th[++i], NULL, thread_func4, NULL);
        if (ret != 0) {
                perror("pthread_create");
                goto out;
        }

out:
        while (j < i)
                pthread_join(th[j++], NULL);

        fprintf(stderr, "main ends\n");
        return 0;
}

これとonce_thread.cをビルドして実行するとこんな感じ。

$ ./once 
main starts!
in thread_func2, before once_func.
in thread_func3, before once_func.
in thread_func1, before once_func.
in thread_func4, now start.
initializing function Start!!
in thread_func4, now end.
initializing function End...
in thread_func2, after once_func.
in thread_func3, after once_func.
in thread_func2, mutex_lock OK.
in thread_func1, after once_func.
in thread_func2, mutex_unlock OK.
in thread_func2, timesec:[5.000698]
in thread_func3, mutex_lock OK.
in thread_func3, mutex_unlock OK.
in thread_func3, timesec:[6.001000]
in thread_func1, mutex_lock OK.
in thread_func1, mutex_unlock OK.
in thread_func1, timesec:[7.001423]
main ends

pthread_once()で実行するonce_func()は一度のみ実行されているし、同時に実行している他のスレッドはblockしてるのがわかる。

今日はここまで。

*1:コンストラクタとか

_smp_mflags

kernelのSRPMを展開して得られるSPECファイルを見るとビルドのところに、_smp_mflagsというのが出てくる。例えば、kernel.specだとこんな感じ。

BuildKernel() {
    MakeTarget=$1
    KernelImage=$2
    Flavour=$3
    InstallName=${4:-vmlinuz}

<snip>

    make -s ARCH=$Arch oldnoconfig >/dev/null
    make -s ARCH=$Arch V=1 %{?_smp_mflags} $MakeTarget %{?sparse_mflags}
    make -s ARCH=$Arch V=1 %{?_smp_mflags} modules %{?sparse_mflags} || exit 1

<snip>

で、この_smp_mflagsなんだが-jX*1に展開されるのだけど、気が向いた時、ビルドの時間を短くするためにXをCPU数の2倍位にしたりすることがあったり。で、本当気が向いた時だけやってるので、SPECを手動で書き換えているのだけど、まあよく忘れるし、適当過ぎよねということで、さらっと調べてみたのでメモしておく*2

まず、_smp_mflagsrpmのマクロになります。で、rpmのマクロの定義は/usr/lib/rpm/にある。マクロを定義しているファイルはいろいろあるので、grepしてみた。

$ grep -r _smp_mflags /usr/lib/rpm/
/usr/lib/rpm/platform/pentium3-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/x86_64-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/athlon-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/noarch-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/i486-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/i686-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/pentium4-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/ia32e-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/geode-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/amd64-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/i386-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/platform/i586-linux/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
/usr/lib/rpm/redhat/macros:%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\

まあ、こんな感じでたくさん出てくるわけだが、その中の/usr/lib/rpm/redhat/macrosを見てみると次のようになってた。

%_smp_mflags %([ -z "$RPM_BUILD_NCPUS" ] \\\
        && RPM_BUILD_NCPUS="`/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\
        if [ "$RPM_BUILD_NCPUS" -gt 16 ]; then echo "-j16"; \\\
        elif [ "$RPM_BUILD_NCPUS" -gt 1 ]; then echo "-j$RPM_BUILD_NCPUS"; fi)

RPM_BUILD_NCPUSが0だったらgetconf _NPROCESSORS_ONLNの結果を代入する。 sysconf(3)のmanを見たら、_SC_NPROCESSORS_ONLNは現在オンラインのCPU数を返すとのことなので、getconfでも同じと思われ、_smp_mflagsには現在オンラインのCPU数が入るはず。これで_smp_mflagsの定義が分かりましたとさ。

このマクロファイルをいじってあげれば、好きに設定できると。今度は忘れないようにしましょう。

(追記) マクロの中身を確認するのに、なにも/usr/lib/rpm/以下をgrepしなくてもよいみたい。rpmコマンドで調べられる模様。

$ rpm --eval %macro

macroの部分に知りたいマクロを入れればOK。

参考:RPMマクロ - N.E.E.T―Never Ending Engineer’s Tragicomedy別館

*1:XはCPUの数

*2:前も調べたんだけど、すっかり忘れてた

/proc/kallsymsの"t"とか"T"とか

意味はnmコマンドのと同じ。

$ man nm

で調べられる。


一応貼っとく。

 "A" The symbol’s value is absolute, and will not be changed by further linking.

 "B"
 "b" The symbol is in the uninitialized data section (known as BSS).

 "C" The symbol is common.  Common symbols are uninitialized data.
     When linking, multiple common symbols may appear with the same
     name.  If the symbol is defined anywhere, the common symbols are
     treated as undefined references.

 "D"
 "d" The symbol is in the initialized data section.

 "G"
 "g" The symbol is in an initialized data section for small objects.
     Some object file formats permit more efficient access to small
     data objects, such as a global int variable as opposed to a large
     global array.

 "i" The symbol is in a section specific to the implementation of DLLs.

 "N" The symbol is a debugging symbol.

 "p" The symbols is in a stack unwind section.

 "R"
 "r" The symbol is in a read only data section.

 "S"
 "s" The symbol is in an uninitialized data section for small objects.

 "T"
 "t" The symbol is in the text (code) section.

 "U" The symbol is undefined.

 "V"
 "v" The symbol is a weak object.  When a weak defined symbol is
     linked with a normal defined symbol, the normal defined symbol
     is used with no error.  When a weak undefined symbol is linked
     and the symbol is not defined, the value of the weak symbol becomes
     zero with no error.  On some systems, uppercase indicates that
     a default value has been specified.

"W"
"w" The symbol is a weak symbol that has not been specifically tagged
    as a weak object symbol.  When a weak defined symbol is linked with
    a normal defined symbol, the normal defined symbol is used with
    no error.  When a weak undefined symbol is linked and the symbol
    is not defined, the value of the symbol is determined in a system-specific
    manner without error.  On some systems, uppercase indicates that
    a default value has been specified.

"-" The symbol is a stabs symbol in an a.out object file.  In this
    case, the next values printed are the stabs other field, the stabs
    desc field, and the stab type.  Stabs symbols are used to hold
    debugging information.

"?" The symbol type is unknown, or object file format specific.

emacsのロードパスの設定

Emacsの設定 -起動・終了編- - intrinsic feelingを参考に設定。


例えば/home/shared/emacs/site-lispにロードパスを通したいときは
.emacsの先頭付近に次の行を追加

(setq load-path (append (list
                         (expand-file-name "/home/shared/emacs/site-lisp")
                         )
                        load-path))

nouveau

fedora12だとnVidiaのグラボ用のドライバとしてnouveauが入っているわけですが、
2.6.33にnouveauが入ってくるみたいですね。


stagingドライバのとこに入ってたYO。
今日気がついたよ。

でも、チェックしてコンパイル/インストールしたら↓のがいっぱい出てきた。
firmwareがないのか?
気持ち悪。

W: Possible missing firmware nouveau/nv4e.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv4e.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv4c.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv4c.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv4b.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv4b.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv4a.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv4a.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv49.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv49.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv47.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv47.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv46.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv46.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv44.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv44.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv43.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv43.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv42.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv42.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv41.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv41.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv40.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv40.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nvac.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nvac.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nvaa.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nvaa.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nva8.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nva8.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nva5.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nva5.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nva0.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nva0.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv98.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv98.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv96.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv96.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv94.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv94.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv92.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv92.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv86.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv86.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv84.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv84.ctxprog for module nouveau.ko
W: Possible missing firmware nouveau/nv50.ctxvals for module nouveau.ko
W: Possible missing firmware nouveau/nv50.ctxprog for module nouveau.ko