- 投稿日:2020-08-09T23:50:52+09:00
mallocのパラメータが環境変数から設定される流れ
はじめに
malloc関連のパラメータは
mallopt(3)
で変更することができます。
例えば、下記を実行することで、malloc内部でmmapを使うしきい値を1MBに変更することができます。mallopt(M_MMAP_THRESHOLD, 1024*1024);malloptで設定可能なパラメータのうちいくつかは、環境変数でも変更できます。
例えば、先述のM_MMAP_THRESHOLD
は、MALLOC_MMAP_THRESHOLD_
環境変数でも設定できます。$ export MALLOC_MMAP_THRESHOLD_=1048576 $ ./a.out環境変数であればプログラムの変更なしに適用できるので、システムのデフォルトを変更するときなどに有用です。
この環境変数によるmalloptの変更は、glibcのTunablesという仕組みを使っています。本記事ではglibcのtunablesが設定される流れを
MALLOC_MMAP_THRESHOLD_
環境変数を例に備忘メモとして残しておきます。
誤りなどありましたら、ご指摘いただければ幸いです。環境は以下のとおりです。
$ arch x86_64 $ uname -r 5.4.0-42-generic $ lsb_release -d Description: Ubuntu 18.04.4 LTS $ dpkg -l | grep libc-bin ii libc-bin 2.27-3ubuntu1.2 amd64 GNU C Library: Binaries
MALLOC_MMAP_THRESHOLD_
環境変数が反映される流れ1. ローダ(ld-linux.so)でauxiliary vectorを確認する
auxiliary vectorとは、
getauxval(3)
で取得することができる、
kernelのELF loaderから渡される実行ファイルの補助情報です。ローダで、auxiliary vectorから
AT_SECURE
情報を取得し、
AT_SECURE
が真の場合、global変数の__libc_enable_secure
が立ちます。ここで
AT_SECURE
は、少し勘違いしやすい名前ですが、
今のプロセスがセキュアに実行される必要があるということを意味します。
より具体的に言えば、下記のいずれかの場合にAT_SECURE
が立ちます。
- set-user-ID もしくは set-group-ID が有効なプログラム
- capabilitiesを付与されたプログラム
glibc-2.27/elf/dl-sysdep.cElfW(Addr) _dl_sysdep_start (void **start_argptr, void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum, ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv)) { ... for (av = GLRO(dl_auxv); av->a_type != AT_NULL; set_seen (av++)) switch (av->a_type) { ... case AT_SECURE: __libc_enable_secure = av->a_un.a_val; break; ... } __tunables_init (_environ); ... (*dl_main) (phdr, phnum, &user_entry, GLRO(dl_auxv)); return user_entry; }2. ローダで、環境変数の値から
tunable_list[]
を更新
__tunables_init
では、tunable_list[]
の中にある項目が環境変数に含まれている場合、
tunable_initialize()
で環境変数の値が反映されます。ただし、
__libc_enable_secure
が立っている場合(=AT_SECURE
が立っている場合)は、
以下の3種類のsecurity_level
に応じた処理が行われます。
SXID_ERASE
:AT_SECURE
の場合、子プロセスが読まないように環境変数から削除するSXID_IGNORE
:AT_SECURE
の場合、無視する(環境変数には残る)NONE
: 常に反映するglibc-2.27/elf/dl-tunables.cvoid __tunables_init (char **envp) { ... while ((envp = get_next_env (envp, &envname, &len, &envval, &prev_envp)) != NULL) { ... for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++) { tunable_t *cur = &tunable_list[i]; ... if (__libc_enable_secure) { if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE) { /* Erase the environment variable. */ ... } if (cur->security_level != TUNABLE_SECLEVEL_NONE) continue; } tunable_initialize (cur, envval); break; } } } }tunableの各項目の
security_level
は、環境変数名や型と併せて、.list
ファイルで定義されています。glibc-2.27/elf/dl-tunables.listglibc { malloc { ... mmap_threshold { type: SIZE_T env_alias: MALLOC_MMAP_THRESHOLD_ security_level: SXID_IGNORE } ... } }
scripts/gen-tunables.awk
によってdl-tunables.list
からdl-tunable-list.h
を自動生成し、
そこにtunable_list[]
が定義されます。dl-tunable-list.hstatic tunable_t tunable_list[] attribute_relro = { ... {TUNABLE_NAME_S(glibc, malloc, mmap_threshold), {TUNABLE_TYPE_SIZE_T, 0, SIZE_MAX}, {}, NULL, TUNABLE_SECLEVEL_SXID_IGNORE, "MALLOC_MMAP_THRESHOLD_"}, ... };3. 初回malloc時に、
tunable_list[]
からmp_
に反映ここからは、tunableの話ではなく、mallocパラメータ固有の話になります。
また、実行タイミングもローダではなく、普通のmain関数に入ってから初めてmallocが呼び出されたときです。プログラムで初めてメモリ確保関数を呼び出したときには、
malloc_hook_ini
が呼び出され、
そこからptmalloc_init
を呼び出します。glibc-2.27/malloc/hooks.cstatic void * malloc_hook_ini (size_t sz, const void *caller) { __malloc_hook = NULL; ptmalloc_init (); return __libc_malloc (sz); }
ptmalloc_init
では、2.で設定したtunable_listから、mmap_threshold
を取得し、
mallocパラメータをまとめて保持する構造体mp_
に設定します。glibc-2.27/malloc/arena.cstatic void ptmalloc_init (void) { ... TUNABLE_GET (mmap_threshold, size_t, TUNABLE_CALLBACK (set_mmap_threshold)); ... }glibc-2.27/elf/dl-tunables.cvoid __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback) { tunable_t *cur = &tunable_list[id]; switch (cur->type.type_code) { ... case TUNABLE_TYPE_SIZE_T: { *((size_t *) valp) = (size_t) cur->val.numval; break; } ... if (cur->initialized && callback != NULL) callback (&cur->val); }実際に設定するのは
do_set_mmap_threshold
関数です。
ここを見ると実は設定値の上限があったり、
mmap_threshold
を設定するときには動的なしきい値制御を無効にしていることがわかります。glibc-2.27/malloc/malloc.cstatic inline int __always_inline do_set_mmap_threshold (size_t value) { /* Forbid setting the threshold too high. */ if (value <= HEAP_MAX_SIZE / 2) { LIBC_PROBE (memory_mallopt_mmap_threshold, 3, value, mp_.mmap_threshold, mp_.no_dyn_threshold); mp_.mmap_threshold = value; mp_.no_dyn_threshold = 1; return 1; } return 0; }これで晴れて、
mmap
するかどうかの判断に、MALLOC_MMAP_THRESHOLD_
環境変数の値が使われるようになります。
めでたしめでたし。glibc-2.27/malloc/malloc.cstatic void * sysmalloc (INTERNAL_SIZE_T nb, mstate av) { ... if (av == NULL || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) && (mp_.n_mmaps < mp_.n_mmaps_max))) { ... mm = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0)); } }おわりに
mallocパラメータを環境変数で設定する場合、デバッガなりでちゃんと設定が反映されているか確認したほうが良いですね。
参考
mallocの動作を追いかける(環境変数編) - Qiita
mallopt(3) - Linux manual page
The GNU C Library
getauxval(3) - Linux manual page
- 投稿日:2020-08-09T17:19:01+09:00
Ansible入門 その① 'Hello World!!'
Ansibleとは?
概要
構成管理ツールと呼ばれ、
リモートマシンやサーバをプログラムに従って、自動で設定することができます。
いちいち同じ作業を繰り返してサーバの設定をしなくても、
Ansibleにコードさえ渡してしまえば何台でも彼が設定してくれる便利な友達。
テスト環境の再現も可能!メリット
- 冪等性
同じプログラムからならどこで何回やっても同じ結果が保証されています。- わかりやすい
メインプログラムは、YAML上に構築され、本当にわかりやすく読みやすい。- エージェントレス
構成管理ツールといえば、他にもいろいろなサービスがあるが、
多くがリモートホストにもそのソフトウェアを導入しなければ作動しない。
しかし、AnsibleはそんなことしなくてもSSH接続だけで、勝手に動く!- 任意のシェルコマンドがリモートサーバー上で実行可能
シェルコマンドを簡単にプログラムに実装可能です。有難い。
ちなみに、モジュールもたくさん用意されていて、色々便利。- すぐに使えるようになる
使えるようになるために必要な事前知識が少ないです。
なんなら、playbookに命令書くんだな。
そして、リモートホストはこう指定するんだな。で始められる気もする。Ansibleインストールに関して
Macユーザの方々は本当に楽です。
Ansible インストール
で検索ください。
Windowsユーザの方々は少し大変です。
僕も苦戦しました。もはや苦戦しかしていない。
仮想環境あるかたは、特に困らないのかもしれませんが、僕はdockerのコンテナ上に立ち上げるところから始めました。ちなみに最近はec2上に立ち上げたものを使っています。
docker Ansible
やaws Ansible
で検索すると色々出てくると思います。
【ちなみに私が参考にした記事様】
Docker編
【Ansible】DockerでAnsibleハンズオン
AWS編
【Ansible入門】EC2環境でAnsibleを実行してみよう「Hello World」を出力してみる
今回は、localHost(自分自身)を使ってHelloWorldを出力するものを作ってみます。
Ansibleの基本はこれで分かるかなと思います。必要なファイル
ファイル構成helloworld ├── playbook.yml └── inventoryplaybook.yml
Ansibleでの設定管理のスクリプト。
基本的にAnsibleを使っている間の時間はこいつを書くことに費やします。
簡単に言えば、サーバーにやってほしい命令とかを書きます。
inventory
どのリモートホストを対象とするかを記述したファイル。INI形式。inventoryの中身
inventory[target] localhostplaybookの中身
playbook.yml--- - hosts: all tasks: - name: Hello World! debug: msg: "Hello World!"YAML形式のファイルは字下げ(インデント)が大事ですので注意してください。
実行してみる
localhost$ ansible-playbook -i inventory playbook.yml PLAY [all] ********************************************************** TASK [Gathering Facts] ********************************************** ok: [localhost] TASK [helloworld : Hello World!] ************************************ ok: [localhost] => { "msg": "Hello World!" } PLAY RECAP ********************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0こんな感じで、実行すると実行結果がバーッと出てくると思います。
これでとりあえずAnsibleが動きますね。簡単かつ便利です。Ansible入門 その② '基本文法'
参考文献
初めてのAnsible(Lorin Hochstein著,玉川竜司訳,株式会社オライリー・ジャパン版)
Ansibleでできることを中の人が教えます
- 投稿日:2020-08-09T15:38:21+09:00
Node.js の再インストール
Nodeがおかしくなった
$ node Illegal instruction環境
2020-02-13-raspbian-buster-lite
既存の Node.js
「Linux 環境に Node.js インストール」
https://qiita.com/nanbuwks/items/ed8adb2d4324c939a349
の通り、以下のようにインストール1.Linux ディストリビューションの公式パッケージで Node.js と npm を入れる
2.npm install で最新の Node.js を入れる
3.古い Node.js を削除する削除
node のインストール先を調べる
```$ which node
/usr/local/bin/node
```ファイル削除
$ sudo rm -rf /usr/local/bin/node sudo rm -rf ~/.npm削除できたかな?
$ npm /usr/bin/env: ‘node’: No such file or directoryこのあと、先の資料「Linux 環境に Node.js インストール」をもう一度実行して入れ直します。
- 投稿日:2020-08-09T02:37:34+09:00
ferenOSの導入2(インストール後の設定、日本語入力の設定)
インストール後の設定
インストール完了後、システムの再起動を行います。(インストール時に使用したメディアは取り出します。)
Feren OSセットアップへようこそ画面
セットアッププログラムが立ち上がりますので、「ようこそ」画面の言語を日本語に設定したあと、「ロケーション」、「キーボード」、「ユーザー情報」を適宜設定します。
設定後、「Welcom to Feren OS」が立ち上がります。Welcom to Feren OS画面
好きなデスクトップレイアウトを選んでください。英語ですが、感覚的に選べると思います。
テーマとカラーを選んでください。
動画や音楽のサードパーティのコーデックをインストールできます。
その他、KDEConnectやNightCoulorなどの設定ができます。日本語入力の設定
インストール直後には、すでに日本語化されているferenOSですが、日本語入力はまだできない状態です。そこで、日本語入力できるように設定を行います。この作業もアプリケーション上で行えます。
デスクトップ上の「Welcom Screen」アイコンから
[Main Menu]>[Getting started]>[Language & Input]へと進み設定を行います。
インプットメソッドのFcitxをインストールし、[Input Method]のボタンから設定を行います。
画像の右側ウィンドウにあるように、言語サポートパッケージをインストールすることで日本語入力が可能になります。インストール後、再度ログインして入力方式フレームワークをFcitxに切り替えることで日本語入力可能です。変換システムはmozcになります。また、Ibusでも日本語入力は可能ですし、変換システムにanthyも導入可能です。