<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yoichi Kawasaki&#039;s Web &#187; c</title>
	<atom:link href="http://yk55.com/blog/tags/c/feed/" rel="self" type="application/rss+xml" />
	<link>http://yk55.com/blog</link>
	<description>the place to organize and record my ideas ...</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:16:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) -->	<item>
		<title>LibeventのRPCフレームワークによるC/Sプログラミング</title>
		<link>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/</link>
		<comments>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/#comments</comments>
		<pubDate>Sat, 05 Jun 2010 14:49:21 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[rpc]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=361</guid>
		<description><![CDATA[前回の投稿ではlibeventのHTTP処理機能evhttpを使ったHTTPサーバを紹介したが今回はlibeventのRPCフレームワーク evrpcを使ったC/Sプログラミング方法を紹介してみる。このevrpcはかなりマイナーな部類のフレームワークといえる。これに関するドキュメントは少なく、検索してみるとまともなページがヒットしない。ヘッダやテストコードを読まない人にとってはちょっと厳しいかもしれない。 巷にはハイパフォーマンスで使いやすく少し検索すれば豊富なドキュメントやブログ記事がわさわさと出てくるようなフレームワークがごろごろしているのでこんなに地味で愛想ないフレームワークをふつーは選ばない。 そんな人気のないevrpcだけど実際に使ってみると思ったより悪くない。 動作は安定しているしAPIはシンプルで使いやすく拡張性も考慮されていてHook関数、Callback関数を駆使すれば好きに振る舞いを制御することができる。 少々粗挽きなところは全く気にしないでこれをベースに自分なりに使いやすいフレームワークを作ってやろうくらいに思ってる人には向いているかもしれない。 RPC marshalling用コードのジェネレート &#8211; event_rpcgen.py marshallingとはRPC C/S処理で内部的に使用するデータ構造をネットワーク転送用のフォーマットに変換することで、その逆をdemarshallingと呼ぶ。厳密には意味が違うらしいがserializationとdeserializationみたいなもの。 libeventにはデータ構造をmarshalling、demarshallingするコードをジェネレートするためのスクリプトが用意されている。それがevent_rpcgen.py。RPC C/S処理で使用するデータ構造を定められたフォーマットで定義してやりそれをevent_rpcgen.pyに食わせてやることでコードが生成される。 データ構造の定義フォーマットは次のとおり。 [データ構造の定義フォーマット] struct &#60;data struct name&#62; { &#160; &#160; [optional] &#60;type&#62; &#60;varname&#62; = &#60;index&#62;; &#160; &#160; &#160;... } &#60;type&#62; データ型 &#160; - string &#160;文字列 &#160; - bytes &#160;uint_tベクター。 [lenght]で長さを指定。　例、bytes hoge[10] &#160; - int &#160;uint32_t &#160; - struct[structname] &#160;構造体 &#160; - array [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/">前回の投稿</a>では<a href="http://www.monkey.org/~provos/libevent/">libevent</a>のHTTP処理機能<a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evhttp_8h.html">evhttp</a>を使ったHTTPサーバを紹介したが今回はlibeventのRPCフレームワーク <a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html">evrpc</a>を使ったC/Sプログラミング方法を紹介してみる。このevrpcはかなりマイナーな部類のフレームワークといえる。これに関するドキュメントは少なく、検索してみるとまともなページがヒットしない。ヘッダやテストコードを読まない人にとってはちょっと厳しいかもしれない。 巷にはハイパフォーマンスで使いやすく少し検索すれば豊富なドキュメントやブログ記事がわさわさと出てくるようなフレームワークがごろごろしているのでこんなに地味で愛想ないフレームワークをふつーは選ばない。 そんな人気のないevrpcだけど実際に使ってみると思ったより悪くない。 動作は安定しているしAPIはシンプルで使いやすく拡張性も考慮されていてHook関数、Callback関数を駆使すれば好きに振る舞いを制御することができる。 少々粗挽きなところは全く気にしないでこれをベースに自分なりに使いやすいフレームワークを作ってやろうくらいに思ってる人には向いているかもしれない。</p>
<p><h2><strong>RPC marshalling用コードのジェネレート &#8211; event_rpcgen.py</strong></h2>
<p><a href="http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29">marshalling</a>とはRPC C/S処理で内部的に使用するデータ構造をネットワーク転送用のフォーマットに変換することで、その逆をdemarshallingと呼ぶ。厳密には意味が違うらしいがserializationとdeserializationみたいなもの。 libeventにはデータ構造をmarshalling、demarshallingするコードをジェネレートするためのスクリプトが用意されている。それが<a href="http://levent.git.sourceforge.net/git/gitweb.cgi?p=levent/levent;a=blob;f=event_rpcgen.py;h=05f0a3622aa7d9343d8f3e86f6c42fc0465e46ae;hb=HEAD">event_rpcgen.py</a>。RPC C/S処理で使用するデータ構造を定められたフォーマットで定義してやりそれをevent_rpcgen.pyに食わせてやることでコードが生成される。 データ構造の定義フォーマットは次のとおり。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[データ構造の定義フォーマット]<br />
<br />
struct &lt;data struct name&gt; {<br />
&nbsp; &nbsp; [optional] &lt;type&gt; &lt;varname&gt; = &lt;index&gt;;<br />
&nbsp; &nbsp; &nbsp;...<br />
}<br />
<br />
&lt;type&gt; データ型<br />
&nbsp; - string &nbsp;文字列<br />
&nbsp; - bytes &nbsp;uint_tベクター。 [lenght]で長さを指定。　例、bytes hoge[10]<br />
&nbsp; - int &nbsp;uint32_t<br />
&nbsp; - struct[structname] &nbsp;構造体<br />
&nbsp; - array &lt;type&gt; &nbsp;typeで指定されたデータ型のベクター。 typeはstring, bytes, int, または struct[structname]<br />
<br />
&lt;varname&gt; 変数名<br />
&lt;index&gt; インデックス番号。フィールド番号。<br />
<br />
[optional] &nbsp;typeの前にoptionalを指定するとリクエスト、レスポンス処理時にそのフィールドへのデータセットを省略することができる。<br />
<br />
※ &nbsp;定義ファイルの拡張子は.rpcである必要がある<br />
※ &nbsp;&lt;varname&gt; と&lt;index&gt;の間は１半角スペースずつを開ける。 そうでない場合はevent_rpcgen.pyによるジェネレートが失敗するので要注意！<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode =1;<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode &nbsp; = 1;<br />
&nbsp; &nbsp;× &nbsp; &nbsp;int errcode=1;<br />
&nbsp; &nbsp;○ &nbsp; &nbsp;int errcode = 1</div></div>
<p>今回のサンプルで使用するデータ構造を定義する。 サンプルはユーザ情報を取得するRPCでありユーザ情報取得のためのリクエスト、レスポンス用データ構造が以下のGetUserRequest、GetUserResponse。</p>
<p><u>サンプルデータ構造の定義フォーマットファイル &#8211; <A href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.rpc">simple.rpc</A></u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">struct</span> GetUserRequest <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">string</span> id <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">struct</span> GetUserResponse <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> errcode <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; optional <span style="color: #993333;">string</span> name <span style="color: #339933;">=</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; optional <span style="color: #993333;">string</span> email <span style="color: #339933;">=</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>これを次のようにevent_rpcgen.pyを使ってデータ構造定義からコードをジェネレートする。 event_rpcgen.pyはlibeventをインストールするとデフォルトで/usr/local/bin/配下にコピーされる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ /usr/local/bin/event_rpcgen.py simple.rpc<br />
<br />
Reading &quot;./simple.rpc&quot;<br />
&nbsp; Created struct: GetUserRequest<br />
&nbsp; &nbsp; Added entry: id<br />
&nbsp; Created struct: GetUserResponse<br />
&nbsp; &nbsp; Added entry: errcode<br />
&nbsp; &nbsp; Added entry: name<br />
&nbsp; &nbsp; Added entry: email<br />
... creating &quot;./simple.gen.h&quot;<br />
... creating &quot;./simple.gen.c&quot;</div></div>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.gen.h">simple.gen.h</a>と<a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple.gen.c">simple.gen.c</a>の2つのファイルがジェネレートされる。 C/S両方でこのデータ構造を使用する。</p>
<p><h2><strong>RPCサーバの実装 &#8211; simple_rpc_server.cpp</strong></h2>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_server.cpp">http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_server.cpp</a></p>
<p>まずは利用するRPCメソッドの登録を行う。 <a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#a526799df545537b2dc67358b0dfaa15">EVRPC_HEADER</a>でRPCコマンドのデータ構造とプロトタイプを作成して<a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#f7abcafae087e3c4dce6a4cd85346114">EVRPC＿GENERATE</a>でRPCメッセージを送受信するためのコードを作成する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#ifdef __cplusplus</span><br />
<span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #ff0000;">&quot;C&quot;</span> <span style="color: #009900;">&#123;</span><br />
<span style="color: #339933;">#endif</span><br />
<span style="color: #339933;">#include &quot;simple.gen.h&quot;</span><br />
<span style="color: #339933;">#ifdef __cplusplus</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #339933;">#endif</span><br />
<span style="color: #339933;">#include &quot;evrpc.h&quot;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #808080; font-style: italic;">/* registe RPC : GetUser */</span><br />
EVRPC_HEADER<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #808080; font-style: italic;">/* generate RPC code : GetUser */</span><br />
EVRPC_GENERATE<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>RPCサーバの実装について説明する。実装は既に存在するHTTPサーバの実装をベースとする。RPCサーバの基本コードは以下の通り。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>argc <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s &lt;server&gt; &lt;port&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr <span style="color: #339933;">=</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">short</span> svr_port <span style="color: #339933;">=</span> atoi<span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>ev_http <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_base <span style="color: #339933;">*</span>rpc_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize base event mechanism */</span><br />
&nbsp; &nbsp; event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ev_http <span style="color: #339933;">=</span> evhttp_start<span style="color: #009900;">&#40;</span>svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a base for the RPC protocol */</span><br />
&nbsp; &nbsp; rpc_base <span style="color: #339933;">=</span> evrpc_init<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* register all of the handlers for all RPCs */</span><br />
&nbsp; &nbsp; EVRPC_REGISTER<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #339933;">,</span> GetUser<span style="color: #339933;">,</span> GetUserRequest<span style="color: #339933;">,</span> GetUserResponse<span style="color: #339933;">,</span> GetUserCallback<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* loop and dispatch events */</span><br />
&nbsp; &nbsp; event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; EVRPC_UNREGISTER<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #339933;">,</span> GetUser<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evrpc_free<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_free<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>event_init()でlibeventライブラリ初期化。とりあえずlibeventを使う際は最初に一度実行しておく。</li>
<li>evhttp_start(svr_addr, svr_port)にサーバアドレス、ポートを指定してHTTPサーバ処理開始準備。</li>
<li>evrpc_init()でrpc処理ハンドル用ポインタを作成。</li>
<li><a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#bb204281e2555a1e91ff3885747d0533">EVRPC_REGISTER</a>で特定のRPCコマンドをサーバに登録する。ここではさきほどEVRPC_HEADERとEVRPC_GENERATEで登録されたRPCコマンドGetUser（リクエスト用データ構造GetUserRequest, レスポンス用データ構造GetUserResponse）をRPCサーバに登録する。また同時にGetUserCallbackというRPCリクエストを受け取った際に呼び出されるコールバック関数を登録する。GetUserCallbackは次で説明する。</li>
<li>event_dispatch()でloop開始しイベントdispatchを開始する。</li>
<li>後処理。サーバ処理を終えるときEVRPC_UNREGISTER、evrpc_free, evhttp_freeの順で後処理をする。</li>
</ul>
<p><p>
GetUserCallbackはさきほどEVRPC_REGISTERでサーバに登録されたRPCコマンドのコールバック関数。 RPCクライアントから送信されるリクエストデータからidを取得。そのidに対するnameとemailデータをレスポンスデータにセットしている。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">void</span><br />
GetUserCallback<span style="color: #009900;">&#40;</span>EVRPC_STRUCT<span style="color: #009900;">&#40;</span>GetUser<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span> rpc<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>arg<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest<span style="color: #339933;">*</span> req <span style="color: #339933;">=</span> rpc<span style="color: #339933;">-&gt;</span>request<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserResponse<span style="color: #339933;">*</span> res <span style="color: #339933;">=</span> rpc<span style="color: #339933;">-&gt;</span>reply<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* get request info */</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>id<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get request info<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;REQUEST id = %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* do somthing due to request info */</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set response info */</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Fooo Baaar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;baz@foo.bar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* send the reply to the RPC */</span><br />
&nbsp; &nbsp; EVRPC_REQUEST_DONE<span style="color: #009900;">&#40;</span>rpc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>EVTAG_HASでリクエストデータ構造中のあるフィールドにデータがセットされているかをチェック(ここではid)してEVTAG_GETで実際にそのフィールドデータを取得。</li>
<li>EVTAG_ASSIGNでレスポンスデータ構造のフィールド(ここではerrcode, name, email)にデータをセット。</li>
<li>EVRPC_REQUEST_DONEでレスポンス送信。</li>
</ul>
<p><h2><strong>RPCクライアントの実装 &#8211; simple_rpc_client.cpp</strong></h2>
<p><a href="http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_client.cpp">http://github.com/yokawasa/any/blob/master/libevent_rpc/simple_rpc_client.cpp<br />
</a><br />
RPCクライアントの実装について説明する。RPCクライアントでもサーバと同じようにEVRPC_HEADERとEVRPC＿GENERATEとで利用するRPCメソッドの登録を行う。以下RPCクライアントの基本コード。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>argc <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s &lt;server&gt; &lt;port&gt;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr <span style="color: #339933;">=</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">short</span> svr_port <span style="color: #339933;">=</span> atoi<span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> event_base <span style="color: #339933;">*</span>ev_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>ev_http <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_base <span style="color: #339933;">*</span>rpc_base <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span>rpc_pool <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest <span style="color: #339933;">*</span>req<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserResponse <span style="color: #339933;">*</span>res<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize base event mechanism */</span><br />
&nbsp; &nbsp; ev_base <span style="color: #339933;">=</span> event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* initialize http internal buffer */</span><br />
&nbsp; &nbsp; ev_http <span style="color: #339933;">=</span> evhttp_new<span style="color: #009900;">&#40;</span>ev_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a base for the RPC protocol */</span><br />
&nbsp; &nbsp; rpc_base <span style="color: #339933;">=</span> evrpc_init<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; rpc_pool <span style="color: #339933;">=</span> get_rpc_pool<span style="color: #009900;">&#40;</span>ev_base<span style="color: #339933;">,</span> svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>rpc_pool<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set up request data */</span><br />
&nbsp; &nbsp; req <span style="color: #339933;">=</span> GetUserRequest_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; EVTAG_ASSIGN<span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> id<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;foobar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* create a response structure */</span><br />
&nbsp; &nbsp; res <span style="color: #339933;">=</span> GetUserResponse_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* set request, response, callback func */</span><br />
&nbsp; &nbsp; EVRPC_MAKE_REQUEST<span style="color: #009900;">&#40;</span>GetUser<span style="color: #339933;">,</span> rpc_pool<span style="color: #339933;">,</span> req<span style="color: #339933;">,</span> res<span style="color: #339933;">,</span> GetUserCallback<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* process request and response */</span><br />
&nbsp; &nbsp; event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; GetUserRequest_free<span style="color: #009900;">&#40;</span>req<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; GetUserResponse_free<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; evrpc_pool_free<span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evrpc_free<span style="color: #009900;">&#40;</span>rpc_base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_free<span style="color: #009900;">&#40;</span>ev_http<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>event_init()でlibeventライブラリ初期化。</li>
<li>evhttp_new()でhttp処理用内部バッファーを初期化。</li>
<li>evrpc_init()でrpc処理ハンドル用ポインタを作成。</li>
<li>get_rpc_pool()よりevrpc_poolポインタを取得。get_rpc_pool()は次で説明。 evrpc_poolは内部にリクエストとして送信するための接続ポインタ(evhttp_connection)を持っている。</li>
<li>GetUserRequest_new()とGetUserResponse_new()によりRPCリクエストとレスポンスのためのリソース確保。</li>
<li>EVTAG_ASSIGNによりリクエスト用データ構造のidフィールドに値(&#8220;foobar&#8221;)を設定。</li>
<li><a href="http://www.monkey.org/~provos/libevent/doxygen-1.4.10/evrpc_8h.html#ff0efcd7cb8b966256b5127960bd2c81">EVRPC_MAKE_REQUEST</a>でサーバへのリクエスト送信に使うRPCコマンドとリクエスト、レスポンスオブジェクトポインタ、evrpc_poolポインタ、コールバック関数をセットする。コールバック関数GetUserCallbackは後で説明する。</li>
<li>event_dispatch()を呼んで実際にリクエスト送信、レスポンス受信を行う。</li>
<li>後処理。GetUserRequest_free()、GetUserResponse_free()でそれぞれリクエストとレスポンスのために確保されたリソースを開放。 次にevrpc_pool_free、evrpc_free, evhttp_freeの順で後処理実行。</li>
</ul>
<p><p>
RPCリクエスト処理で使用するevrpc_poolポインタを取得するための関数。get_rpc_poolがコールされる度にサーバ接続ポインタ (evhttp_connection)を生成しevrpc_poolの接続プールに追加している。 ちなみにevrpc_poolとはいわゆるコネクションプールのこと。仕組みとしては内部に接続とリクエストを管理するQUEUEを持っていてリクエストごとに接続QUEUEから空いている接続をリクエストに割り当てる。もし割り当てる接続がなければそのリクエストをリクエストQUEUEに追加する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span><br />
&nbsp;get_rpc_pool<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> event_base <span style="color: #339933;">*</span>base<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>svr_addr<span style="color: #339933;">,</span> <span style="color: #993333;">short</span> svr_port<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evhttp_connection <span style="color: #339933;">*</span>ev_conn<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evrpc_pool <span style="color: #339933;">*</span>rpc_pool<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rpc_pool <span style="color: #339933;">=</span> evrpc_pool_new<span style="color: #009900;">&#40;</span>base<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>rpc_pool<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get new rpc pool<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// create a connection to RPC server</span><br />
&nbsp; &nbsp; ev_conn <span style="color: #339933;">=</span> evhttp_connection_new<span style="color: #009900;">&#40;</span>svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>ev_conn<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to get new evhttp connection: %s:%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; svr_addr<span style="color: #339933;">,</span> svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// add request connection in the pool</span><br />
&nbsp; &nbsp; evrpc_pool_add_connection<span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #339933;">,</span> ev_conn<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span>rpc_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>evrpc_pool_new()でrpcコネクションプールを作成。</li>
<li>evhttp_connection_newでリクエスト用接続ポインタを生成。</li>
<li>evrpc_pool_add_connectionでevrpc_poolの接続プールに生成されたリクエスト用接続ポインタを追加。</li>
</ul>
<p><p>
以下EVRPC_MAKE_REQUESTで指定するRPCリクエストを送信してサーバよりレスポンスが返ってきたときに呼ばれるコールバック関数。RPC クライアントからのリクエストに対するサーバからのレスポンス結果を表示している。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> <span style="color: #993333;">void</span><br />
&nbsp;GetUserCallback<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evrpc_status <span style="color: #339933;">*</span>status<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> GetUserRequest <span style="color: #339933;">*</span>req<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> GetUserResponse <span style="color: #339933;">*</span>res<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>arg<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; uint32_t errcode<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #339933;">,*</span>email<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* check return status */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>status<span style="color: #339933;">-&gt;</span>error <span style="color: #339933;">!=</span> EVRPC_STATUS_ERR_NONE<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> exitloop<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* get response info */</span><br />
&nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> errcode<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>errcode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE errcode=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> errcode<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> name<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE name=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>EVTAG_HAS<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EVTAG_GET<span style="color: #009900;">&#40;</span>res<span style="color: #339933;">,</span> email<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>email<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;RESPONSE email=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> email<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
exitloop<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; event_loopexit<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>
<h2><strong>ダウンロード、コンパイル、動作確認</strong></h2>
<p>git clone でソースコードを取得してmakeを行う。 リポジトリanyのサブディレクトリ any/libevent_rpcが今回のサンプルにあたる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/any.git &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
<br />
Initialized empty Git repository in /home/m/dev/github/any/.git/<br />
remote: Counting objects: 33, done.<br />
remote: Compressing objects: 100% (32/32), done.<br />
remote: Total 33 (delta 7), reused 0 (delta 0)<br />
Receiving objects: 100% (33/33), 11.28 KiB, done.<br />
Resolving deltas: 100% (7/7), done.<br />
<br />
$ cd any/libevent_rpc<br />
$ make<br />
<br />
g++ -I/usr/include -I/usr/local/include -Wall -g -o simple_rpc_client.o -c simple_rpc_client.cpp<br />
gcc -I/usr/include -I/usr/local/include -Wall -g -o simple.gen.o -c simple.gen.c<br />
g++ -L/usr/local/lib -levent -o simple_rpc_client simple_rpc_client.o simple.gen.o<br />
g++ -I/usr/include -I/usr/local/include -Wall -g -o simple_rpc_server.o -c simple_rpc_server.cpp<br />
g++ -L/usr/local/lib -levent -o simple_rpc_server simple_rpc_server.o simple.gen.o</div></div>
<p>これで同ディレクトリにRPCサーバsimple_rpc_server とRPCクライアントsimple_rpc_client実行ファイルのできあがり。simple_rpc_server 、simple_rpc_clientともに実行時に第一引数にサーバアドレス、第二引数にIOポートを指定する。 まずサーバから立ち上げる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./simple_rpc_server localhost 8888</div></div>
<p>サーバが立ち上がったら次のようにクライアントからリクエスト送信する。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./simple_rpc_client localhost 8888<br />
RESPONSE errcode=0<br />
RESPONSE name=Fooo Baaar<br />
RESPONSE email=baz@foo.bar</div></div>
<p>上のような結果が出力されればOK。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/06/05/libevent_rpc_cs_programmin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LibeventとAPRでイベント駆動型HTTPサーバを作成してみた</title>
		<link>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/</link>
		<comments>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/#comments</comments>
		<pubDate>Fri, 30 Apr 2010 01:35:25 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ab]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apr]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[libevent]]></category>
		<category><![CDATA[memorypool]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[vs_httpd]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=319</guid>
		<description><![CDATA[イベント駆動型処理フレームワークの定番？であるlibevent(An event notification library)とAPR(Apache ProtableRuntime)を使ってイベント駆動型HTTPサーバを書いてみた。既にこの手の簡易HTTPサーバは書き尽くされてる感があり何ら目新しさはなく、若干車輪の再開発的なものになってしまっているのは否めないがそこは気にしないでlibeventが提供するイベント駆動型HTTP処理機能（evhttp）のサンプルの1つとして読んでいただきたく。ちなみにAPRは主にメモリプールのために使っている。 ソースコード &#8211; vs_httpd.c http://github.com/yokawasa/vs_httpd/ http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c イベント駆動HTTP処理基本コード main @ vs_httpd.c struct evhttp *httpd; /* event driven http */ event_init&#40;&#41;; httpd = evhttp_start&#40;g_config-&#62;svr_addr, g_config-&#62;svr_port&#41;; evhttp_set_gencb&#40;httpd, main_request_handler, NULL&#41;; event_dispatch&#40;&#41;; evhttp_free&#40;httpd&#41;; event_initでlibeventライブラリの初期化処理。event_base_new()でもOK evhttp_start(address, port)でbindするアドレス、listenするポートを指定 evhttp_set_gencbでリクエストイベントが通知される度にコールされるコールバック関数(main_request_handler)を登録。 event_dispatchでイベントループを開始しイベント通知を開始 evhttp_freeで作成されたHTTPサーバリソースを開放 &#91;evhttp_set_gencbの定義 @ evhttp.h&#93; /** Set a callback for all requests that are not caught by specific callbacks [...]]]></description>
			<content:encoded><![CDATA[<p>イベント駆動型処理フレームワークの定番？である<a href="http://monkey.org/~provos/libevent/">libevent</a>(An event notification library)と<a href="http://apr.apache.org/">APR</a>(Apache ProtableRuntime)を使ってイベント駆動型HTTPサーバを書いてみた。既にこの手の簡易HTTPサーバは書き尽くされてる感があり何ら目新しさはなく、若干車輪の再開発的なものになってしまっているのは否めないがそこは気にしないでlibeventが提供するイベント駆動型HTTP処理機能（<strong>evhttp</strong>）のサンプルの1つとして読んでいただきたく。ちなみにAPRは主にメモリプールのために使っている。</p>
<p><h2><strong>ソースコード &#8211; vs_httpd.c</strong></h2>
<p><a href="http://github.com/yokawasa/vs_httpd/">http://github.com/yokawasa/vs_httpd/</a><br />
<a href="http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c">http://github.com/yokawasa/vs_httpd/blob/master/vs_httpd.c</a></p>
<p><u>イベント駆動HTTP処理基本コード  main @ vs_httpd.c</u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*</span>httpd<span style="color: #339933;">;</span><br />
<br />
<span style="color: #808080; font-style: italic;">/* event driven http */</span><br />
event_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
httpd <span style="color: #339933;">=</span> evhttp_start<span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>svr_addr<span style="color: #339933;">,</span> g_config<span style="color: #339933;">-&gt;</span>svr_port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
evhttp_set_gencb<span style="color: #009900;">&#40;</span>httpd<span style="color: #339933;">,</span> main_request_handler<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
event_dispatch<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
evhttp_free<span style="color: #009900;">&#40;</span>httpd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<ul>
<li>event_initでlibeventライブラリの初期化処理。event_base_new()でもOK</li>
<li>evhttp_start(address, port)でbindするアドレス、listenするポートを指定</li>
<li>evhttp_set_gencbでリクエストイベントが通知される度にコールされるコールバック関数(main_request_handler)を登録。</li>
<li>event_dispatchでイベントループを開始しイベント通知を開始</li>
<li>evhttp_freeで作成されたHTTPサーバリソースを開放</li>
</ul>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>evhttp_set_gencbの定義 @ evhttp.<span style="color: #202020;">h</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #808080; font-style: italic;">/** Set a callback for all requests that are not caught by specific callbacks */</span><br />
<span style="color: #993333;">void</span> evhttp_set_gencb<span style="color: #009900;">&#40;</span> <span style="color: #993333;">struct</span> evhttp <span style="color: #339933;">*,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evhttp_request <span style="color: #339933;">*,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p><p>
<u>リクエスト処理用コールバック関数 main_request_handler @ vs_httpd.c</u></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">void</span> main_request_handler<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> evhttp_request <span style="color: #339933;">*</span>r<span style="color: #339933;">,</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>args<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; apr_status_t rv<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> evbuffer <span style="color: #339933;">*</span>evbuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>path<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>mimetype<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>complemented_path<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>extbuf<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>filebuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> filesize <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* check reqeust type. currently only suppoert GET */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>type <span style="color: #339933;">!=</span> EVHTTP_REQ_GET<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;only support GET request <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_BADREQUEST<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;only support GET request&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; path <span style="color: #339933;">=</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s%s&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g_config<span style="color: #339933;">-&gt;</span>doc_root<span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>verbose<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;req uri=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;req path=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> path <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file or dir existence check */</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>exists<span style="color: #009900;">&#40;</span>path<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>complemented_path<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>filesize<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_NOTFOUND<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;file not found&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file's extension check */</span><br />
&nbsp; &nbsp; mimetype <span style="color: #339933;">=</span> apr_pstrdup<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> DEFAULT_MIME_TYPE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; extbuf <span style="color: #339933;">=</span> strrchr<span style="color: #009900;">&#40;</span>complemented_path<span style="color: #339933;">,</span><span style="color: #ff0000;">'.'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>extbuf<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">++</span>extbuf<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mimetype <span style="color: #339933;">=</span> find_mime_type<span style="color: #009900;">&#40;</span>extbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* file read */</span><br />
&nbsp; &nbsp; filebuf <span style="color: #339933;">=</span> apr_palloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> filesize <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; apr_file_t <span style="color: #339933;">*</span>file <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rv <span style="color: #339933;">=</span> apr_file_open<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>file<span style="color: #339933;">,</span> complemented_path<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;APR_READ<span style="color: #339933;">|</span>APR_BINARY<span style="color: #339933;">,</span> APR_OS_DEFAULT<span style="color: #339933;">,</span> g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>rv <span style="color: #339933;">!=</span> APR_SUCCESS<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to open file&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; apr_size_t len <span style="color: #339933;">=</span> filesize<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; rv <span style="color: #339933;">=</span> apr_file_read<span style="color: #009900;">&#40;</span>file<span style="color: #339933;">,</span> filebuf<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>rv <span style="color: #339933;">!=</span> APR_SUCCESS<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to read file&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; apr_file_close<span style="color: #009900;">&#40;</span>file<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp;<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>g_config<span style="color: #339933;">-&gt;</span>verbose<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res mimetype=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> mimetype<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res file size=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;res file output=%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> filebuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; evbuf <span style="color: #339933;">=</span> evbuffer_new<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>evbuf<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fprintf<span style="color: #009900;">&#40;</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to create response buffer<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; evhttp_send_error<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_SERVUNAVAIL<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;failed to create response buffer&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; evhttp_add_header<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>output_headers<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Content-Type&quot;</span><span style="color: #339933;">,</span>mimetype<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_add_header<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">-&gt;</span>output_headers<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Content-Length&quot;</span><span style="color: #339933;">,</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,</span>filesize<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evbuffer_add<span style="color: #009900;">&#40;</span>evbuf<span style="color: #339933;">,</span> filebuf<span style="color: #339933;">,</span> len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evhttp_send_reply<span style="color: #009900;">&#40;</span>r<span style="color: #339933;">,</span> HTTP_OK<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;&quot;</span><span style="color: #339933;">,</span> evbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; evbuffer_free<span style="color: #009900;">&#40;</span>evbuf<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<ul>
<li>GETメソッド(EVHTTP_REQ_GET)のみ処理を行う</li>
<li>exists()でリクエストされたuri(evhttp_request_uri(r))がファイルまたはディレクトリとして存在するかをチェック</li>
<li>find_mime_typeでファイル拡張子に対応するMIME TYPEを取得。拡張子がなければデフォルトMIME TYPE application/ocet-stream。この部分の処理は600 行のCでCGIをサポートする軽量WEBサーバ<a href="http://www.ibm.com/developerworks/jp/web/library/wa-ltwebserv/">mattows</a>のコードを参考、流用。</li>
<li>APRの<a href="http://apr.apache.org/docs/apr/1.4/group__apr__file__io.html">ファイルI/Oハンドルライブラリ</a>でファイルの読み込み。画像等バイナリファイルのためにopen時にAPR_BINARYフラグを指定している</li>
<li>evhttp_add_headerでレスポンス用outputヘッダに&#8221;Content-Type&#8221;と&#8221;Content-Lenght&#8221;を指定</li>
<li>(struct evbuffe*)evbufに読み込んだファイルデータをボディデータとして書き込む</li>
<li>evhttp_send_replyでクライアントにレスポンス</li>
</ul>
<p><p>
<u>APRメモリプールの利用 @ vs_httpd.c</u><br />
これは本題からそれるが全体的な特徴としてメモリ管理はAPRの<a href="http://apr.apache.org/docs/apr/1.4/group__apr__pools.html">メモリプール</a>を利用しているのでここで軽く説明する。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> apr_pool_t <span style="color: #339933;">*</span>g_mem_pool <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
apr_pool_create<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>g_mem_pool<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
...<br />
<span style="color: #202020;">g_config</span> <span style="color: #339933;">=</span> apr_pcalloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>httpsvr_config<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
path <span style="color: #339933;">=</span> apr_psprintf<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s%s&quot;</span><span style="color: #339933;">,</span> g_config<span style="color: #339933;">-&gt;</span>doc_root<span style="color: #339933;">,</span> evhttp_request_uri<span style="color: #009900;">&#40;</span>r<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
mimetype <span style="color: #339933;">=</span> apr_pstrdup<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> DEFAULT_MIME_TYPE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
filebuf <span style="color: #339933;">=</span> apr_palloc<span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #339933;">,</span> filesize <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
rv <span style="color: #339933;">=</span> apr_file_open<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>file<span style="color: #339933;">,</span> complemented_path<span style="color: #339933;">,</span> APR_READ<span style="color: #339933;">|</span>APR_BINARY<span style="color: #339933;">,</span> APR_OS_DEFAULT<span style="color: #339933;">,</span> g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
...<br />
<span style="color: #202020;">apr_pool_destroy</span><span style="color: #009900;">&#40;</span>g_mem_pool<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<ul>
<li>apr_pool_createでメモリプールの作成 </li>
<li>apr_palloc、apr_psprintf, を使用して、メモリプールからメモリを確保します</li>
<li>apr_pool_destroyを使用して、メモリプールを破棄 </li>
</ul>
<p><h2><strong>ダウンロード、コンパイル、そしてテスト</strong></h2>
<p>git clone で<a href="http://github.com/yokawasa/vs_httpd/">vs_httpdのコード</a>を取得(リポジトリ複製)する。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git clone git@github.com:yokawasa/vs_httpd.git<br />
<br />
Initialized empty Git repository in /home/m/dev/github/t/vs_httpd/.git/<br />
remote: Counting objects: 11, done.<br />
remote: Compressing objects: 100% (11/11), done.<br />
remote: Total 11 (delta 0), reused 0 (delta 0)<br />
Receiving objects: 100% (11/11), 8.51 KiB, done.</div></div>
<p>libeventとaprヘッダへのインクルードや両ライブラリのリンクができるようにMakefileのパス調整を行う。もちろんlibeventとaprがインストール済みであることが前提。もしまだならばまずはlibeventとaprをインストールしましょ。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ vi Makefile<br />
CFLAGS = -I&lt;libeventのincludeパス&gt; -I&lt;apacheのincludeパス -Wall -g<br />
LIBS = -L&lt;libeventのlibパス&gt; -levent -L&lt;apacheのlibパス&gt; -lapr-1</div></div>
<p>パス変更後にmakeを実行。これでvs_httpdバイナリの出来上がり。vs_httpdの使い方は次のとおり。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./vs_httpd -h<br />
Usage: vs_httpd [-a address] [-p port] [-d documentroot]<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[-D] [-v] [-h]<br />
Options:<br />
&nbsp; -a address &nbsp; &nbsp; &nbsp;: define server address (default: &quot;0.0.0.0&quot;)<br />
&nbsp; -p port &nbsp; &nbsp; &nbsp; &nbsp; : define server port (default: 8080)<br />
&nbsp; -d documentroot : define document root (default: &quot;./&quot;) &nbsp;<br />
&nbsp; -D &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: daemonize option 0-off,1-on (default: 0)<br />
&nbsp; -v &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: verbose option 0-off,1-on (default: 0)<br />
&nbsp; -h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;: list available command line options (this page)</div></div>
<p>使い方の説明にあるようにオプションを指定しない場合はデフォルトサーバアドレス&#8221;0.0.0.0&#8243;、ポート番号 8080、ドキュメントルート &#8220;./&#8221;、デーモンモードOFF、VerboseモードOFFで起動される。尚、デフォルトインデックスファイルをindex.htmlとしているので http://hostname:port/path/のようにファイル名を指定しないでアクセスした場合はvs_httpdがドキュメントルート /path/配下のindex.htmlを表示させようとする。試しにvs_httpdをポート(8888)、ドキュメントルート(/home /vs_httpd/docs)、デーモンモードON、VerboseモードONで起動させてみる。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ./vs_httpd -p 8888 -d /home/vs_httpd/docs -D -v<br />
svr_addr=0.0.0.0<br />
svr_port=8888<br />
doc_root=/home/vs_httpd/docs<br />
verbose=1<br />
daemonize=1<br />
$ ※<br />
<br />
※ daemonized! fork成功、親プロセスからはexitで子プロセスに処理が移る</div></div>
<p>ページ表示テスト用にvs_httpd/pages下にhtml、css、jpegファイルを用意してあるのでこれらを/home/vs_httpd /docs配下に配置して実際にブラウザでindex.htmlを表示させてみる。成功すると以下のようなページが表示させる。</p>
<p><a href="http://www.flickr.com/photos/yk55/4563326293/" title="VSHTTPD by yoichi*, on Flickr"><img src="http://farm4.static.flickr.com/3214/4563326293_63624d58f8_o.jpg" width="680" height="335" alt="VSHTTPD" /></a></p>
<p><h2><strong>ベンチマーク結果</strong></h2>
<p><a href="http://httpd.apache.org/docs/2.0/programs/ab.html">ab(apache bench)</a>でベンチマークテストをしてみる。並列数100、リクエスト数10000。比較のためにapache2(mpm prefork)でもテストをしてみる。まずはvs_httpdのテスト結果。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ab -c 100 -n 10000 http://127.0.0.1:8888/<br />
<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;127.0.0.1<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8888<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;285 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 2.295104 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;3490440 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 2858550 bytes<br />
Requests per second: &nbsp; &nbsp;4357.10 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 22.951 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 0.230 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1484.90 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp;5 &nbsp; 4.2 &nbsp; &nbsp; &nbsp;4 &nbsp; &nbsp; &nbsp;27<br />
Processing: &nbsp; &nbsp; 5 &nbsp; 17 &nbsp; 6.4 &nbsp; &nbsp; 15 &nbsp; &nbsp; &nbsp;46<br />
Waiting: &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp; 13 &nbsp; 6.5 &nbsp; &nbsp; 11 &nbsp; &nbsp; &nbsp;45<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp; 10 &nbsp; 22 &nbsp; 7.0 &nbsp; &nbsp; 21 &nbsp; &nbsp; &nbsp;47<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp; 21<br />
&nbsp; 66% &nbsp; &nbsp; 24<br />
&nbsp; 75% &nbsp; &nbsp; 26<br />
&nbsp; 80% &nbsp; &nbsp; 27<br />
&nbsp; 90% &nbsp; &nbsp; 32<br />
&nbsp; 95% &nbsp; &nbsp; 37<br />
&nbsp; 98% &nbsp; &nbsp; 41<br />
&nbsp; 99% &nbsp; &nbsp; 42<br />
&nbsp;100% &nbsp; &nbsp; 47 (longest request)</div></div>
<p>次にapache2(mpm prefork)でも同様のテストを行う。利用するページはvs_httpdと同じでテスト環境のprefork MPM設定値は次のとおり。</p>
<pre>
[prefork MPMの設定値]
StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0
</pre>
<p>以下、apache2のテスト結果。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ ab -c 100 -n 10000 http://127.0.0.1/<br />
<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;Apache/2.2.2<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;127.0.0.1<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;80<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;285 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 3.580232 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;5310000 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 2850000 bytes<br />
Requests per second: &nbsp; &nbsp;2793.12 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 35.802 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 0.358 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1448.23 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp;0 &nbsp; 0.8 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;10<br />
Processing: &nbsp; &nbsp; 8 &nbsp; 35 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
Waiting: &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; 34 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp; 12 &nbsp; 35 &nbsp; 7.4 &nbsp; &nbsp; 31 &nbsp; &nbsp; &nbsp;66<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp; 31<br />
&nbsp; 66% &nbsp; &nbsp; 36<br />
&nbsp; 75% &nbsp; &nbsp; 40<br />
&nbsp; 80% &nbsp; &nbsp; 43<br />
&nbsp; 90% &nbsp; &nbsp; 47<br />
&nbsp; 95% &nbsp; &nbsp; 50<br />
&nbsp; 98% &nbsp; &nbsp; 53<br />
&nbsp; 99% &nbsp; &nbsp; 54<br />
&nbsp;100% &nbsp; &nbsp; 66 (longest request)</div></div>
<p>単純すぎるベンチマークテストなのでアレなのですが、10000リクエストの処理時間だけをみるとvs_httpd(2.295104 seconds)のほうがapache2(3.580232 seconds)よりも約35%速いといえる。余計な処理はな何も行わないで静的ファイル処理に特化しているので速いのは当たり前なんだけど、うれしい。この世界、速いは美徳。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/04/30/eventdriven_http_server_vs_httpd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>簡単Boehm GCによるC/C++メモリリーク検知</title>
		<link>http://yk55.com/blog/2010/03/25/boehm_gc_detect_memory_leak/</link>
		<comments>http://yk55.com/blog/2010/03/25/boehm_gc_detect_memory_leak/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 14:37:54 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[boehm]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[gc]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=269</guid>
		<description><![CDATA[Boehm GCはガベージコレクションの標準実装がないC/C++でガベージコレクションのようなことを実現可能にしてくれるライブラリ。 一度確保されたリソースは明示的に解放処理が行われない限りメモリリークが発生してしまうけれどもBoehm GCで用意されている関数群（通常はGC_MALLOC）を使ってリソースを確保すれば不要になった段階で自動的に解放してくれる。 ソースコード全体で統一してこのライブラリを利用していればオブジェクトの寿命管理の手間は減るだろうし自分がコードの責任者であるならば難しいところを枯れたライブラリにお任せできるので安心感はあるのだろう。ちなみにこのライブラリ、以前からその存在は知ってはいたけれどスマートポインタ派の自分としてはオブジェクトの寿命管理のためにこれを使うモチベーションはいまいち感じられない。 そんなBoehm GCは「Using the Garbage Collector as Leak Detector」で紹介されているようにメモリリーク検知用ユーティリティとしても使える。ドキュメントやソースコードを覗いてみて少し工夫すれば手軽に既存のコードに殆ど手を加えること無くメモリリークの検知ができそうだったので試しにサンプルコードを書いてみた。以下、Boehm GCのインストールからC/C++コードでのメモリリーク検知について。 Boehm GCインストール まずは自分の環境(debina5.0.1&#8243;lenny&#8221;)にBoehm GCをインストールしてみる。 Boehm GCライブラリをつかって開発するにはlibgc-devとlibgc1c2が必要。もし自分の環境に合うパッケージが存在しない場合は直接ここから tar.gzボールをダウンロードして例のconfigure、make、make install。 $ sudo apt-get install libgc-dev $ sudo apt-get install libgc1c2 $ dpkg --list &#124;grep libgc ii &#160;libgc-dev &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; 1:6.8-1.1 &#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/">Boehm GC</a>はガベージコレクションの標準実装がないC/C++でガベージコレクションのようなことを実現可能にしてくれるライブラリ。 一度確保されたリソースは明示的に解放処理が行われない限りメモリリークが発生してしまうけれどもBoehm GCで用意されている関数群（通常はGC_MALLOC）を使ってリソースを確保すれば不要になった段階で自動的に解放してくれる。 ソースコード全体で統一してこのライブラリを利用していればオブジェクトの寿命管理の手間は減るだろうし自分がコードの責任者であるならば難しいところを枯れたライブラリにお任せできるので安心感はあるのだろう。ちなみにこのライブラリ、以前からその存在は知ってはいたけれどスマートポインタ派の自分としてはオブジェクトの寿命管理のためにこれを使うモチベーションはいまいち感じられない。</p>
<p>そんなBoehm GCは「<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html">Using the Garbage Collector as Leak Detector</a>」で紹介されているようにメモリリーク検知用ユーティリティとしても使える。ドキュメントやソースコードを覗いてみて少し工夫すれば手軽に既存のコードに殆ど手を加えること無くメモリリークの検知ができそうだったので試しにサンプルコードを書いてみた。以下、Boehm GCのインストールからC/C++コードでのメモリリーク検知について。</p>
<h2><strong>Boehm GCインストール</strong></h2>
<p>まずは自分の環境(debina5.0.1&#8243;lenny&#8221;)にBoehm GCをインストールしてみる。 Boehm GCライブラリをつかって開発するには<a href="http://packages.debian.org/lenny/libgc-dev">libgc-dev</a>と<a href="http://packages.debian.org/lenny/libgc1c2">libgc1c2</a>が必要。もし自分の環境に合うパッケージが存在しない場合は直接<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/">ここ</a>から tar.gzボールをダウンロードして例のconfigure、make、make install。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ sudo apt-get install libgc-dev<br />
$ sudo apt-get install libgc1c2<br />
$ dpkg --list |grep libgc<br />
ii &nbsp;libgc-dev &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1:6.8-1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;conservative garbage collector for C (develo<br />
ii &nbsp;libgc1c2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1:6.8-1.1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;conservative garbage collector for C and C++</div></div>
<p><h2><strong>Cコードメモリリーク検知 &#8211; *alloc/freeをGC_関数に置換</strong></h2>
<p>Boehm GCにはGC_MALLOC等のリソース確保系関数でリソース確保されたにもかかわらずGC_FREE等の解放系関数でリソース解放されずにリークしてしまっているオブジェクトを検知してそれらをレポートする機能がある。 このメモリリーク検知レポートはGC_gcollect関数で実行される。ただしこのときメモリリーク検知レポート機能をオンにするためにはそもそもBoehm GC を-DFIND_LEAKオプションでコンパイルするか、または実行時にダイナミックにGC_find_leak=1をセットしてやる必要がある。</p>
<ul>
<li>対象オブジェクト: GC_MALLOC等でリソース確保されたにもかかわらずGC_FREE等で解放されないオブジェクト</li>
<li>検知レポート実行関数： GC_gcollect</li>
<li>前提条件： -DFIND_LEAKオプションでコンパイルされたBoehmGC or 実行時にGC_find_leak=1をセット</li>
</ul>
<p>
「<a href="http：//www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html">Using the Garbage Collector as Leak Detector</a>」ではこのメモリリーク検知レポート機能を利用して実際のCコードのメモリリークを検知するために直接ヒープからメモリ確保、解放を行うための基本関数をBoehmGCの関数で置き換えるためのヘッダを用意している。</p>
<p><span style="text-decoration: underline;">gc_detect_leaks.h</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#define GC_DEBUG</span><br />
<span style="color: #339933;">#include &quot;gc.h&quot;</span><br />
<span style="color: #339933;">#define malloc(n) GC_MALLOC(n)</span><br />
<span style="color: #339933;">#define calloc(m,n) GC_MALLOC((m)*(n))</span><br />
<span style="color: #339933;">#define free(p) GC_FREE(p)</span><br />
<span style="color: #339933;">#define realloc(p,n) GC_REALLOC((p),(n))</span><br />
<span style="color: #339933;">#define CHECK_LEAKS() GC_gcollect()</span></div></div>
<p>試しにメモリリークを引き起こすコードに上記ヘッダをインクルードしたサンプルコード(t1.c)を用意してコンパイル+ 実行してみる。<br />
<span style="text-decoration: underline;">サンプルコード: t1.c</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #339933;">#include &quot;gc_detect_leaks.h&quot;</span><br />
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; GC_find_leak <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; a <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>malloc<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>　　<span style="color: #666666; font-style: italic;">// t1.c: line7</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//free(a);</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CHECK_LEAKS<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[コンパイルと実行結果]<br />
$ gcc -g -Wall t1.c -o t1 -I/usr/include/gc -L/usr/lib -lgc<br />
$ ./t1<br />
Leaked composite object at 0x805af90 (t1.c:7, sz=100, NORMAL)<br />
Leaked composite object at 0x805af10 (t1.c:7, sz=100, NORMAL)<br />
Leaked composite object at 0x805af90 (t1.c:7, sz=100, NORMAL)<br />
...</div></div>
<p>無事メモリリークを検知。メモリリークの原因となっている箇所（t1.cの７行目）も特定されているので合格。ちなみに上記ヘッダでGC_DEBUGをdefineしているは理由は<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gch.txt">gc.h</a>で定義されているGC_MALLOCをデバック用出力にモードにするため。以下gc.hの該当部分だけを略して抜粋。</p>
<p><span style="text-decoration: underline;">gc6.8 &#8211; /usr/local/gc/gc.h</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#ifdef GC_ADD_CALLER</span><br />
<span style="color: #339933;"># &nbsp;define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__</span><br />
...略...<br />
<span style="color: #339933;">#else</span><br />
<span style="color: #339933;"># &nbsp;define GC_EXTRAS __FILE__, __LINE__</span><br />
...略...<br />
<span style="color: #339933;">#endif</span><br />
<br />
<span style="color: #339933;"># ifdef GC_DEBUG</span><br />
<span style="color: #339933;"># &nbsp; define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)</span><br />
... 略...<br />
<span style="color: #339933;"># else</span><br />
<span style="color: #339933;"># &nbsp; define GC_MALLOC(sz) GC_malloc(sz)</span><br />
...略...<br />
<span style="color: #339933;"># endif</span></div></div>
<p><h2><strong>C++ コードメモリリーク検知 &#8211; gc/gc_cleanupクラスで継承</strong></h2>
<p>次にC++コードのメモリリーク検知を行う。C++のデータ構造の基本はクラス（細かいことを省けば構造体もクラス）でありクラスはnewオペレーターでメモリを動的に確保する。 当然のことながらデフォルトのnewオペレータでリソース確保した場合はGC回収不能であるためBoehm GCが用意しているC++用ライブラリを利用する。<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gc_cpph.txt">gc_cpp.h</a>をみるとこれは単なるCライブラリのラップクラス。以下のようにgcやgc_cleanupクラスをベースクラスとすることでGC回収可能なオブジェクトとして扱うことができる。</p>
<p><span style="text-decoration: underline;">サンプルコード: t2.cpp</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #339933;">#define GC_DEBUG</span><br />
<span style="color: #339933;">#include &quot;gc_cpp.h&quot;</span><br />
<span style="color: #339933;">#define CHECK_LEAKS() GC_gcollect()</span><br />
class Foo<span style="color: #339933;">:</span> public gc<span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; GC_find_leak <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; Foo <span style="color: #339933;">*</span>f<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; f <span style="color: #339933;">=</span>new Foo<span style="color: #339933;">;</span>　　　<span style="color: #666666; font-style: italic;">// t2.cpp: line10</span><br />
<span style="color: #666666; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp;delete f;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CHECK_LEAKS<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[コンパイルと実行結果]<br />
$ g++ -g -Wall t2.cpp -o t2 -I/usr/include/gc -L/usr/lib -lgc<br />
$ ./t2<br />
Leaked composite object at 0x805afe8 (/usr/include/gc/gc_cpp.h:274, sz=1, NORMAL)<br />
Leaked composite object at 0x805afd0 (/usr/include/gc/gc_cpp.h:274, sz=1, NORMAL)<br />
Leaked composite object at 0x805afe8 (/usr/include/gc/gc_cpp.h:274, sz=1, NORMAL)<br />
....</div></div>
<p>これも無事メモリリーク検知はされている。ただしリーク箇所が/usr/include/gc/gc_cpp.hのL274行目を指している。これではリークの原因箇所がわからない。できればt2.cppのL10行目(f=new Foo)を指してもらいたい。さらにこの方法では単に既存のコードのメモリーリーク検知のみを行いたい場合でも、クラスをgc やgc_cleanupクラスで継承させるといったコードに手を加えていく作業が必要があるのでとても面倒でありコード量が多ければ多いほど手間がかかる。</p>
<p><h2><strong>C++コードメモリリーク検知 &#8211; new/deleteオペレータのオーバーロード</strong></h2>
<p>そこで既存のコードにあまり手を加えなくてもメモリリーク検知ができ、且つリークの原因箇所を特定できる方法を考えてみた。まずは既存のコードの手を加えないでメモリリーク検知する方法。クラスはリソースの確保、解放をそれぞれnew、 deleteオペレータで行うのでこれらをグローバルにオーバーロードしてやり内部のリソース確保、解放のための実装をGC関数で置き換えてやる。そしてそのヘッダを既存のコードにインクルードしてやれば既存のコードに手を加えないでメモリーリークの検知ができるのではないかと。 ヘッダは以下のような感じ。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#define GC_DEBUG</span><br />
<span style="color: #339933;">#include &quot;gc.h&quot;</span><br />
<span style="color: #993333;">void</span><span style="color: #339933;">*</span> operator new<span style="color: #009900;">&#40;</span>size_t size<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> GC_MALLOC<span style="color: #009900;">&#40;</span>size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span><span style="color: #339933;">*</span> operator new<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span>size_t size<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> GC_MALLOC<span style="color: #009900;">&#40;</span>size<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span> operator delete<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span> GC_FREE<span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span> &nbsp;operator delete<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span> GC_FREE<span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>ただしこれだけではメモリリークの検知はできてもリークの原因箇所の特定が難しい。このままだと上記ヘッダのGC_MALLOC()コール箇所がリーク箇所としてレポートされてしまう。 理想はnewオペレータをコールしている箇所がレポートされて欲しい。ということで次のように GC_debug_malloc()にnewオペレータコール箇所のファイル名と行を渡すように変更してみる。</p>
<p><span style="text-decoration: underline;">gc_detect_leaks.h</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#define GC_DEBUG</span><br />
<span style="color: #339933;">#include &quot;gc.h&quot;</span><br />
<span style="color: #993333;">void</span><span style="color: #339933;">*</span> operator new<span style="color: #009900;">&#40;</span>size_t size<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> s<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> i<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> GC_debug_malloc<span style="color: #009900;">&#40;</span>size<span style="color: #339933;">,</span>s<span style="color: #339933;">,</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span><span style="color: #339933;">*</span> operator new<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span>size_t size<span style="color: #339933;">,</span> &nbsp;<span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> s<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> i<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> GC_debug_malloc<span style="color: #009900;">&#40;</span>size<span style="color: #339933;">,</span>s<span style="color: #339933;">,</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span> operator delete<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span> GC_debug_free<span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #993333;">void</span> &nbsp;operator delete<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span> p<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span> GC_debug_free<span style="color: #009900;">&#40;</span>p<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #339933;"># &nbsp; define new new(__FILE__, __LINE__)</span><br />
<span style="color: #339933;"># &nbsp; define CHECK_LEAKS() GC_gcollect()</span><br />
<span style="color: #993333;">int</span> GC_find_leak <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span></div></div>
<p>ためしにメモリリークを引き起こすC++コードに上記ヘッダをインクルードしたものを用意してコンパイル+ 実行してみる。今度はヘッダにint GC_find_leak = 1を含めているのでサンプルコードにGC_find_leak = 1をセットする必要はない。</p>
<p><span style="text-decoration: underline;">サンプルコード: t3.cpp</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #339933;">#include &quot;gc_detect_leaks.h&quot;</span><br />
class Foo<span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; Foo <span style="color: #339933;">*</span>f<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; f <span style="color: #339933;">=</span>new Foo<span style="color: #339933;">;</span> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">// t3.cpp: line7</span><br />
<span style="color: #666666; font-style: italic;">// &nbsp; &nbsp; &nbsp; &nbsp;delete f;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CHECK_LEAKS<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[コンパイルと実行結果]<br />
$ g++ -g -Wall t3.cpp -o t3 -I/usr/include/gc -L/usr/lib -lgc<br />
$ ./t3<br />
Leaked composite object at 0x805afe8 (t3.cpp:7, sz=1, NORMAL)<br />
Leaked composite object at 0x805afd0 (t3.cpp:7, sz=1, NORMAL)<br />
Leaked composite object at 0x805afe8 (t3.cpp:7, sz=1, NORMAL)<br />
...</div></div>
<p>見事メモリリークを検知しnewオペレータをコールしている行がレポートされた。というわけでこのヘッダをインクルードするだけで他の既存のコードに手を加えることなくメモリリークを検知することができた。</p>
<p>最後に、今回使ったサンプルコードとここで紹介したヘッダを少し体裁を整えて<a href="http://github.com/yokawasa/any/tree/master/boehmgc/">github</a>にあげておきました。ちなみにgithubにあげたgc_detect_leaks.hを使う際は-DGC_DETECT_MEM_LEAKでコンパイルすることをお忘れなく。</p>
<p><a href="http://github.com/yokawasa/any/tree/master/boehmgc/">http://github.com/yokawasa/any/tree/master/boehmgc/</a></p>
<p>おわり</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/03/25/boehm_gc_detect_memory_leak/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/03/25/boehm_gc_detect_memory_leak/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ページ置換アルゴリズム(Page Replacement Algorithms)のシュミレーション</title>
		<link>http://yk55.com/blog/2010/03/13/page_replacement_algo_simulation/</link>
		<comments>http://yk55.com/blog/2010/03/13/page_replacement_algo_simulation/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 00:46:33 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[fifo]]></category>
		<category><![CDATA[lru]]></category>
		<category><![CDATA[optimal]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=227</guid>
		<description><![CDATA[システムのオペレーションをやっているとスラッシングが原因でサーバが一時的にサービス提供不能になっていまうなんてことがたまにある。スラッシングとは、例えば大量の処理リクエストが発生してしまい利用可能な物理メモリ量を大きく超えてしまった場合に起ったりする。OSのメモリ割り当て処理（ページアウト・イン）が追いつかないため全体のパフォーマンスが極端に低下、最悪固まってしまいlsすらできなくなる。この記事のタイトルにあるページ置換アルゴリズム（Page Replacement Algorithm）はこのページ割り当てを効率的に行うためのアルゴリズム群のことでどれを選択するかによってパフォーマンスが大きく左右される。ちなみにこのアルゴリズム群はページに限らずキャッシュやメモリプールなど限られたリソースを効率的に割り当てる場合には必ずといっていいくらい登場するものなのでプログラマとしては是非とも押さえておきたいところ。 前置きが少し長くなってきたのでここらで本題に入る。ページ置換アルゴリズムを調べていたときにumassの教材として作られたであろう置換アルゴリズムのシュミレーションツールを見つけた。JavaScript版とJava Applet版の2つ。アルゴリズム学習者にとっては目で見て挙動が確認できるので便利なはず。 これ見て自分もなんとなく作ってみたくなったので勉強がてらにcで作ってみた。もちろんCUI。アルゴリズムはLRU、FIFO、OPTIMALの3つに絞った。これがc版ページ置換アルゴリズムシュミレーションツール。 http://github.com/yokawasa/any/raw/master/page_rep_algos/page_rep_algos.c 内容は、見つけたツールと同じで物理メモリのページ・フレームの数、置換アルゴリズム、そして今後メモリ割り当ての必要なページ番号の数列を指定して順番にそのページ番号に対して物理メモリの割り当てを行うといったもの。利用ページ番号が既に物理メモリの割り当てが既にされていればHit、されていなければMiss（ページフォルト発生）として過去に割り当てたページの置き換えを行い、最終的なページフォールト発生数とHit率を出力する。 以下、ツールのコンパイルとその使い方、そして各アルゴリズムの挙動をツールの実行結果とあわせて説明する。 ツールのコンパイルとその使い方 上記URLからソースコードを取得してからコンパイルを行う。 gcc -o page_rep_algos page_rep_algos.c 使い方はアルゴリズム、アクセスするページ番号の数列、ページフレーム数の3つのオプションを次のように指定。 ./page_rep_algos [options] Options are: -a &#160;&#60;アルゴリズム&#62; &#160; LRU, FIFO または OPTIMAL -p &#160;&#60;ページ番号列&#62; &#160; Page # sequences in which the pages are accessed by some program &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;in the order. [...]]]></description>
			<content:encoded><![CDATA[<p>システムのオペレーションをやっているとスラッシングが原因でサーバが一時的にサービス提供不能になっていまうなんてことがたまにある。スラッシングとは、例えば大量の処理リクエストが発生してしまい利用可能な物理メモリ量を大きく超えてしまった場合に起ったりする。OSのメモリ割り当て処理（ページアウト・イン）が追いつかないため全体のパフォーマンスが極端に低下、最悪固まってしまいlsすらできなくなる。この記事のタイトルにある<a href="http://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%BC%E3%82%B8%E7%BD%AE%E6%8F%9B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0">ページ置換アルゴリズム</a>（<a href="http://en.wikipedia.org/wiki/Page_replacement_algorithm">Page Replacement Algorithm</a>）はこのページ割り当てを効率的に行うためのアルゴリズム群のことでどれを選択するかによってパフォーマンスが大きく左右される。ちなみにこのアルゴリズム群はページに限らずキャッシュやメモリプールなど限られたリソースを効率的に割り当てる場合には必ずといっていいくらい登場するものなのでプログラマとしては是非とも押さえておきたいところ。</p>
<p>前置きが少し長くなってきたのでここらで本題に入る。ページ置換アルゴリズムを調べていたときに<a href="http://www.ecs.umass.edu/">umass</a>の教材として作られたであろう置換アルゴリズムのシュミレーションツールを見つけた。<a href="http://www.ecs.umass.edu/ece/koren/architecture/PReplace/">JavaScript版</a>と<a href="http://www.ecs.umass.edu/ece/koren/architecture/RepPolicies/">Java Applet版</a>の2つ。アルゴリズム学習者にとっては目で見て挙動が確認できるので便利なはず。 これ見て自分もなんとなく作ってみたくなったので勉強がてらにcで作ってみた。もちろんCUI。アルゴリズムはLRU、FIFO、OPTIMALの3つに絞った。これがc版ページ置換アルゴリズムシュミレーションツール。</p>
<p><a href="http://github.com/yokawasa/any/raw/master/page_rep_algos/page_rep_algos.c">http://github.com/yokawasa/any/raw/master/page_rep_algos/page_rep_algos.c</a></p>
<p>内容は、見つけたツールと同じで物理メモリのページ・フレームの数、置換アルゴリズム、そして今後メモリ割り当ての必要なページ番号の数列を指定して順番にそのページ番号に対して物理メモリの割り当てを行うといったもの。利用ページ番号が既に物理メモリの割り当てが既にされていればHit、されていなければMiss（ページフォルト発生）として過去に割り当てたページの置き換えを行い、最終的なページフォールト発生数とHit率を出力する。</p>
<p>以下、ツールのコンパイルとその使い方、そして各アルゴリズムの挙動をツールの実行結果とあわせて説明する。</p>
<h2><strong> ツールのコンパイルとその使い方</strong></h2>
<p><a href="http://github.com/yokawasa/any/raw/master/page_rep_algos.c">上記URL</a>からソースコードを取得してからコンパイルを行う。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">gcc -o page_rep_algos page_rep_algos.c</div></div>
<p>使い方はアルゴリズム、アクセスするページ番号の数列、ページフレーム数の3つのオプションを次のように指定。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">./page_rep_algos [options]<br />
Options are:<br />
-a &nbsp;&lt;アルゴリズム&gt; &nbsp; LRU, FIFO または OPTIMAL<br />
-p &nbsp;&lt;ページ番号列&gt; &nbsp; Page # sequences in which the pages are accessed by some program<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;in the order. max entry num is 100. &nbsp;(space between each)<br />
-f &nbsp;&lt;フレーム数&gt; &nbsp; &nbsp; The number of page frames. max frame num is 10.<br />
-h &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Display usage information (this message)<br />
<br />
実行例:<br />
./page_rep_algos -a LRU -p &quot;0 1 2 3 2 1 4 3 6 0 9&quot; -f 3</div></div>
<h2><strong>LRU（Least Recently Used）</strong></h2>
<p><a href="http://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%BC%E3%82%B8%E7%BD%AE%E6%8F%9B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0#LRU.EF.BC.88Least_Recently_Used.EF.BC.89">LRU</a>ではその名のとおり「最も長く使われないページ」を置換の対象とする。なのでいつ追加されたということよりも最後にアクセスされてからどれだけ経過しているかを測り最も長いものから置換していく。 例えばページフレーム数3でアクセスページ番号列を「0 1 2 3 2 1 4 1 6 0 2 1」とした場合、1つずつトレースすると次のような図になる。Faultとはページフォールト(Page Fault)のことでFaultのない場合はページHitしたことを意味する。</p>
<p><a title="LRU by yoichi*, on Flickr" href="http://www.flickr.com/photos/yk55/4423171522/"><img src="http://farm3.static.flickr.com/2721/4423171522_0f239aa4ab_o.png" alt="LRU" width="598" height="202" /></a></p>
<p>Page Referenceが4の時のページ置換計算を例にする。置換される前の各ページフレームPF[0]、PF[1]、PF[2]にはそれぞれページ番号3、1、2が割り当てられている。ページ番号4がアクセスされるタイミングでページ番号3、1、2がアクセスされていない期間はそれぞれ3、1、2となる。よって最も長くアクセスされていないPF[0](ページ番号3)が置換対象となる。ツールで実行してみると次のとおり。ページフォールトが9回で、Hit率25%。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[kawasaki@debian:~] $ ./page_rep_algos -a LRU -p &quot;0 1 2 3 2 1 4 1 6 0 2 1&quot; -f 3<br />
0: &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
3: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
1: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
4: &nbsp; &nbsp;4 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;4 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
6: &nbsp; &nbsp;4 &nbsp; 1 &nbsp; 6 &nbsp; &nbsp;Miss<br />
0: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 6 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;0 &nbsp; 2 &nbsp; 6 &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;0 &nbsp; 2 &nbsp; 1 &nbsp; &nbsp;Miss</div></div>
<p>Number of Page Frames = 3<br />
Total Number of References = 12<br />
Number of Hits = 3<br />
Number of Page Fault = 9<br />
HitRatio = 0.25</p>
<h2><strong>FIFO（First-In First-Out）</strong></h2>
<p><a href="http://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%BC%E3%82%B8%E7%BD%AE%E6%8F%9B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0#FIFO.EF.BC.88First-In_First-Out.EF.BC.89">FIFO</a>もその名のとおり「早く追加されたページ」を置換の対象とする。この場合はLRUと違っていつ追加されたということが重要であり最も早いものから置換していく。<br />
LRUと同くサンプル( ページフレーム数3でアクセスページ番号列を「0 1 2 3 2 1 4 1 6 0 2 1」とした場合、1つずつトレースすると次のような図になる。</p>
<p><a title="FIFO by yoichi*, on Flickr" href="http://www.flickr.com/photos/yk55/4422406289/"><img src="http://farm3.static.flickr.com/2724/4422406289_e4f1663cc2_o.png" alt="FIFO" width="597" height="202" /></a></p>
<p>ツールで実行してみると次のとおり。ページフォールトが10回で、Hit率17%。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[kawasaki@debian:~] $ ./page_rep_algos -a FIFO -p &quot;0 1 2 3 2 1 4 1 6 0 2 1&quot; -f 3<br />
0: &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
3: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
1: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
4: &nbsp; &nbsp;3 &nbsp; 4 &nbsp; 2 &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;3 &nbsp; 4 &nbsp; 1 &nbsp; &nbsp;Miss<br />
6: &nbsp; &nbsp;6 &nbsp; 4 &nbsp; 1 &nbsp; &nbsp;Miss<br />
0: &nbsp; &nbsp;6 &nbsp; 0 &nbsp; 1 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;6 &nbsp; 0 &nbsp; 2 &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;1 &nbsp; 0 &nbsp; 2 &nbsp; &nbsp;Miss</div></div>
<p>Number of Page Frames = 3<br />
Total Number of References = 12<br />
Number of Hits = 2<br />
Number of Page Fault = 10<br />
HitRatio = 0.17</p>
<h2><strong>OPTIMAL</strong></h2>
<p><a href="http://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%BC%E3%82%B8%E7%BD%AE%E6%8F%9B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0#.E7.90.86.E8.AB.96.E4.B8.8A.E6.9C.80.E9.81.A9.E3.81.AA.E3.83.9A.E3.83.BC.E3.82.B8.E7.BD.AE.E6.8F.9B.E3.82.A2.E3.83.AB.E3.82.B4.E3.83.AA.E3.82.BA.E3.83.A0">OPTIMAL</a>とは未来に対して「最も長い間使われないであろう」ページを置換の対象とする。LRUが過去に対して「最も長く使われないページ」であるのと対象的であるといえる。ただし、実行時に未来の計測をするのは不可能であり経験則でパターン分析ができているとか、今回のように予めパターンを指定する場合においてのみ有効である。理論上一番いいのはOPTIMALアルゴリズムといわれているが未来予測どうするのかといったところでしょうか。</p>
<p><a title="OPTIMAL by yoichi*, on Flickr" href="http://www.flickr.com/photos/yk55/4422406307/"><img src="http://farm5.static.flickr.com/4071/4422406307_9ab8e71c4a_o.png" alt="OPTIMAL" width="599" height="202" /></a></p>
<p>Page Referenceが4の時のページ置換計算を例にする。 置換される前の各ページフレームPF[0]、PF[1]、PF[2]にはそれぞれページ番号3、1、2が割り当てられている。ページ番号4がアクセスされるタイミングからページ番号3、1、2が未来にアクセスされるまでの期間はそれぞれ5以上、1、4となる。よって最も遠い未来までアクセスされないPF[0](ページ番号3)が置換対象となる。ツールで実行してみると次のとおり。ページフォールトが7回で、Hit率42%と最も高い。</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[kawasaki@debian:~] $ ./page_rep_algos -a OPTIMAL -p &quot;0 1 2 3 2 1 4 1 6 0 2 1&quot; -f 3<br />
0: &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
3: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
1: &nbsp; &nbsp;3 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
4: &nbsp; &nbsp;4 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
1: &nbsp; &nbsp;4 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
6: &nbsp; &nbsp;6 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
0: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Miss<br />
2: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit<br />
1: &nbsp; &nbsp;0 &nbsp; 1 &nbsp; 2 &nbsp; &nbsp;Hit</div></div>
<p>Number of Page Frames = 3<br />
Total Number of References = 12<br />
Number of Hits = 5<br />
Number of Page Fault = 7<br />
HitRatio = 0.42</p>
<p>シュミレーションの結果、OPTIMALアルゴリズムのHit率が最も高く、これが最も置換効率がよいということになる。今回はインプットするサンプル数が少ないのでまともな結果を出すならばデータサンプルをもっと増やす必要があるのだろうけどこの辺で終わりにしておきます。</p>
<p>おわり。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/03/13/page_replacement_algo_simulation/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/03/13/page_replacement_algo_simulation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Scatter/Gather I/O(readv/writev)の実装</title>
		<link>http://yk55.com/blog/2010/01/31/readv_writev_implementation/</link>
		<comments>http://yk55.com/blog/2010/01/31/readv_writev_implementation/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 02:03:15 +0000</pubDate>
		<dc:creator>yoichi</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://yk55.com/blog/?p=86</guid>
		<description><![CDATA[readv、writevは複数バッファをまとめて読み書きするシステムコールです。 writevはiovec 構造体の配列に書き込みたいものを突っ込んでまとめてその複数バッファーを書き込み、readvは指定した個数分の複数バッファーをiovec 構造体の配列に格納します。例えばwritevによる複数バッファの書き込みはこんな感じです。 #include &#60;stdio.h&#62; #include &#60;unistd.h&#62; #include &#60;fcntl.h&#62; #include &#60;string.h&#62; #include &#60;sys/uio.h&#62; int &#160;main&#40; int argc, char** argv &#41; &#123; &#160; &#160; int fd = 0; &#160; &#160; ssize_t written; &#160; &#160; struct iovec iov&#91;3&#93;; &#160; &#160; char *buffer0, *buffer1, *buffer2; &#160; &#160; char *file = argv&#91;1&#93;; &#160; &#160; fd = open&#40; file, [...]]]></description>
			<content:encoded><![CDATA[<p>readv、writevは複数バッファをまとめて読み書きするシステムコールです。 writevはiovec 構造体の配列に書き込みたいものを突っ込んでまとめてその複数バッファーを書き込み、readvは指定した個数分の複数バッファーをiovec 構造体の配列に格納します。例えばwritevによる複数バッファの書き込みはこんな感じです。</p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;stdio.h&gt;</span><br />
<span style="color: #339933;">#include &lt;unistd.h&gt;</span><br />
<span style="color: #339933;">#include &lt;fcntl.h&gt; </span><br />
<span style="color: #339933;">#include &lt;string.h&gt;</span><br />
<span style="color: #339933;">#include &lt;sys/uio.h&gt;</span><br />
<span style="color: #993333;">int</span> <br />
&nbsp;main<span style="color: #009900;">&#40;</span> <span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span><span style="color: #339933;">**</span> argv <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> fd <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ssize_t written<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> iovec iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>buffer0<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>buffer1<span style="color: #339933;">,</span> <span style="color: #339933;">*</span>buffer2<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>file <span style="color: #339933;">=</span> argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span> file<span style="color: #339933;">,</span> &nbsp;O_RDWR<span style="color: #339933;">|</span>O_CREAT<span style="color: #339933;">|</span>O_EXCL<span style="color: #339933;">,</span> <span style="color: #208080;">0666</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> fd <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;cannot open file:%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> file<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; buffer0 <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;buffer0 string&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; buffer1 <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;buffer1 string&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; buffer2 <span style="color: #339933;">=</span> <span style="color: #ff0000;">&quot;buffer2 string&quot;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_base</span> <span style="color: #339933;">=</span> buffer0<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_len</span> <span style="color: #339933;">=</span> strlen<span style="color: #009900;">&#40;</span>buffer0<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_base</span> <span style="color: #339933;">=</span> buffer1<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_len</span> <span style="color: #339933;">=</span> strlen<span style="color: #009900;">&#40;</span>buffer1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_base</span> <span style="color: #339933;">=</span> buffer2<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; iov<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">iov_len</span> <span style="color: #339933;">=</span> strlen<span style="color: #009900;">&#40;</span>buffer2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; written <span style="color: #339933;">=</span> writev<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> iov<span style="color: #339933;">,</span> <span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; close<span style="color: #009900;">&#40;</span>fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p><span style="text-decoration: underline;">※iovec 構造体の定義 </span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;">/* Structure for scatter/gather I/O. &nbsp;*/</span><br />
<span style="color: #993333;">struct</span> iovec<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp;<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>iov_base<span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* Pointer to data. &nbsp;*/</span><br />
&nbsp; &nbsp;size_t iov_len<span style="color: #339933;">;</span> <span style="color: #808080; font-style: italic;">/* Length of data. &nbsp;*/</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
<p><a href="http://www.linux.or.jp/JM/html/LDP_man-pages/man2/readv.2.html">man</a>によると基本的にはこのシステムコールの特徴は次の2つです。</p>
<ol>
<li>1.  readv、writevともに複数のバッファにデータを読み込む点を除いてそれぞれread(2)、write(2)と全く同様の動作を行う。</li>
<li>2.  readvと writevともにatomic。writevによるデータ書き込み中に他のスレッド、プロセスのwrite による割り込みが入らない。readvも同様にファイルから連続するデータブロックが読み出すことを保証。 </li>
</ol>
<p>本当にこのシステムコールが上記のような実装になっているのか確かめるために実際にソースコードを覗いてみます。readv、writevでは内部で次のdo_readv_writev関数がコールされます。</p>
<p><span style="text-decoration: underline;">do_readv_writev @ linux-2.6.12.1/fs/read_write.c</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">static</span> ssize_t do_readv_writev<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> type<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> file <span style="color: #339933;">*</span>file<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">const</span> <span style="color: #993333;">struct</span> iovec __user <span style="color: #339933;">*</span> uvector<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">unsigned</span> <span style="color: #993333;">long</span> nr_segs<span style="color: #339933;">,</span> loff_t <span style="color: #339933;">*</span>pos<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #202020;">ret</span> <span style="color: #339933;">=</span> rw_verify_area<span style="color: #009900;">&#40;</span>type<span style="color: #339933;">,</span> file<span style="color: #339933;">,</span> pos<span style="color: #339933;">,</span> tot_len<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ret<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> out<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fnv <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>type <span style="color: #339933;">==</span> READ<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fn <span style="color: #339933;">=</span> file<span style="color: #339933;">-&gt;</span>f_op<span style="color: #339933;">-&gt;</span>read<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fnv <span style="color: #339933;">=</span> file<span style="color: #339933;">-&gt;</span>f_op<span style="color: #339933;">-&gt;</span>readv<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fn <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>io_fn_t<span style="color: #009900;">&#41;</span>file<span style="color: #339933;">-&gt;</span>f_op<span style="color: #339933;">-&gt;</span>write<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fnv <span style="color: #339933;">=</span> file<span style="color: #339933;">-&gt;</span>f_op<span style="color: #339933;">-&gt;</span>writev<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>fnv<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ret <span style="color: #339933;">=</span> fnv<span style="color: #009900;">&#40;</span>file<span style="color: #339933;">,</span> iov<span style="color: #339933;">,</span> nr_segs<span style="color: #339933;">,</span> pos<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> out<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/* Do it by hand, with file-ops */</span><br />
&nbsp; &nbsp; ret <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; vector <span style="color: #339933;">=</span> iov<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>nr_segs <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #993333;">void</span> __user <span style="color: #339933;">*</span> base<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; size_t len<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ssize_t nr<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; base <span style="color: #339933;">=</span> vector<span style="color: #339933;">-&gt;</span>iov_base<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; len <span style="color: #339933;">=</span> vector<span style="color: #339933;">-&gt;</span>iov_len<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; vector<span style="color: #339933;">++;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; nr_segs<span style="color: #339933;">--;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; nr <span style="color: #339933;">=</span> fn<span style="color: #009900;">&#40;</span>file<span style="color: #339933;">,</span> base<span style="color: #339933;">,</span> len<span style="color: #339933;">,</span> pos<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>nr <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>ret<span style="color: #009900;">&#41;</span> ret <span style="color: #339933;">=</span> nr<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ret <span style="color: #339933;">+=</span> nr<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>nr <span style="color: #339933;">!=</span> len<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; ...<br />
<span style="color: #009900;">&#125;</span></div></div>
<p>後半のwhileブロックを見るとたしかにreadv、writevのときそれぞれ内部でread、writeがループで繰り返されています。 想像を超えたシンプルさでした。次にatomicを保障している箇所ですがREADかWRITEのtypeチェックを行う前のrw_verify_areaがそれっぽい。ということでrw_verify_areaを覗いてみます。</p>
<p><span style="text-decoration: underline;">rw_verify_area @ linux-2.6.12.1/fs/read_write.c</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #993333;">int</span> rw_verify_area<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> read_write<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> file <span style="color: #339933;">*</span>file<span style="color: #339933;">,</span> loff_t <span style="color: #339933;">*</span>ppos<span style="color: #339933;">,</span> size_t count<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> inode <span style="color: #339933;">*</span>inode<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; loff_t pos<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>unlikely<span style="color: #009900;">&#40;</span>count <span style="color: #339933;">&gt;</span> file<span style="color: #339933;">-&gt;</span>f_maxcount<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> Einval<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; pos <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>ppos<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>unlikely<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>pos <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span>loff_t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span>pos <span style="color: #339933;">+</span> count<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">goto</span> Einval<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; inode <span style="color: #339933;">=</span> file<span style="color: #339933;">-&gt;</span>f_dentry<span style="color: #339933;">-&gt;</span>d_inode<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>inode<span style="color: #339933;">-&gt;</span>i_flock <span style="color: #339933;">&amp;&amp;</span> MANDATORY_LOCK<span style="color: #009900;">&#40;</span>inode<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> locks_mandatory_area<span style="color: #009900;">&#40;</span>read_write <span style="color: #339933;">==</span> READ <span style="color: #339933;">?</span> FLOCK_VERIFY_READ <span style="color: #339933;">:</span> FLOCK_VERIFY_WRITE<span style="color: #339933;">,</span> inode<span style="color: #339933;">,</span> file<span style="color: #339933;">,</span> pos<span style="color: #339933;">,</span> count<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span><br />
<br />
Einval<span style="color: #339933;">:</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span>EINVAL<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>ここではファイルの読み込み・書き込みエリアのバリデーションチェックとlocks_mandatory_areaで排他チェックを行っています。念のためlocks_mandatory_areaを覗いてみます。</p>
<p><span style="text-decoration: underline;">locks_mandatory_area @ linux-2.6.12.1/fs/locks.c</span></p>
<div class="codecolorer-container c mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;">/**<br />
&nbsp;* locks_mandatory_area - Check for a conflicting lock<br />
&nbsp;* @read_write: %FLOCK_VERIFY_WRITE for exclusive access, %FLOCK_VERIFY_READ<br />
&nbsp;* &nbsp; &nbsp; &nbsp;for shared<br />
&nbsp;* @inode: &nbsp; &nbsp; &nbsp;the file to check<br />
&nbsp;* @filp: &nbsp; &nbsp; &nbsp; how the file was opened (if it was)<br />
&nbsp;* @offset: &nbsp; &nbsp; start of area to check<br />
&nbsp;* @count: &nbsp; &nbsp; &nbsp;length of area to check<br />
&nbsp;*<br />
&nbsp;* Searches the inode's list of locks to find any POSIX locks which conflict.<br />
&nbsp;* This function is called from rw_verify_area() and<br />
&nbsp;* locks_verify_truncate().<br />
&nbsp;*/</span><br />
<span style="color: #993333;">int</span> locks_mandatory_area<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> read_write<span style="color: #339933;">,</span> <span style="color: #993333;">struct</span> inode <span style="color: #339933;">*</span>inode<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #993333;">struct</span> file <span style="color: #339933;">*</span>filp<span style="color: #339933;">,</span> loff_t offset<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;size_t count<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">struct</span> file_lock fl<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">int</span> error<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; locks_init_lock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>fl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_owner</span> <span style="color: #339933;">=</span> current<span style="color: #339933;">-&gt;</span>files<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_pid</span> <span style="color: #339933;">=</span> current<span style="color: #339933;">-&gt;</span>tgid<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_file</span> <span style="color: #339933;">=</span> filp<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_flags</span> <span style="color: #339933;">=</span> FL_POSIX <span style="color: #339933;">|</span> FL_ACCESS<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>filp <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>filp<span style="color: #339933;">-&gt;</span>f_flags <span style="color: #339933;">&amp;</span> O_NONBLOCK<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; fl.<span style="color: #202020;">fl_flags</span> <span style="color: #339933;">|=</span> FL_SLEEP<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_type</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>read_write <span style="color: #339933;">==</span> FLOCK_VERIFY_WRITE<span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> F_WRLCK <span style="color: #339933;">:</span> F_RDLCK<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_start</span> <span style="color: #339933;">=</span> offset<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; fl.<span style="color: #202020;">fl_end</span> <span style="color: #339933;">=</span> offset <span style="color: #339933;">+</span> count <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">;;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; error <span style="color: #339933;">=</span> __posix_lock_file<span style="color: #009900;">&#40;</span>inode<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>fl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>error <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span>EAGAIN<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>fl.<span style="color: #202020;">fl_flags</span> <span style="color: #339933;">&amp;</span> FL_SLEEP<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; error <span style="color: #339933;">=</span> wait_event_interruptible<span style="color: #009900;">&#40;</span>fl.<span style="color: #202020;">fl_wait</span><span style="color: #339933;">,</span> <span style="color: #339933;">!</span>fl.<span style="color: #202020;">fl_next</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>error<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">/*<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* If we've been sleeping someone might have<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* changed the permissions behind our back.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>inode<span style="color: #339933;">-&gt;</span>i_mode <span style="color: #339933;">&amp;</span> <span style="color: #009900;">&#40;</span>S_ISGID <span style="color: #339933;">|</span> S_IXGRP<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> S_ISGID<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; locks_delete_block<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>fl<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> error<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p><span style="text-decoration: underline;">※ kernelソースコード<a href="http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.12.1.tar.gz">linux-2.6.12.1</a></span> </p>
<p>以上、簡単ではありますがreadv、writevの実装でした。 このシステムコールはこれまで何度か業務で利用していておなじみな物のではありましたが特に内部の実装を気にすることなく使ってました。実際に見てみると単純な複数バッファ分のread, writeの繰り返しではありますがその処理間に排他制御がしっかりされているのでパフォーマンスはさておき安心して使えると思います。その辺の自分で実装するのは面倒ですから。</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http://yk55.com/blog/2010/01/31/readv_writev_implementation/&amp;layout=button_count&amp;show_faces=1&amp;width=450&amp;action=like&amp;colorscheme=light&amp;font=arial" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:25px"></iframe>]]></content:encoded>
			<wfw:commentRss>http://yk55.com/blog/2010/01/31/readv_writev_implementation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	<!-- google_ad_section_end --><!-- google_ad_section_start(weight=ignore) --></channel>
</rss>

