徒然なるままに

個人の備忘録を中心としたブログです

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
多重I/O(I/O Multiplexing)について勉強する機会があったのでメモ。

具体的な使用方法の前に多重I/Oについての前置き。

多重I/Oとは、複数のプロセスにread(recv)要求を行っている状況において
順番を気にせず、読み込みが完了したプロセスから順次読み込んだデータを使って処理する場合に使う。

いわゆるイベント駆動型動作であり、一つでも読み込みが完了していれば
まだ読み込みが終了していないプロセスのread待ちによるブロックがない。

例えば100プロセスとの通信で、ファイルディスクリプタを100個所持している状況を考えよう。
1つのプロセスからの入力を待って、入力が来たら、次のプロセスからの入力を待って、・・・として
全てのプロセスからデータを読み込むのは非常に非効率である。

そこで100個のファイルディスクリプタを監視して、
読み込みイベントがあったファイルディスクリプタから先に処理ができるようにしたものが
多重I/Oである。


多重I/Oを実現する手段として、Linuxにselecet(2),poll(2),epoll(2)がある。

selectは扱えるファイルディスクリプタ数に上限があるので、selectを使うならpollを使った方がよい(マシ)。
pollは扱えるファイルディスクリプタ数を無限にできる。
しかし、select,pollはファイルディスクリプタを一つずつループで見ていく方法で
ファイルディスクリプタを監視するのでO(n)の時間がかかる。

一方、epollはファイルディスクリプタの数が無制限なのに加え、ディスクリプタの状態をkernelで管理するため
ファイルディスクリプタの状態が変わったものに対して直接通知ができる。

つまり性能としては select<poll<epoll である。

epollはnginx(エンジンエックス)というサーバーやプロキシに使われるソフトウェアで使われている。
参考サイト:入門! nginx - 馬鹿と天才は紙一重



やっと本題のepollの使い方に入ります・・・。

まずはepoll_create(2)で、epollのインスタンスを作成します。
FD_SIZEは監視するファイルディスクリプタ数の上限であり、
この値をepoll_create(2)に渡しているが、これは後方互換性のものであり、
現在はこの上限を越えるファイルディスクリプタを追加すると、カーネルが自動的にメモリの追加割り当てを行うので
この上限は形骸化している。ただし、現在でも0より大きな値を渡さなければいけない。

#define FD_SIZE 100
int epfd;
epfd = epoll_create(FD_SIZE)



int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_create(2)でディスクリプタのインタフェースを操作する。
このシステムコールは、ファイルディスクリプタ epfd が参照する epoll インスタンスに対する操作を行う。 対象のファイルディスクリプタ fd に対して、 操作 op の実行が要求される。

opで指定する値の一つでよく使うのは「EPOLL_CTL_ADD」。
対象のファイルディスクリプタ fd をファイルディスクリプタ epfd が参照する epoll インスタンスに登録し、イベント event を fd に結び付けられた内部ファイルに関連付ける。

int conn_sock; //プロセス間の通信に使うファイルディスクリプタ(以降既に通信ができているものとする)
struct epoll_event ev; // epoll_event

memset(&ev, 0, sizeof ev); // epoll_eventの初期化
ev.events = EPOLLIN; // 入力を待つ
ev.data.fd = conn_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev); //epollインスタンスにfdを追加し、イベントをfdに関連付ける。



int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epoll_wait() システムコールは、ファイルディスクリプタ epfd で参照される epoll インスタンスに対するイベントを待つ。 events が指すメモリ領域には、 呼び出し側が利用可能なイベントが格納される。最大 maxevents 個のイベントが epoll_wait() によって返される。 maxevents 引き数は 0 より大きくなければならない。

timeout 引き数は、 epoll_wait() が停止する最小時間をミリ秒で指定する。 timeout を -1 に指定すると、epoll_wait() は無限に停止する。timeoutを 0 に指定すると、 epoll_wait() は利用可能なイベントがなくても、すぐに返る。

成功した場合、 epoll_wait() は要求された I/O に対して準備ができているファイルディスクリプタの数を返す。 また要求された timeout ミリ秒の間にファイルディスクリプタが準備できない場合は、0 を返す。 エラーが起こった場合、 epoll_wait() は -1 を返し、 errno を適切に設定する。

epoll_events events[FD_SIZE];

while (1) {
int i;
int nfd = epoll_wait(epfd, events, MAX_EVENTS, -1); // epoll_waitは準備ができているファイルディスクリプタの数を返す

for (i = 0; i < nfd; i++) {
if (events[i].data.fd == conn_sock) { // 目的のfdが含まれていたらそのfd専用の操作を行う。
int n = read(conn_sock,&data,sizeof(data));
if(n<0){ perror("read"); exit(1); }
}
}
}


↓のサイトでepollを使った良いテストコードが紹介されています。
epoll を使った echo サーバ
スポンサーサイト
通常、Linuxで起動サービスのランレベル変更にはchkconfigを使いますが、Ubuntuではデフォルトでインストールされていません。
apt-getで普通にインストールできますが、Ubuntuでランレベルの変更の際にchkconfigを使うとエラーを吐かれることがあります。

このchkconfigに変わって、使うのが「sysv-rc-conf」
文字通り「従来のsystem-V系のrcファイルを設定する」スクリプトです。
sudo apt-get install sysv-rc-conf

でインストールしましょう。

引数などの使用法はchkconfigとほとんど変わらないみたいです。
通常、Ubuntu以外のLinuxディストリビューションでテキストモードのログインをするには
起動時のデフォルトランレベルの変更という手段を使う。
/etc/inittabの
id:5:initdefault:

の5(Graphical mode)を、3(Text mode)に変更するのだとか。

ところがUbuntuではそもそもinitデーモンを使用せず(6.10以降)、
「Upstart」というイベントをトリガとする起動形式をとっていて
/etc/inittabは存在しないようだ。

しかし、互換性のためにランレベルの概念も引き継いでいるようで
/etc/event.d/rc-defaultというスクリプトにデフォルトのランレベルを記述せよ。とのこと
しかし、これは(9.04)までの話であり、12.04には/etc/event.dは存在しない。

現在(12.04)のUbuntuでテキストモードのログインを行う一般的な方法として、GRUBの起動オプションを変更する。
/etc/default/grubの編集で
GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash”


GRUB_CMDLINE_LINUX_DEFAULT=”text”

に変更。
その後に$ sudo update-grub2で更新を行わないと設定が反映されないことに注意。

GRUB_CMDLINE_LINUX_DEFAULTは通常起動のlinuxラインの最後に指定されたオプションを付け足すことができる。

すなわち、GRUBの選択画面で'e'を押して、起動時のコマンドラインを直接編集してもよい。
その場合も" quiet splash"の部分を" text"に変更するだけ。

ちなみに、オプションの意味はquietはkernelメッセージの抑制、splashはスプラッシュスクリーンの表示。
splashそのままで、元々のquietを外せば起動時の読み込み動作などが小窓に表示されるとのこと。
グラフィカルモードで読み込み動作をスプラッシュスクリーンなしで、表示させたい場合には
GRUB_CMDLINE_LINUX_DEFAULT=”quiet nosplash”

に変更するらしい。

(追記13/03/01 11:30)
実際試してみたところ、12.04では"splash", "quiet nosplash"の起動時の表示は"quiet splash"と変わらないみたい?
ここでは、テキストモードでログインしたいだけなのでまあいいや

(参考にしたサイト)
http://bibo-log.blog.so-net.ne.jp/2010-05-23
http://christina04.blog.fc2.com/blog-entry-162.html
一般ユーザとrootでは、セキュリティ上、環境変数PATHが異なっています。
そのため、以下のような状況が考えられます。

ルート権限が必要なプログラムがあり、格納されているディレクトリにPATHを通したとします。
ここでこのプログラムを実行するには、
「root権限が必要」
かといって、
「rootになるとPATHが通っていない」
という状況が出てきます。

この対策案として、
1、rootのホームディレクトリに.bash_profileを作成してPATHを追加する
2、rootのPATHが通っている/usr/bin内に目的のプログラムのシンボリックリンクを作成する
という手があります。

セキュリティ上、rootのPATHをあちこちに通したくないので、2を推奨します。
例えばApacheとtomcatのスタートアップ(シャットダウン)スクリプトの場合
ln -s /usr/local/apache/bin/apachectl /usr/bin/apachectl
ln -s /usr/local/apache/bin/startup.sh /usr/bin/startup.sh
ln -s /usr/local/apache/bin/shutdown.sh /usr/bin/shutdown.sh


lrwxrwxrwx 1 root root 31  2月 20 06:43 /usr/bin/apachectl -> /usr/local/apache/bin/apachectl
lrwxrwxrwx 1 root root 33 2月 20 06:43 /usr/bin/shutdown.sh -> /usr/local/tomcat/bin/shutdown.sh
lrwxrwxrwx 1 root root 32 2月 20 06:43 /usr/bin/startup.sh -> /usr/local/tomcat/bin/startup.sh


という感じになります。
なおシンボリックリンクのパーミションは全く関係ありません。
実行はリンク先のパーミションのみに影響されます。

kamiyasu

Author:kamiyasu

QR

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。