20191203のLinuxに関する記事は10件です。

SSH ポートフォワーディング時に Bad local forwarding specification エラーでハマった話

SSH ポートフォワーディングについては下記記事がわかりやすいです。
SSH ポートフォワーディング とは

再現した環境

  • macOS Mojave / Catalina
  • OpenSSH_7.9p1, LibreSSL 2.7.3

エラーでハマる

いつものように下記コマンドを叩いた。

ssh -L ローカルのポート番号:接続したいサーバ:接続したいサーバのポート番号

しかし、エラーが出て、動作しなかった!

Bad local forwarding specification 'ローカルのポート番号:接続したいサーバ:接続したいサーバのポート番号'

スペースが足りなかったり、余分なスペースが入ると出るエラーらしい(参考)が、
確認しても間違いが見つからなかった。

原因

Mac のデフォルトのメモ帳からコマンドをコピペして、そのままコマンドラインに貼り付けていたから。
形式が勝手に変わってしまうから?
本当の原因は不明...

尚、メモ帳のコマンドをコピーして、 Slack などに一度ペーストし、更に Slack にペーストしたコマンドをコピーしてコマンドラインにペーストすると、動作する。(なぜ...)

何度も使うコマンドを Mac のデフォルトのメモ帳に保存しておくことがあるが、動作しないこともあるので注意するべきなのかもしれない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ShellScript Bash 変数に「*」を格納して出力する時に少し詰まったところ

目的

  • ShellScriptのBashで変数に文字列として*を出力する際に詰まったところをまとめる

結論

  • 変数を出力するときに変数名を""で囲む
  • echo "${変数名}"

筆者が困った流れ

  1. 変数FOO*を格納して出力したくなった。
  2. 下記コマンドを実行して*を変数FOOに格納した。

    FOO="*"
    
  3. ~/ディレクトリで下記コマンドを実行して変数FOOを展開しようとしたが、カレントディレクトリのフォルダが出力されてしまった。

    echo ${FOO}
    >Applications Desktop Documents Downloads Library Movies Music Pictures Public tig workspace
    
  4. *が出力されない・・・。

解決方法

  • 変数名を""で囲むことで出力することができた。
  • 下記に*を出力する方法を記載する。

    $ echo "${FOO}"
    >*
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#Linux の touch でファイル作成をする時にディレクトリが存在しなくてもエラーを起こさない mkdir -p みたいなエイリアスを作る

settiing

以下をコンソールで直接実行

あるいは

~/.zshrc ~/.bashrc などにエイリアスを登録して関数を作る

function touchp() { mkdir -p $(dirname "$1"); touch "$1"; }

execute

touchp ~/too/deep/dir/dir/dir/file.txt

Ref

mkdir + touch を実現するコマンドinstall - Qiita

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2801

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux コマンドを打った自分のログを取得していく方法

Linuxのログを取得する方法はいくつかあると思いますが自分がいつも実施する方法を記載します。

1 .bash_profileファイル編集

nano .bash_profile viかnanoなどで編集してください。

nano .bash_profile
script -q -f -a ../../etc/xxx/xxx.log

2 logファイルの権限変更

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZynqMP で Linux の CMA 領域を devicetree の reserved-memory で指定した時のアライメントは 0x00400000(4MiB) 単位

Linux ではデバイスツリーで次のように reserved-memory(予約メモリ)空間を指定出来ます。

devicetree.dts
/ {
    #address-cells = <2>;
    #size-cells = <2>;
    image_buf0: image_buf@0 {
        compatible = "shared-dma-pool";
        reusable;
        reg = <0x0 0x6fc00000 0x0 0x00400000>;
        alignment = <0x0 0x1000>;
        label = "image_buf0";
    };
};

この時、resuable プロパティを付けることによって、予約したメモリ領域を CMA 領域として使うことが出来ます。例えば ZynqMP-FPGA-Linux で上記のデバイスツリーを追加して Linux Kernel を起動すると、次のようなログが出ます。

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
[    0.000000] Linux version 4.19.0-xlnx-v2019.1-zynqmp-fpga (ichiro@Jabberwock) (gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04)) #2 SMP Wed Jul 17 15:19:07 DST 2019
[    0.000000] Machine model: Avnet Ultra96 Rev1
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: UEFI not found.
[    0.000000] Reserved memory: created CMA memory pool at 0x000000006fc00000, size 4 MiB
[    0.000000] OF: reserved mem: initialized node image_buf@0, compatible id shared-dma-pool
[    0.000000] cma: Reserved 256 MiB at 0x0000000070000000
   :
   :
   :

このログを見てわかるように、0x000000006fc00000 から 4MiB が CMA 領域として確保されています。

実はこの件に関して udmabuf に issue があげられました。

この issue によれば、次のようなデバイスツリーの設定だと、

devicetree.dts
    reserved-memory {
        #address-cells = <2>;
        #size-cells = <2>;
        ranges;
        rproc_0_reserved: rproc@3ed00000 {
            no-map;
            reg = <0x0 0x3ed00000 0x0 0x1000000>;
        };
        image_buf0: image_buf@0 {
            compatible = "shared-dma-pool";
            reusable;
            reg = <0x0 0x6fc00000 0x0 0x0100000>;
            alignment = <0x0 0x1000>; 
            label = "image_buf0";
        };
    };
    udmabuf@0 {
        compatible = "ikwzm,udmabuf-0.10.a";
        device-name = "udmabuf0";
        size = <0x0 0x0100000>;
        memory-region = <&image_buf0>;
    };

"incorrect alignment of CMA region" というエラーが出て CMA 領域の確保に失敗します。

[ 0.000000] Reserved memory: incorrect alignment of CMA region
[ 0.000000] cma: Reserved 256 MiB at 0x000000005fc00000
  :
  :
  :
[ 127.914295] udmabuf udmabuf@0: of_reserved_mem_device_init failed. return=-22
[ 127.921580] udmabuf udmabuf@0: driver installed.
[ 127.926204] udmabuf: probe of udmabuf@0 failed with error -22
[ 127.932553] udmabuf udmabuf.0: DMA mask not set
[ 127.937692] udmabuf udmabuf0: driver version = 1.4.5
[ 127.942653] udmabuf udmabuf0: major number = 240
[ 127.947439] udmabuf udmabuf0: minor number = 0
[ 127.952052] udmabuf udmabuf0: phys address = 0x000000005fd00000
[ 127.958140] udmabuf udmabuf0: buffer size = 1048576
[ 127.963274] udmabuf udmabuf0: dma device = udmabuf.0
[ 127.968582] udmabuf udmabuf0: dma coherent = 0
[ 127.973195] udmabuf udmabuf.0: driver installed.

そこで Linux Kernel のソースコードを見てみると、kernel/dma/contiguous.c に次のような記述がありました。

kernel/dma/contiguous.c
static int __init rmem_cma_setup(struct reserved_mem *rmem)
{
    phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
    phys_addr_t mask = align - 1;
    unsigned long node = rmem->fdt_node;
    struct cma *cma;
    int err;

    if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
        of_get_flat_dt_prop(node, "no-map", NULL))
        return -EINVAL;

    if ((rmem->base & mask) || (rmem->size & mask)) {
        pr_err("Reserved memory: incorrect alignment of CMA region\n");
        return -EINVAL;
    }

    err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
    if (err) {
        pr_err("Reserved memory: unable to setup CMA region\n");
        return err;
    }
    /* Architecture specific contiguous memory fixup. */
    dma_contiguous_early_fixup(rmem->base, rmem->size);

    if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
        dma_contiguous_set_default(cma);

    rmem->ops = &rmem_cma_ops;
    rmem->priv = cma;

    pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
        &rmem->base, (unsigned long)rmem->size / SZ_1M);

    return 0;
}
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

align 変数でアライメント単位を設定してから、開始アドレス(rmem->base) と容量(rmem->size) がアライメント単位であるかどうかチェックしています。アライメント単位は MAX_ORDER 定数や pageblock_order 変数(or定数) によって算出されますが、ZynqMP-FPGA-Linux では 0x00400000 になります。

したがって、ZynqMP で Linux の CMA 領域を devicetree の reserved-memory で指定した時のアライメントは 0x00400000(4MiB) 単位であることがわかります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロセス間通信の種類

Introduction of Communication

agenda

WHOAMI

IPFactory 1年 @n01e0
普段はLinuxのカーネルモジュールを作ったりしています。

WHAT IS IPC

IPCとは Inter Process Communication の略称である。
プロセス間でのデータのやり取りを意味し、Linuxにおいては、様々な種類のIPCが用意されている。
本記事ではそれぞれの軽い紹介程度に留め、実装について詳細な説明は行わない。
各機能のおおまかな特徴を理解し、読者にとっての最適な選択が出来ることを目標としている為である。

IPCの分類

IPCはその機能により大きく3つに分類される

  • 通信
    • プロセス間のデータ通信、交換に関する機構
  • 同期
    • プロセス、スレッド間の同期に関する機構
  • シグナル
    • シグナルは特殊で、条件によっては同期にも通信にも用いることが出来る

IPCの仕様

IPCはUNIXの長い歴史の中でいくつかの規格に沿って実装されており、混在している。
主にSystem Vの実装とPOSIXの実装がある
全体的にPOSIXの方が扱いやすくなってはいるが、POSIXのIPCはカーネルバージョン2.6から実装されている為、可搬性には劣る。

SYSTEM V IPC と POSIX IPC

System Vにおいて、各IPCのデータ構造は、カーネル空間にあり、
プロセスがIPC資源(セマフォ、メッセージキュー、共有メモリリージョン)を要求した時に動的に生成される。
各IPC資源は固有の識別子を持ち。ユーザーは各IPCをそれとは異なるIPCキーで区別出来る。
この関係はファイルとファイルディスクリプタの関係に似ている。
しかし、ファイル異なる点として、プロセスが明示的に解放しない限り、メモリ上に存在し続ける。
同様の機能を提供するPOSIX IPCがあり、こちらはマルチスレッドセーフな設計になっている。
もう1つの大きな差異としては、POSIXでは各IPCに名前を付けて区別できる点がある。
命名には規則があり、/で始まり、/以外の1文字以上の長さのnull終端の文字列でなければいけない。
仕様に細かな違いはあるが、各IPCの概念で大きく異なるのは各オブジェクト(資源)の管理方法である

IPCの比較

System VとPOSIXの大きな違いとしてIPCオブジェクトの識別子、ハンドラがあり、これらを列挙する。

IPC種別 識別子 ハンドラ
パイプ なし ファイルディスクリプタ
FIFO パス ファイルディスクリプタ
System Vセマフォ System V IPCキー System V IPC ID
POSIX 無名セマフォ なし セマフォポインタ
POSIX 名前付きセマフォ POSIX IPCパス セマフォポインタ
System Vメッセージ System V IPCキー System V IPC ID
POSIXメッセージ POSIX IPCパス メッセージキューディスクリプタ
System V共有メモリ System V IPCキー System V IPC ID
POSIX共有メモリ POSIX IPCパス ファイルディスクリプタ
UNIXドメインソケット パス ファイルディスクリプタ
インターネットドメインソケット IPアドレス ポート ファイルディスクリプタ

本記事で紹介するLinuxにおけるIPC

PIPE

パイプとは

日常、シェルで生活をしている読者にとっては非常に慣れ親しんだ概念だろう。
シェルにおけるパイプ(|)とは何なのか、改めて簡単に記すと
あるプロセスの出力を別のプロセスの入力につなげる
といった意味になる。
IPCとしてのパイプも同様、データの出力と入力を繋げる為に用いられる事が多い。
パイプのデータ構造について、何かを例に説明しようと思ったが、パイプ以外に良い例が浮かばない。
筒なので、入出力は先入れ先出しとなる。
まとめると、パイプとは単方向の先入れ先出し型データ構造である。

実装

unistd.hで定義されているpipe()システムコールは2つのファイルディスクリプタを生成する。
一方は読み出し用、もう一方は書き込み用となる。
これらは、ファイルディスクリプタではあるが、対応するパスは無い。
パイプに書き込まれたデータは、読み出されるまでカーネル内のデータ構造によってバッファリングされる。
通常、空のパイプに対してプロセスが読み込み(read())を行うと、そのパイプにデータが書き込まれるまで、読み込みは停止する。

FIFO

類似した機能としてFIFOが存在する。
名前付きパイプとも呼ばれ、また名前の通り先入れ先出しのデータ構造である
パイプと異なる点は、作られるファイルディスクリプタに名前(パス)があるという点くらい。

SIGNAL

これもまた、慣れ親しんだ概念だろう。
シグナルもIPCの一種であると言える。
シグナルには多くの種類があるので、一部を例にとって挙げると

  • SIGHUP
  • SIGINT
  • SIGQUIT
  • SIGKILL
  • SIGSEGV

などがある。
シグナルは主に、プロセスに対し何かが発生したことを伝える時、プロセスに特定の動作をさせる時に用いられている。
シグナルの持つ情報量は少なく、通常は番号(種類)以外の情報は持たない。
また、受け取ったシグナルをどう扱うかはプロセス次第である。

対応

シグナルへの対応にはいくつかパターンがある
1. 無視
1. 標準設定の動作を実行する
1. シグナルハンドラを呼び出す

無視

一部を除き、受け取ったシグナルを無視する事もできる。
無視できない一部のシグナルとは

  • SIGKILL
  • SIGSTOP

であり、これらのシグナルを受け取ったプロセスは、必ず標準設定動作を実行する。

標準設定動作

その標準設定動作とは、名前の通りLinuxにおいて標準で設定されている各シグナルに対する反応である。
プロセスの終了ダンプ停止、標準で無視が設定されているシグナルもある。

シグナルハンドラ

標準設定動作以外にも、signal()を用いてユーザーが各シグナル毎の対応を定義できる。

実装

プロセスがプロセスに対し、シグナルを発行すると、シグナルはカーネルによって受け取られる。
カーネルは対象のプロセスが実行中かどうかを調べ、実行中でなかった場合にはシグナルを保留状態にする。
signal()システムコールは引数にシグナルの種類と対応するシグナルハンドラとなる関数のポインタを持ち、それらを対応づける。

SEMAPHORE

セマフォはIPCの分類の中でも、同期機構にあたる。
セマフォの実態は整数値である。
複数プロセスで共有する資源の保護の為、アクセス制御のカウンタとして割り当てられ

で構成される。

構成

整数型の変数

カウンタとなる。この値が資源の状態(使用可能か否か)を示す

操作待ち状態にあるプロセスのリスト

資源が使用可能になるまで待機しているプロセスのリスト

2つのアトミックなメソッド

セマフォのカウントアップ、ダウンを行う。
セマフォが保護している資源にプロセスがアクセスする時、まず対象資源に紐付けられたセマフォをカウントダウンする。
もしそのセマフォのカウントが負になった場合、プロセスの実行は中断され、リストに加えられる。
資源へのアクセスが終わると、プロセスはセマフォをカウントアップする。
これによりセマフォの値が正になると、リストのプロセスが再開される。

実装

セマフォ自身がプロセスの動作を制限する訳ではなく、セマフォに意味を持たせるのはあくまでユーザーである。
また、セマフォは同期機構である為、非常に複雑な操作を必要とする。

System V

semget()によりセマフォを作成、または開く。
semop()によってセマフォの操作を行う。

POSIX

POSIXでは、セマフォは2種類存在する
- 名前付きセマフォ
- メモリベースドセマフォ(無名セマフォ)

名前付きセマフォ

POSIXの他のIPC同様、セマフォに名前を付けて管理出来る。
名前を共有する事で、プロセス間でセマフォを共有する

メモリベースドセマフォ

共有メモリにマッピングされる。
名前を持たず、プロセス、スレッド間でメモリの共有によってセマフォを共有する。

MESSAGE

IPCメッセージキューは名前の通りキューである。
プロセスによって送信されたメッセージは、他のプロセスが読み込むまでメッセージキューに置かれる。
他のプロセスがメッセージを読み込むと、カーネルはメッセージをキューから削除する。
そのため、プロセス間でのメッセージのやり取りは必ず一対一となる。

実装

System V

メッセージとして送信されるデータは、必ずメッセージの優先度を整数値で指定する必要がある。
受信側は、優先度を指定してメッセージを受け取る。
(となると、先入れ先出しではなくなることもあるのでキューと呼んで良いものなのか)
msgget()を用いてキューを取得し、messnd()で送信、msgrcv()で受信する。

POSIX

POSIXメッセージキューも名前を付けて管理する。
受信の際、メッセージの優先度を指定する事は出来ない。
最も高い優先度の、最も古いメッセージが読み出される。
mq_open()でキューを開き、mq_sendで送信、mq_receiveで受信を行う。

SHARED MEMORY

IPC共有メモリ
名前の通り、共有するメモリ空間に特定のデータ構造を配置する。
また、他のIPCは実行時にユーザー空間からカーネル空間のデータ構造へデータを転送していたのに対し、共有しているメモリ空間へマッピングするだけなのでオーバーヘッドも小さい。
しかし、カーネルが介していないという点には留意すべき問題もある。
複数プロセスが同時にアクセスするのを防ぐ必要性があり、その為には先述のセマフォを用いる事が出来る。

実装

System V

  • shmget()により、共有メモリセグメントを作成、または既存セグメントのIDを取得
  • shmat()により、自プロセスのメモリ空間に共有メモリセグメントをアタッチ
  • shmdt()により、デタッチする。

アタッチされた共有メモリセグメントはプログラム内の通常のメモリと何ら違いなく扱える。
共有メモリオブジェクトが破棄されるのは、すべてのプロセスがデタッチしshmctl()により削除された時である。

POSIX

  • shm_open()によって共有メモリオブジェクトをオープンする。また、この戻り値はファイルディスクリプタである。
  • 得られたファイルディスクリプタに対し、MAP_SHAREDフラグをセットしてmmap()する

SOCKET

ソケット。
ソケットはデータの転送方式によって2つに分類でき、

  • ストリームソケット
  • データグラムソケット

と呼ばれる。
ストリームソケットは名前の通りストリームとして扱え、ファイル等と同様、書き込んだサイズに関わらず任意のバイト数読み取れる。
データグラムソケットはメッセージ等と似ており、データに特定の区切りがあり、読み取りではデータ全体を読み取る必要がある。
また、ソケットのもう一つの分類として、通信先での分類もある

  • UNIXドメインソケット
  • インターネットドメインソケット

と呼ばれ、
UNIXドメインソケットは同一ホスト内でのアプリケーション間の通信を、インターネットドメインソケットではインターネットプロトコルで接続されたアプリケーション間の通信をサポートしている。

実装

ソケットの操作に関するシステムコールは

  • socket()
    • 新規ソケットを作成する
  • bind()
    • ソケットをアドレスに結びつける
  • listen()
    • ストリームソケットを他のソケットからの接続を受け付ける状態にする
  • accept()
    • 受け付け可能な状態のソケットに対する接続要求を取り出す
  • connect()
    • 他ソケットとの接続を確立する

ソケットについて、ここではごく一部しか紹介出来ないが、非常に多くの事が可能な概念である。
IPCのまとめとしての記事ではこの程度に留まるが、ソケットに関する記事は豊富にあるので必要になればそちらを参照していただきたい。

まとめ

それぞれの特徴、長所、短所を見極め、最適なIPCを用いられると便利。
自分の場合、ファイルパス等のやり取りにはPOSIXメッセージキューを用いている。

ダラダラと駄文を書き連ねてしまったが、必要に応じてそれぞれ実装のサンプルを含めてまた別でまとめたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロセス間通信

Introduction of Communication

agenda

WHOAMI

IPFactory 1年 @n01e0
普段はLinuxのカーネルモジュールを作ったりしています。

WHAT IS IPC

IPCとは Inter Process Communication の略称である。
プロセス間でのデータのやり取りを意味し、Linuxにおいては、様々な種類のIPCが用意されている。
本記事ではそれぞれの軽い紹介程度に留め、実装について詳細な説明は行わない。
各機能のおおまかな特徴を理解し、読者にとっての最適な選択が出来ることを目標としている為である。

IPCの分類

IPCはその機能により大きく3つに分類される

  • 通信
    • プロセス間のデータ通信、交換に関する機構
  • 同期
    • プロセス、スレッド間の同期に関する機構
  • シグナル
    • シグナルは特殊で、条件によっては同期にも通信にも用いることが出来る

IPCの仕様

IPCはUNIXの長い歴史の中でいくつかの規格に沿って実装されており、混在している。
主にSystem Vの実装とPOSIXの実装がある
全体的にPOSIXの方が扱いやすくなってはいるが、POSIXのIPCはカーネルバージョン2.6から実装されている為、可搬性には劣る。

SYSTEM V IPC と POSIX IPC

System Vにおいて、各IPCのデータ構造は、カーネル空間にあり、
プロセスがIPC資源(セマフォ、メッセージキュー、共有メモリリージョン)を要求した時に動的に生成される。
各IPC資源は固有の識別子を持ち。ユーザーは各IPCをそれとは異なるIPCキーで区別出来る。
この関係はファイルとファイルディスクリプタの関係に似ている。
しかし、ファイル異なる点として、プロセスが明示的に解放しない限り、メモリ上に存在し続ける。
同様の機能を提供するPOSIX IPCがあり、こちらはマルチスレッドセーフな設計になっている。
もう1つの大きな差異としては、POSIXでは各IPCに名前を付けて区別できる点がある。
命名には規則があり、/で始まり、/以外の1文字以上の長さのnull終端の文字列でなければいけない。
仕様に細かな違いはあるが、各IPCの概念で大きく異なるのは各オブジェクト(資源)の管理方法である

IPCの比較

System VとPOSIXの大きな違いとしてIPCオブジェクトの識別子、ハンドラがあり、これらを列挙する。

IPC種別 識別子 ハンドラ
パイプ なし ファイルディスクリプタ
FIFO パス ファイルディスクリプタ
System Vセマフォ System V IPCキー System V IPC ID
POSIX 無名セマフォ なし セマフォポインタ
POSIX 名前付きセマフォ POSIX IPCパス セマフォポインタ
System Vメッセージ System V IPCキー System V IPC ID
POSIXメッセージ POSIX IPCパス メッセージキューディスクリプタ
System V共有メモリ System V IPCキー System V IPC ID
POSIX共有メモリ POSIX IPCパス ファイルディスクリプタ
UNIXドメインソケット パス ファイルディスクリプタ
インターネットドメインソケット IPアドレス ポート ファイルディスクリプタ

本記事で紹介するLinuxにおけるIPC

PIPE

パイプとは

日常、シェルで生活をしている読者にとっては非常に慣れ親しんだ概念だろう。
シェルにおけるパイプ(|)とは何なのか、改めて簡単に記すと
あるプロセスの出力を別のプロセスの入力につなげる
といった意味になる。
IPCとしてのパイプも同様、データの出力と入力を繋げる為に用いられる事が多い。
パイプのデータ構造について、何かを例に説明しようと思ったが、パイプ以外に良い例が浮かばない。
筒なので、入出力は先入れ先出しとなる。
まとめると、パイプとは単方向の先入れ先出し型データ構造である。

実装

unistd.hで定義されているpipe()システムコールは2つのファイルディスクリプタを生成する。
一方は読み出し用、もう一方は書き込み用となる。
これらは、ファイルディスクリプタではあるが、対応するパスは無い。
パイプに書き込まれたデータは、読み出されるまでカーネル内のデータ構造によってバッファリングされる。
通常、空のパイプに対してプロセスが読み込み(read())を行うと、そのパイプにデータが書き込まれるまで、読み込みは停止する。

FIFO

類似した機能としてFIFOが存在する。
名前付きパイプとも呼ばれ、また名前の通り先入れ先出しのデータ構造である
パイプと異なる点は、作られるファイルディスクリプタに名前(パス)があるという点くらい。

SIGNAL

これもまた、慣れ親しんだ概念だろう。
シグナルもIPCの一種であると言える。
シグナルには多くの種類があるので、一部を例にとって挙げると

  • SIGHUP
  • SIGINT
  • SIGQUIT
  • SIGKILL
  • SIGSEGV

などがある。
シグナルは主に、プロセスに対し何かが発生したことを伝える時、プロセスに特定の動作をさせる時に用いられている。
シグナルの持つ情報量は少なく、通常は番号(種類)以外の情報は持たない。
また、受け取ったシグナルをどう扱うかはプロセス次第である。

対応

シグナルへの対応にはいくつかパターンがある
1. 無視
1. 標準設定の動作を実行する
1. シグナルハンドラを呼び出す

無視

一部を除き、受け取ったシグナルを無視する事もできる。
無視できない一部のシグナルとは

  • SIGKILL
  • SIGSTOP

であり、これらのシグナルを受け取ったプロセスは、必ず標準設定動作を実行する。

標準設定動作

その標準設定動作とは、名前の通りLinuxにおいて標準で設定されている各シグナルに対する反応である。
プロセスの終了ダンプ停止、標準で無視が設定されているシグナルもある。

シグナルハンドラ

標準設定動作以外にも、signal()を用いてユーザーが各シグナル毎の対応を定義できる。

実装

プロセスがプロセスに対し、シグナルを発行すると、シグナルはカーネルによって受け取られる。
カーネルは対象のプロセスが実行中かどうかを調べ、実行中でなかった場合にはシグナルを保留状態にする。
signal()システムコールは引数にシグナルの種類と対応するシグナルハンドラとなる関数のポインタを持ち、それらを対応づける。

SEMAPHORE

セマフォはIPCの分類の中でも、同期機構にあたる。
セマフォの実態は整数値である。
複数プロセスで共有する資源の保護の為、アクセス制御のカウンタとして割り当てられ

で構成される。

構成

整数型の変数

カウンタとなる。この値が資源の状態(使用可能か否か)を示す

操作待ち状態にあるプロセスのリスト

資源が使用可能になるまで待機しているプロセスのリスト

2つのアトミックなメソッド

セマフォのカウントアップ、ダウンを行う。
セマフォが保護している資源にプロセスがアクセスする時、まず対象資源に紐付けられたセマフォをカウントダウンする。
もしそのセマフォのカウントが負になった場合、プロセスの実行は中断され、リストに加えられる。
資源へのアクセスが終わると、プロセスはセマフォをカウントアップする。
これによりセマフォの値が正になると、リストのプロセスが再開される。

実装

セマフォ自身がプロセスの動作を制限する訳ではなく、セマフォに意味を持たせるのはあくまでユーザーである。
また、セマフォは同期機構である為、非常に複雑な操作を必要とする。

System V

semget()によりセマフォを作成、または開く。
semop()によってセマフォの操作を行う。

POSIX

POSIXでは、セマフォは2種類存在する
- 名前付きセマフォ
- メモリベースドセマフォ(無名セマフォ)

名前付きセマフォ

POSIXの他のIPC同様、セマフォに名前を付けて管理出来る。
名前を共有する事で、プロセス間でセマフォを共有する

メモリベースドセマフォ

共有メモリにマッピングされる。
名前を持たず、プロセス、スレッド間でメモリの共有によってセマフォを共有する。

MESSAGE

IPCメッセージキューは名前の通りキューである。
プロセスによって送信されたメッセージは、他のプロセスが読み込むまでメッセージキューに置かれる。
他のプロセスがメッセージを読み込むと、カーネルはメッセージをキューから削除する。
そのため、プロセス間でのメッセージのやり取りは必ず一対一となる。

実装

System V

メッセージとして送信されるデータは、必ずメッセージの優先度を整数値で指定する必要がある。
受信側は、優先度を指定してメッセージを受け取る。
(となると、先入れ先出しではなくなることもあるのでキューと呼んで良いものなのか)
msgget()を用いてキューを取得し、messnd()で送信、msgrcv()で受信する。

POSIX

POSIXメッセージキューも名前を付けて管理する。
受信の際、メッセージの優先度を指定する事は出来ない。
最も高い優先度の、最も古いメッセージが読み出される。
mq_open()でキューを開き、mq_sendで送信、mq_receiveで受信を行う。

SHARED MEMORY

IPC共有メモリ
名前の通り、共有するメモリ空間に特定のデータ構造を配置する。
また、他のIPCは実行時にユーザー空間からカーネル空間のデータ構造へデータを転送していたのに対し、共有しているメモリ空間へマッピングするだけなのでオーバーヘッドも小さい。
しかし、カーネルが介していないという点には留意すべき問題もある。
複数プロセスが同時にアクセスするのを防ぐ必要性があり、その為には先述のセマフォを用いる事が出来る。

実装

System V

  • shmget()により、共有メモリセグメントを作成、または既存セグメントのIDを取得
  • shmat()により、自プロセスのメモリ空間に共有メモリセグメントをアタッチ
  • shmdt()により、デタッチする。

アタッチされた共有メモリセグメントはプログラム内の通常のメモリと何ら違いなく扱える。
共有メモリオブジェクトが破棄されるのは、すべてのプロセスがデタッチしshmctl()により削除された時である。

POSIX

  • shm_open()によって共有メモリオブジェクトをオープンする。また、この戻り値はファイルディスクリプタである。
  • 得られたファイルディスクリプタに対し、MAP_SHAREDフラグをセットしてmmap()する

SOCKET

ソケット。
ソケットはデータの転送方式によって2つに分類でき、

  • ストリームソケット
  • データグラムソケット

と呼ばれる。
ストリームソケットは名前の通りストリームとして扱え、ファイル等と同様、書き込んだサイズに関わらず任意のバイト数読み取れる。
データグラムソケットはメッセージ等と似ており、データに特定の区切りがあり、読み取りではデータ全体を読み取る必要がある。
また、ソケットのもう一つの分類として、通信先での分類もある

  • UNIXドメインソケット
  • インターネットドメインソケット

と呼ばれ、
UNIXドメインソケットは同一ホスト内でのアプリケーション間の通信を、インターネットドメインソケットではインターネットプロトコルで接続されたアプリケーション間の通信をサポートしている。

実装

ソケットの操作に関するシステムコールは
- socket()
- 新規ソケットを作成する
- bind()
- ソケットをアドレスに結びつける
- listen()
- ストリームソケットを他のソケットからの接続を受け付ける状態にする
- accept()
- 受け付け可能な状態のソケットに対する接続要求を取り出す
- connect()
- 他ソケットとの接続を確立する

ソケットについて、ここではごく一部しか紹介出来ないが、非常に多くの事が可能な概念である。
IPCのまとめとしての記事ではこの程度に留まるが、ソケットに関する記事は豊富にあるので必要になればそちらを参照していただきたい。

まとめ

それぞれの特徴、長所、短所を見極め、最適なIPCを用いられると便利。
自分の場合、ファイルパス等のやり取りにはPOSIXメッセージキューを用いている。

ダラダラと駄文を書き連ねてしまったが、必要に応じてそれぞれ実装のサンプルを含めてまた別でまとめたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シェルスクリプトについてメモ

シェルスクリプトについてメモ。

シバンについて #!

シェルスクリプトを作成する際は、
冒頭に #! で始まる行を追加する必要がある。これはシバンと呼ばれている。

/test.sh
#!/bin/bash
mkdir test

#!/bin/bash という行は、/bin/bashで動かすという宣言をしている

このシェルスクリプトの実行方法は、こちら

./test.sh

シェルから実行命令を受けたLinuxカーネルが、対象ファイルの先頭を確認して
もし#!があったら、その後に書かれたコマンドを実行するよという流れ

実質的には

/bin/bash ./test.sh

このようなコマンドラインとして実行される

sourceコマンドでファイルを実行

その他にsourceコマンドを利用して、シェルスクリプトを実行することができる。

source ./test.sh

sourceコマンドは、指定したファイルの内容をそのままコマンドラインとして実行する。

シバン(#!) が表記されていても、# はコメントアウトとして扱われるので無視される

ちなみにsourceコマンドと同様の意味をもつ、ドットコマンドもある

. ./test.sh

ドットだと、見落としやすいので、sourceコマンドの方がベターかもしれない。

こういう基本はしっかりと抑えたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ターミナルで使えるファイラrangerを使ってみる

※本投稿はTechCommit Advent Calendar 2019の2日目の記事です。

はじめに

こんにちは、フリーランスでプログラマーをやってます rattcv と申します。

僕は普段の開発では主にLinuxを使っていて、割とターミナルエミュレータに閉じこもって作業する事が多いんです。
CLI環境において、作業中のディレクトリ上で編集したいファイルを効率よく探す方法は色々あって、最近は「選択的インターフェイス」と呼ばれるジャンルの peco とか fzf 等のツールをシェルと組み合わせて使いこなしている例を良く見かけますし、VimやEmacs等、エディタから使う検索プラグインにも色々と便利なものが揃っていますよね。
上記の様な便利なツール類を上げてる記事とかを見て「スゲー便利そうだなー」と思って試してはみるものの、中々手に馴染まず使うのをやめちゃうのが常だったりします。使いこなせたら凄い効率あがりそうなんですけどね笑

それで僕は普段どうしてるかというと、昔っからの慣れで FDclone というMS-DOS用のファイラ"FD"をUnix系OSに移植したファイラをよく使ってます。見た目はこんな感じですね。
ran01.png

これはとても手に馴染んでて、もうしょっちゅう fd fd って無意識に打っちゃう位多用してますね笑

他にCLIで使えるファイラに Midnight Commanderっていうのがあります。良く海外のCLI環境のスクリーンショットでお目にかかりますよね。これは使った事がないので今インストールしてみました笑
ran02.png

日本語化もされてて見た目からして使いやすそうな感じですね!時間があったら試してみたいです。

さて、かなり脱線しましたが、ここからが本題の "ranger" です。

rangerのインストール

ranger っていうCLIファイラはpython製でとても高機能で、Vimキーバンドで使える上にVimの中にも組み込めるっていう話を聞いてて興味があったんで、今回試してみる事にしました。
トライする環境ですが、今この記事書いてるUbuntu Desktopでやろうと思ったんですが色々イジってるうちにrangerの一部機能が使えなくなっちゃったので、持ち歩き用のLinuxネットブックを使います。こんな感じです。

~% cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=17.04
DISTRIB_CODENAME=zesty
DISTRIB_DESCRIPTION="Ubuntu 17.04"

Ubuntuのリポジトリのrangerはバージョンが古いんですが、今は手っ取り早く試したいのでサクッと apt でインストールしちゃいます。

~% sudo apt-get install ranger ffmpegthumbnailer w3m-img xpdf highlight mediainfo atool

依存関係も含めてインストールされます。バージョンを確認してみます。

~% ranger --version
ranger version: ranger 1.8.1
Python version: 2.7.13 (default, Nov 23 2017, 22:12:08) [GCC 6.3.0]

初期設定の為、下記コマンドを打ちます。

~% ranger --copy-config=all

上記で $HOME/.config/ranger 配下にデフォルトの設定ファイルが作成されます。
設定ファイルを以下の様に編集します。

$HOME/.config/ranger/rc.conf
set draw_borders true
$HOME/.config/ranger/scope.sh
# Image preview for video, disabled by default.:
   video/*)
       ffmpegthumbnailer -i "$path" -o "$cached" -s 0 && exit 6 || exit 1;;

# PDF documents:
  pdf)
      try pdftoppm -jpeg -singlefile "$path" "$cached" && mv "$cached.jpg" "$cached" && exit 6 || exit 1;;

ここまでrangerを一度起動してみます。

~% ranger

このファイラの真骨頂はVimキーバインド(H J K L)でどんどんディレクトリに潜っていけて、最終的なファイル選択により一番右側にファイルのプレビューが表示可能な所だと思います。
上記設定によりテキストファイルはSyntaxHighlightがかかった状態で、PDFや各種画像ファイル、動画のサムネイルもプレビュー表示出来てしまいます。
n5d8k-2pjbq.gif

プレビュー表示から更にL押下で、当該ファイルを適切なアプリケーションで開く事ができます。なかなか優れものですよね。

ファイルのアイコン表示を試してみる

僕はターミナルには Cicaフォント を使用する様に設定してますが、このフォントはアイコンフォントを包括しているのでranger上でもファイルにアイコン表示をする事が可能です。

上記のフォントをインストールした状態で、ranger_devicons を導入します。

~% git clone https://github.com/alexanderjeurissen/ranger_devicons.git
~% cd ranger_devicons
~/ranger_devicons% make install

この状態でrangerを起動するとこんな感じになります。
abc.png
結構イイ感じですよね。
他にもrangerには色々便利な設定がたくさんあるので、以下の参考サイトを参照してみて頂ければと思います。
・ArchWiki - ranger
・CLIファイルマネージャrangerの基本設定
・Rangerを少し試した

他のOSでの使用について

MacOSでは apt-get の代わりにHomebrewを使って brew コマンドでUbuntuと同様にインストール出来ると思います(すいません、僕Mac持ってないんですが多分出来ます)。iTrem2の画像表示機能を使ってファイルプレビューする場合は、 rc.conf

set preview_images_method iterm2

に修正すればイケる様です。

Windowsでは、Linuxディストリビューションが使えるWSLとターミナルエミュレータをインストールすればこちらも同様に使用可能です。

WSL&wslttyを導入する記事をこちらに書きましたので、参考にして頂ければと思います。
ただし、WSLではw3m-img(の画像表示用のツールであるw3mimgdisplay)が使えないので画像のプレビューが現状出来ないです。これは頑張れば出来る様になりそうな気がするので、成功しましたらお知らせします笑

ではでは、是非是非CLIファイラーの世界で遊んでみてください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Paiza Cloud で LINE Bot を試してみる

プロトアウトスタジオアドベントカレンダー4発目の記事です!

昨日は @tkyko13 さんの「word2vecの勉強で「word2vecの勉強で「ナダルリバースエボリューション」が再現できるのではないかと思いついたのでやってみた」でした。

Paiza Cloud とは

クラウド開発環境 PaizaCloudクラウドIDE - クラウドIDEでWeb開発!

2019-12-03_01h00_54.png

ブラウザを開くだけでLinuxサーバが使える!
クラウド開発環境PaizaCloudクラウドIDEでは、ブラウザだけでLinuxサーバを操作できます。ファイル操作、テキスト操作、コマンド操作、Webサーバ/DBサーバの立ち上げなど、全てブラウザだけで行えます。 もう、面倒なコマンドでのログイン(ssh)やファイル操作(vim)、ファイルのアップロードは必要ありません。 目の前のコンピュータと同じように、クラウド上のLinuxサーバを操作できます。

とのことで、以前、Katacodaで LINE Messaging API Playground (ja) を作った身としては興味があります。

image.png

料金表をみてみても1つのサーバーが無料で24時間使えるので、Katacodaよりも長時間使えます。(2019/12/03現在)

サーバーを立ち上げる

Paiza Cloud のアカウント登録をして、まず、Node.jsサーバを立てあげてみましょう。

image.png

新規サーバーを押します。

image.png

Node.jsをクリックして新規サーバ作成します。

image.png

このような形で起動します。

LINE Bot をつくる

1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest - Qiita

こちらの資料をベースに、「1. Botアカウントを作成する」を進めてBotと友達になるところまで進めましょう。

「2. Node.jsでBot開発」からはじめます。

image.png

左のメニューのターミナルを押して、ターミナルを起動します。

npm i @line/bot-sdk express

を実行します。

image.png

無事インストールされました。

image.png

新規ファイルを押して、

image.png

server.js ファイルを作成します。

以下をコピー&ペーストしましょう。

server.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: '作成したBOTのチャンネルシークレット',
    channelAccessToken: '作成したBOTのチャンネルアクセストークン'
};

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

    //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
    if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello LINE BOT!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.text //実際に返信の言葉を入れる箇所
  });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

image.png

保存します。

自分のBotとして動くように、Channel SecretとChannel Access Tokenを反映

自分のBotとして動くように、Channel SecretとChannel Access Tokenを反映させます。

1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest - Qiita

の流れに沿ってChannel SecretとChannel Access Tokenをメモしておきます。

左上のファイルツリーから server.js を選択してエディタで編集できるようにします。

const config = {
    channelSecret: 'channelSecret',
    channelAccessToken: 'channelAccessToken'
};

server.jsのこちらを変更します。仮に Channel Secret が ABCDEFGHIJ 、channelAccessTokenが 1234567890 とすると。

const config = {
    channelSecret: 'ABCDEFGHIJ',
    channelAccessToken: '1234567890'
};

と、なります。

ファイルを保存します。

server.jsを動作させてWebhook URLを設定

ターミネルウィンドウで以下のコマンドを打ち込んで起動します。

node server.js

起動すると Server running at port 3000 と表示されたらOKです。

image.png

公開URL確認

image.png

起動すると左のメニューに 3000 というボタンが出来るので、公開URLを確認します。

image.png

内部ブラウザが開いてURLが確認できるのでメモしておきましょう。

image.png

こちらをLINEの管理画面のメッセージ送受信設定>Webhook URLに反映します。

これで準備完了です。

動かしてみる

実際にLINEでBotを会話してオウム返しを体験しましょう。

image.png

LINEで話しかけてみると無事返答されます。

image.png

ターミナルを見てみると

image.png

サーバーのやり取りも確認できます。

明日の記事は…

@doikatsuyuki さんの「Firebaseを利用した中耳炎診療支援Webアプリの作成 (1.Firebaseの設定~認証方法の追加)」です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む