<?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/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"
>

<channel>
	<title>EMSTONE Bebop &#187; 카스탈리엔</title>
	<atom:link href="http://bebop.emstone.com/tags/%ec%b9%b4%ec%8a%a4%ed%83%88%eb%a6%ac%ec%97%94/feed/" rel="self" type="application/rss+xml" />
	<link>http://bebop.emstone.com</link>
	<description>엠스톤 개발팀 블로그</description>
	<lastBuildDate>Sun, 29 Jan 2012 05:25:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
		<item>
		<title>모니터 없이 X 서버 실행 후 나중에 모니터 연결해도 화면이 안보인다면</title>
		<link>http://lethean.pe.kr/2012/01/29/setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25eb%25aa%25a8%25eb%258b%2588%25ed%2584%25b0-%25ec%2597%2586%25ec%259d%25b4-x-%25ec%2584%259c%25eb%25b2%2584-%25ec%258b%25a4%25ed%2596%2589-%25ed%259b%2584-%25eb%2582%2598%25ec%25a4%2591%25ec%2597%2590-%25eb%25aa%25a8%25eb%258b%2588%25ed%2584%25b0-%25ec%2597%25b0%25ea%25b2%25b0%25ed%2595%25b4%25eb%258f%2584-%25ed%2599%2594</link>
		<comments>http://lethean.pe.kr/2012/01/29/setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors#comments</comments>
		<pubDate>Sun, 29 Jan 2012 05:25:29 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Udev]]></category>
		<category><![CDATA[Xorg]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1864</guid>
		<description><![CDATA[제목이 조금 길지만, 이 글의 내용은 제목 그대로입니다. (참고로, 이 글은 최근 인텔 그래픽 칩셋을 대상으로 작성되었습니다. 즉, 다른 그래픽 칩셋 드라이버는 어떻게 동작하는지 확인을 안 해 보았다는 의미입니다) 요즘 X 서버는 연결된 모니터가 없고, /etc/X11/xorg.conf 파일에 수직/수평 주파수가 정의되어 &#8230; <a href="http://lethean.pe.kr/2012/01/29/setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2012/01/29/setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>제목이 조금 길지만, 이 글의 내용은 제목 그대로입니다. (참고로, 이 글은 최근 인텔 그래픽 칩셋을 대상으로 작성되었습니다. 즉, 다른 그래픽 칩셋 드라이버는 어떻게 동작하는지 확인을 안 해 보았다는 의미입니다)</p>
<p>요즘 X 서버는 연결된 모니터가 없고, <code>/etc/X11/xorg.conf</code> 파일에 수직/수평 주파수가 정의되어 있지 않다고 하더라도 일단 정상적으로 실행됩니다. 다만, 초기 해상도가 320&#215;200 처럼 매우 작을 수 있습니다. 그런데 나중에 필요에 의해 모니터를 연결했는데 화면이 보이지 않는 경우가 발생합니다. 이 경우, 네트웍으로 접속해서 다음 명령어를 실행합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">DISPLAY</span>=:<span style="color: #000000;">0.0</span>
$ xrandr <span style="color: #660033;">--auto</span></pre></div></div>

<p>그러면 X 서버가 알아서 연결되어 있는 모니터를 출력으로 재설정하고 가장 선호하는(preferred) 해상도와 주파수를 선택합니다. 그런데 이를 자동으로 동작하게 하려면 udev 데몬의 도움을 받아야 합니다. 그래서 <code>/etc/udev/rules.d</code> 디렉토리에 확장자가 <code>'.rules'</code>인 파일을 생성하고 다음과 같이 내용을 채웁니다.</p>

<div class="wp_syntax"><div class="code"><pre class="" style="font-family:monospace;">ACTION==&quot;change&quot;, SUBSYSTEM==&quot;drm&quot;, KERNEL==&quot;card*&quot;, RUN+=&quot;/usr/bin/auto-xrandr.sh&quot;</pre></div></div>

<p>그리고 <code>/usr/bin/auto-xrandr.sh</code> 파일을 아래와 같이 작성한뒤 실행권한을 줍니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$DISPLAY</span>&quot;</span> = <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">DISPLAY</span>=:<span style="color: #000000;">0.0</span>
xrandr <span style="color: #660033;">--auto</span>
xrandr <span style="color: #660033;">--dpi</span> <span style="color: #000000;">96</span></pre></div></div>

<p>그러면 이제부터 모니터 연결시 자동으로 연결을 재설정하게 됩니다.</p>
<p>그런데, 만일 네트웍으로 접속했거나, udev 데몬에 의해 실행되는 경우 X 서버 인증이 안된 계정이라며 <code>xrandr</code> 명령이 실행이 거부됩니다. 이를 제대로 처리하려면 복잡한 인증 과정이 필요한데, 이를 쉽게 처리하려면 그냥 X 서버 시작할때 자동으로 실행되는 초기화 스크립트에 <code>'xhost +'</code> 명령어를 주면 인증을 무시하게 됩니다. 물론 보안상 좋은 방법은 아니지만, 폐쇠된 환경이라면 별로 문제가 없을 겁니다.</p>
<p>각각의 명령어에 대해 더 궁금하신 분은 관련 명령어 매뉴얼 페이지를 확인해 보시기 바랍니다.</p>
<p>참고로 조금만 더 설명하면, 노트북 외부 모니터 단자에 빔 프로젝트나 외부 모니터를 연결했을 경우도 xrandr 명령을 직접 사용하거나 지금까지 설명한 방법을 조금 다르게 응용할 수 있습니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2012/01/29/setup-new-connected-monitors-automatically-after-starting-x-server-without-connected-monitors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>ClutterGst 메모리 누수 디버깅</title>
		<link>http://lethean.pe.kr/2011/09/28/clutter-gst-memory-leak-debugging/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=clutter-gst-memory-leak-debugging&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cluttergst-%25eb%25a9%2594%25eb%25aa%25a8%25eb%25a6%25ac-%25eb%2588%2584%25ec%2588%2598-%25eb%2594%2594%25eb%25b2%2584%25ea%25b9%2585</link>
		<comments>http://lethean.pe.kr/2011/09/28/clutter-gst-memory-leak-debugging/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=clutter-gst-memory-leak-debugging#comments</comments>
		<pubDate>Wed, 28 Sep 2011 10:20:29 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Clutter]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1809</guid>
		<description><![CDATA[최근 클러터를 이용한 프로그램을 개발하면서 메모리 누수 현상을 발견했습니다. 코드를 하나 하나 막아가면서 테스트를 한 결과 ClutterGstVideoSink 객체를 사용하지 않으면 메모리 누수가 발생하지 않았습니다. 하지만, 아무리 소스를 분석해도 원인을 찾아낼 수 없었고, 잘못된 부분도 없는 것 같았습니다. 물론 구글링을 해도, &#8230; <a href="http://lethean.pe.kr/2011/09/28/clutter-gst-memory-leak-debugging/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/09/28/clutter-gst-memory-leak-debugging/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=clutter-gst-memory-leak-debugging">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>최근 <a href="http://lethean.pe.kr/2011/09/15/note-about-using-clutter/">클러터를 이용한 프로그램을 개발</a>하면서 메모리 누수 현상을 발견했습니다. 코드를 하나 하나 막아가면서 테스트를 한 결과 <a href="http://developer.gnome.org/clutter-gst/1.3/ClutterGstVideoSink.html"><code>ClutterGstVideoSink</code></a> 객체를 사용하지 않으면 메모리 누수가 발생하지 않았습니다. 하지만, 아무리 소스를 분석해도 원인을 찾아낼 수 없었고, 잘못된 부분도 없는 것 같았습니다. 물론 구글링을 해도, 검색 실력이 미천한지, 답을 찾을 수 없었습니다.</p>
<p>그래서 결국 예전에 소개한 적 있는 <a href="http://lethean.pe.kr/2009/06/18/debugging-memory-leaks-with-tcmalloc-google-perftools/">구글 성능 도구(google-perftools)를 이용해 디버깅</a>을 했습니다. 그런데 문제는, <a href="http://www.archlinux.org/">아치 리눅스(Arch Linux)</a> x86_64 환경으로 개발 환경을 바꾸면서 메모리 프로파일 기능이 제대로 동작하지 않는다는 사실인데, 특히 메모리 누수 발생 지점을 정확하게 알기 위해서 필요한 함수 호출 백트레이스(backtrace) 정보가 추출되지 않는 게 가장 큰 문제였습니다. 이 문제를 해결하기 위한 과정을 기록으로 남겨봅니다.</p>
<p><strong>구글 성능 도구 설치</strong></p>
<p>아치 리눅스(Arch Linux) x86_64 환경에서 구글 성능 도구(google-perftools)가 정확한 메모리 프로파일 결과를 얻으려면 <a href="http://www.nongnu.org/libunwind/">libunwind</a> 라이브러리를 설치해야 하는데, 아치리눅스 <a href="https://wiki.archlinux.org/index.php/AUR">AUR</a> 패키지를 <a href="https://wiki.archlinux.org/index.php/Yaourt">yaourt</a>를 이용해 다음과 같이 쉽게 설치했습니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ yaourt <span style="color: #660033;">-S</span> libunwind</pre></div></div>

<p>그리고 다음과 같이 구글 성능 도구를 빌드하고 설치합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #7a0874; font-weight: bold;">cd</span> google-perftools
$ .<span style="color: #000000; font-weight: bold;">/</span>configure <span style="color: #660033;">--prefix</span>=<span style="color: #000000; font-weight: bold;">/</span>usr <span style="color: #660033;">--enable-frame-pointers</span>
$ <span style="color: #c20cb9; font-weight: bold;">make</span>
$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">make</span> <span style="color: #c20cb9; font-weight: bold;">install</span></pre></div></div>

<p><strong>라이브러리 패키지 재생성 및 재설치</strong></p>
<p>정확한 함수 호출 백트레이스(backtrace) 정보를 얻기 위해 프로그램에 사용되는 모든 라이브러리를 다시 컴파일해 패키지를 다시 설치해야 하는데, 그 과정은 다음과 같습니다. (<a href="https://wiki.archlinux.org/index.php/Debug_-_Getting_Traces">관련 위키 페이지</a> 참고)</p>
<p>먼저 아치 리눅스 빌드 시스템(ABS) 정보를 동기화합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> abs</pre></div></div>

<p>그러면 <code>/var/abs</code> 디렉토리 밑에 모든 공식 패키지의 빌드 정보가 다운로드됩니다.</p>
<p>라이브러리의 패키지 빌드 옵션을 수정하기 위해, <code>/etc/makepkg.conf</code> 파일에서 아래 부분을 찾아 디버그 심볼(<code>-g</code>)과 프레임 포인터 포함(<code>-fno-omit-frame-pointer</code>) 컴파일 옵션을 추가하고 빌드 옵션에서 <code>strip</code>을 제외합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #007800;">CFLAGS</span>=<span style="color: #ff0000;">&quot;-g -fno-omit-frame-pointer -march=x86-64 -mtune=generic -O2 -pipe&quot;</span>
<span style="color: #007800;">CXXFLAGS</span>=<span style="color: #ff0000;">&quot;-g -fno-omit-frame-pointer -march=x86-64 -mtune=generic -O2 -pipe&quot;</span>
<span style="color: #007800;">OPTIONS</span>=<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">!</span><span style="color: #c20cb9; font-weight: bold;">strip</span> docs libtool emptydirs zipman purge<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p><code>/var/abs/local</code> 디렉토리로 이동해서(없으면 새로 생성) 다음과 같이 사용되는 프로그램에 사용되는 모든 라이브러리 패키지를 다시 생성하고 설치합니다. 예를 들어 클러터 라이브러리는 다음과 같습니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #007800;">src</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">find</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>abs <span style="color: #660033;">-name</span> clutter <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #660033;">-v</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>abs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">local</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
$ <span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-r</span> <span style="color: #007800;">$src</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>abs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">local</span>
$ <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>abs<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>clutter
$ makepkg <span style="color: #660033;">-f</span>
$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> pacman <span style="color: #660033;">-U</span> <span style="color: #000000; font-weight: bold;">*</span>.pkg.tar.xz</pre></div></div>

<p>위와 같은 방식으로 clutter, cogl, glib2, glibc 패키지를 다시 만들고 설치합니다.</p>
<p><strong>메모리 프로파일링</strong></p>
<p>이제 다음 명령으로 디버깅할 프로그램(<code>eview-demo</code>)을 실행합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #007800;">G_SLICE</span>=always-malloc \
  <span style="color: #007800;">HEAPPROFILE</span>=<span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile \
  <span style="color: #007800;">HEAP_PROFILE_ALLOCATION_INTERVAL</span>=<span style="color: #000000;">10737418240</span> \
  <span style="color: #007800;">LD_PRELOAD</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>libtcmalloc.so \
  .<span style="color: #000000; font-weight: bold;">/</span>eview-demo
Starting tracking the heap
Dumping heap profile to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0001.heap <span style="color: #7a0874; font-weight: bold;">&#40;</span>...<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Dumping heap profile to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0002.heap <span style="color: #7a0874; font-weight: bold;">&#40;</span>...<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Dumping heap profile to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0003.heap <span style="color: #7a0874; font-weight: bold;">&#40;</span>...<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Dumping heap profile to <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0004.heap <span style="color: #7a0874; font-weight: bold;">&#40;</span>...<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>정상적으로 구글 성능 도구의 메모리 프로파일러가 동작하면 위와 같은 메시지가 출력됩니다. 이제 적당한 시점에서 프로그램을 멈추고, 다음과 같이 프로파일링 데이터를 분석합니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ pprof \
    <span style="color: #660033;">--pdf</span> \
    <span style="color: #660033;">--lines</span> \
    <span style="color: #660033;">--base</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0001.heap \
    .<span style="color: #000000; font-weight: bold;">/</span>eview-demo \
    <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>profile.0004.heap \
    <span style="color: #000000; font-weight: bold;">&gt;</span> profile-<span style="color: #000000;">1</span>.pdf</pre></div></div>

<p>이렇게 생성된 그래프는 다음과 같습니다. (<a href="http://lethean.pe.kr/wp-content/uploads/2011/09/clutter-1.6-memory-leak-profile.pdf">PDF </a>형식도 있습니다)</p>
<p><a href="http://lethean.pe.kr/wp-content/uploads/2011/09/clutter-1.6-memory-leak-profile.jpg" rel="lightbox[1809]"><img class="aligncenter size-large wp-image-1810" title="clutter-1.6-memory-leak-profile" src="http://lethean.pe.kr/wp-content/uploads/2011/09/clutter-1.6-memory-leak-profile-1024x884.jpg" alt="" width="584" height="504" /></a></p>
<p>이 그래프를 분석해서 관련 코드를 분석해 보니, 결정적으로 두 군데에 문제가 있습니다. 첫번째는 <code>cogl_pipeline_fragend_arbfp_start()</code> 함수 내부에서 생성한 <code>arbfp_program_state</code> 객체를 해제하는 곳이 없다는 점이고, 두번째는 <code>cogl_pipeline_get_layers()</code> 함수에서 생성한 <code>deprecated_get_layers_list</code> 리스트를 해제하는 곳이 없다는 점입니다. 그런데 최근 클러터 1.8 버전 소스를 보면 두번째 문제는 해결이 된 것 같은데, 첫번째 문제가 있는 곳은 코드 수정이 많이 되어 해결 여부를 알 수가 없습니다.</p>
<p>그래서 결론은, 며칠 전에 릴리스된 클러터 1.8 안정 버전이 아치 리눅스 패키지로 올라오면 다시 메모리 누수 여부를 확인해볼 예정입니다. (GNOME 3 핵심 라이브러리를 직접 컴파일해서 사용하는게 귀찮기도 하고 두렵기도 해서입니다&#8230; :)</p>
<p><strong>[UPDATE 2011-10-04]</strong> 클러터 1.8 버전에서 확인해 보니 메모리 누수 문제가 해결된 것 같습니다. 역시, 미루기를 잘 했습니다. ;)</p>
<p><strong>[UPDATE 2011-10-05]</strong> 다시 확인해 보니, 이제는 다른 부분에서 메모리 누수가 발생합니다. 그래서 이번에는 당당히(?) 버그 리포팅(<a href="https://bugzilla.gnome.org/show_bug.cgi?id=660985">Bug 660985</a>, <a href="https://bugzilla.gnome.org/show_bug.cgi?id=660986">Bug 660986</a>) 했습니다.</p>
<p><strong>[UPDATE 2011-10-10]</strong> CPU 사용량이 가장 많은 함수를 프로파일링하려면 다음과 같이 실행하면 됩니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #007800;">CPUPROFILE</span>=.<span style="color: #000000; font-weight: bold;">/</span>cpu.prof \
  <span style="color: #007800;">LD_PRELOAD</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>libtcmalloc_and_profiler.so \
  .<span style="color: #000000; font-weight: bold;">/</span>eview-demo</pre></div></div>

<p>정상적으로 종료한뒤 다음과 같이 CPU 사용량을 함수별로 프로파일한 그래프를 얻을 수 있습니다.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ pprof \
    <span style="color: #660033;">--pdf</span> \
    <span style="color: #660033;">--lines</span> \
    .<span style="color: #000000; font-weight: bold;">/</span>eview-demo \
    .<span style="color: #000000; font-weight: bold;">/</span>cpu.prof
    <span style="color: #000000; font-weight: bold;">&gt;</span> profile-<span style="color: #000000;">1</span>.pdf</pre></div></div>

<p><strong>[UPDATE 2012-02-04]</strong> 최신 아치 리눅스에 포함되어 있는 <a href="http://code.google.com/p/gperftools/issues/detail?id=396">glibc 2.15 버전의 버그</a> 때문에 프로파일링이 제대로 동작하지 않을 경우 <del datetime="2012-02-05T23:55:49+00:00"><a href="http://permalink.gmane.org/gmane.comp.lib.glibc.alpha/17093">sscanf 관련 패치</a>를 적용해 glibc 패키지를 다시 빌드하고 설치해야 합니다.</del> glibc 2.15-5 버전으로 업그레이드하면 됩니다. <a href="https://bugs.archlinux.org/task/28246">버그 리포팅</a>이 바로 반영되어 버렸습니다. :)</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/09/28/clutter-gst-memory-leak-debugging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>클러터(Clutter) 사용기</title>
		<link>http://lethean.pe.kr/2011/09/15/note-about-using-clutter/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=note-about-using-clutter&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25ed%2581%25b4%25eb%259f%25ac%25ed%2584%25b0clutter-%25ec%2582%25ac%25ec%259a%25a9%25ea%25b8%25b0</link>
		<comments>http://lethean.pe.kr/2011/09/15/note-about-using-clutter/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=note-about-using-clutter#comments</comments>
		<pubDate>Thu, 15 Sep 2011 09:05:39 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Clutter]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1774</guid>
		<description><![CDATA[클러터(Clutter) 라이브러리를 이용하면서 부딪친 대부분의 문제는 성능과 관련된 것입니다. 클러터 라이브러리 자체가 느리다는 얘기가 아니라, 주로 개발하는 분야에서 요구되는 16채널 이상 다채널 라이브 / 녹화 동영상 재생을 구현할 때, 고사양 장비는 문제가 되지 않지만 저사양 임베디드 보드에서는 성능 저하가 발생하기 &#8230; <a href="http://lethean.pe.kr/2011/09/15/note-about-using-clutter/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/09/15/note-about-using-clutter/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=note-about-using-clutter">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.clutter-project.org/">클러터(Clutter)</a> 라이브러리를 이용하면서 부딪친 대부분의 문제는 성능과 관련된 것입니다. 클러터 라이브러리 자체가 느리다는 얘기가 아니라, 주로 개발하는 분야에서 요구되는 16채널 이상 다채널 라이브 / 녹화 동영상 재생을 구현할 때, 고사양 장비는 문제가 되지 않지만 저사양 임베디드 보드에서는 성능 저하가 발생하기 때문입니다. 하지만, 효율적인 2D 그래픽을 위한 3D 그래픽 라이브러리로서 클러터는 아직까지 만족스럽습니다. OpenGL 기반 라이브러리는 기존 2D 그래픽 라이브러리와 여러가지 기본 개념이 달라서, 저처럼 이쪽 세상에 입문한지 얼마 안되는 개발자는 많은 시행 착오를 겪을 수 밖에 없는데,  이미 사용해 본  <a href="http://www.gtk.org/">GTK+</a> / <a href="http://developer.gnome.org/gobject/stable/">GObject</a> 방식에 익숙한 점도 유리하게 작용했지만, 2D 그래픽 + 효과를 위한 약간의 3차원 API 조합은 복잡하고 어려운(&#8230;) 3D 라이브러리를 직접 사용하는 것보다 훨씬 수월했습니다.</p>
<p>아무튼 그래서, 지금까지 겪은 경험 중 몇 가지를 정리해 보았습니다. 당연하지만, 아직 OpenGL에 대한 이해가 부족해 틀린 내용이 있을 수도 있으니, 감안해 주시기 바랍니다.</p>
<p><span class="Apple-style-span" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">1.<br />
</span>클러터 라이브러리는 계속 버전업 되는데 예전에 작성된 튜토리얼이나 예제는 갱신되지 않아 잘못되거나 사용을 권장하지 않는(deprecated) API를 사용하는 경우가 많이 있습니다. 가능한 클러터 개발자들이 라이브러리와 함께 직접 업데이트하는 <a href="http://docs.clutter-project.org/docs/clutter-cookbook/1.0/">클러터 해설서(The Clutter Cookbook)</a>를 참고하는게 가장 정확했습니다.</p>
<p>2.<br />
OpenGL 기반 클러터 라이브러리 동작 방식은 일반적인 2D GUI 프로그래밍과 달리 화면, 즉 스테이지(stage)에 조그만 변화라도 있으면 그때마다 스테이지를 다시 그립니다. 즉, 클러터의 기본 단위인 액터(actor) 하나가 다시 그려져야 하면 액터가 속한 스테이지의 모든 액터를 다시 그립니다. 그리고 이로 인해 스테이지에 보이는 모든 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>paint()</code></a> 함수가 매번 호출되기 때문에 이 함수를 최적화하는 게 매우 중요합니다.</p>
<p>3.<br />
내부적으로 캐싱(caching)이 이용되긴 하지만, 한 액터의 좌표(크기 + 위치)가 변경되면 스테이지의 모든 액터의 크기를 다시 계산하기 위해 모든 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>allocate()</code></a> 함수가 호출됩니다. 예를 들어 텍스트(text) 액터 구현을 보면, 문자열이나 폰트, 크기 등이 변경되었을때 텍스트 액터를 포함하는 부모 컨테이너 액터가 변경된 크기를 감지하고 자신의 크기를 조정할 수 있도록 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-queue-relayout"><code>clutter_actor_queue_relayout()</code></a> 함수가 호출됩니다. 그리고, 이 함수가 호출되면 결국 스테이지 단계까지 호출이 계속된 다음, 다시 스테이지에 속한 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>allocate()</code></a> 함수가 재귀적으로 호출됩니다. 따라서 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>allocate()</code></a> 함수 역시 내부적으로 최적화되는 것이 좋습니다. 참고로 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-queue-relayout"><code>clutter_actor_queue_relayout()</code></a> 함수가 호출되면 자동으로 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-queue-redraw"><code>clutter_actor_queue_redraw()</code></a> 함수가 호출되어 스테이지의 모든 객체를 다시 그립니다.</p>
<p>4.<br />
클러터에서 기본으로 제공하는 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterBox.html">박스(ClutterBox)</a>, <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterGroup.html">그룹(CutterGroup)</a> 등과 같은 컨테이너 액터를 사용하지 않고 직접 컨테이너 액터를 구현해 자식 액터를 배치하고 싶거나 혹은 기존 컨테이너 액터를 상속받아 새 컨테이너 액터를 구현할 때가 있습니다. 그런데, 컨테이너 액터 좌표(크기 + 위치) 변경에 따라 자식 액터의 좌표를 자동으로 변경할 필요가 있으면 대개 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActor-allocation-changed"><code>"allocation-changed"</code></a> 시그널을 이용해 감지한 뒤 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-set-size"><code>clutter_actor_set_size()</code></a>, <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-set-position"><code>clutter_actor_set_position()</code></a> 함수 등을 이용해 자식 액터의 좌표를 조정하거나, <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterConstraint.html">제약(ClutterConstraints)</a> 기능을 이용하는데, 위에서 설명한 것처럼 좌표가 변환되면 자동으로 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-queue-relayout"><code>clutter_actor_queue_relayout()</code></a> 함수가 호출되면서 <em>&#8220;The actor &#8216;xxx&#8217; is currenty inside an allocation cycle; calling clutter_actor_queue_relayout() is not recommended&#8221;</em> 디버그 경고 메시지가 계속 출력됩니다. 메시지니를 무시할 수도 있지만, 문제는 한 액터의 좌표 변경으로 인해 매번 화면 전체가 다시 좌표를 다시 계산하기 때문에 결국 모든 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>allocate()</code></a> 함수가 계속 호출되면서 CPU 점유율이 매우 높아진다는 점입니다. 여기에 좌표를 이용한 애니메이션까지 사용하면 CPU 점유율은 상상을 초월할 정도로 올라갑니다. 이 문제를 해결하려면 반드시 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>allocate()</code></a> 함수에서 자식 액터의 좌표를 지정할때 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#clutter-actor-allocate"><code>clutter_actor_allocate*()</code></a> 종류의 함수만 이용해야 하고, 어쩔 수 없을 경우 <a href="http://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add-full"><code>g_idle_add_full()</code></a> 함수를 이용해 자식 액터 좌표 지정 루틴의 실행을 뒤로 조금 미룬 뒤에 좌표 중복 검사 등을 통해 가능한 화면 재구성(relayout) 작업이 덜 일어나게 해야 합니다. 메인루프 우선 순위는 <a href="http://docs.clutter-project.org/docs/clutter/stable/clutter-Events.html#CLUTTER-PRIORITY-EVENTS:CAPS"><code>CLUTTER_PRIORITY_EVENTS</code></a> 값을 사용하는 게 좋습니다.</p>
<p>5.<br />
<a href="http://docs.clutter-project.org/docs/clutter/stable/running-clutter.html">클러터 실행에 영향을 주는 환경 변수</a>를 이용하면 성능 조율 및 디버깅에 상당한 도움을 받을 수 있습니다. 예를 들어 <a href="http://wiki.clutter-project.org/wiki/ClutterProfiling#Are_you_drawing_actors_unnecessarily.3F"><code>COGL_DEBUG=rectangles</code></a> 이나 <a href="http://docs.clutter-project.org/docs/clutter/stable/running-clutter.html"><code>CLUTTER_DEBUG="paint layout"</code></a> 등은 도움이 많이 됩니다.</p>
<p>6.<br />
<a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterText.html">텍스트(ClutterText)</a> 액터의 위치가 정수가 아니라면, 즉 소수점 이하 값이 존재하는 실수일 경우  글꼴 선이 흐려지거나 뭉개지는 현상이 발생합니다. 텍스트 액터 뿐 아니라 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterRectangle.html">사각형(ClutterRectangle)</a> 액터처럼 그림이 아니라 직접 그려지는 액터들도 비슷한 현상이 발생합니다. 비단 액터의 위치가 정수일 지라도 이를 포함하는 상위 컨테이너 액터의 위치가 소수점 이하를 포함하는 실수일 경우, 즉 화면(stage)상 절대 좌표가 정수가 아닐 경우 이 현상이 발생합니다. 따라서 액터의 좌표를 계산해서 지정할 경우 반드시 <a href="http://www.manpagez.com/man/3/floor/"><code>floor()</code></a> / <a href="http://www.manpagez.com/man/3/ceil/"><code>ceil()</code></a> 등의 함수를 이용해 소수점 아래 값을 없애주는 것이 좋습니다.</p>
<p>7.<br />
액터에 배경 또는 테두리를 장식하고 싶을때 보통 떠오르는 구현 방법은 두 가지가 있습니다. 첫번째는 컨테이너 액터를 이용해 사각형 액터를 맨 아래 두고 대상 액터를 위에 두는 방법을 이용한 것이고, 두 번째는 이런 작업을 하는 커스텀 액터를 직접 구현하는 것입니다. 그런데 이보다 더 좋은 방법은, <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterEffect.html">효과(ClutterEffect)</a> 객체를 구현해서 사용하는 것입니다. 효과 객체가 액터 객체에 추가되면 효과의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterEffect.html#ClutterEffectClass"><code>pre_paint()</code> / <code>post_paint()</code></a> 함수가 액터의 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterActor.html#ClutterActorClass"><code>paint()</code></a> 함수 호출 전후에 자동으로 호출되므로, 동일한 디스플레이 루틴을 여러 객체에 쉽게 적용할 수 있습니다. 클러터에서 이미 기본으로 제공하는 <a href="http://docs.clutter-project.org/docs/clutter/stable/ch07.html">고급 효과</a>를 사용해도 되지만, 예를 들어 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterEffect.html">텍스트에 그림자를 넣어주는 예제</a>를 그대로 이용해 <a href="http://docs.clutter-project.org/docs/clutter-cookbook/1.0/effects-basic.html">테두리 효과</a>처럼 구현할 수도 있는 셈입니다.</p>
<p>8.<br />
클러터에서 직접 그리기 위해 사용하는 OpenGL 랩퍼 API <a href="http://docs.clutter-project.org/docs/cogl/stable/">Cogl</a> 함수를 사용할때 <a href="http://docs.clutter-project.org/docs/cogl/stable/cogl-Path-Primitives.html">경로(Path)</a> 등을 사용하지 않고 가능하다면 <a href="http://docs.clutter-project.org/docs/cogl/stable/cogl-Primitives.html">기본(Primitives) 함수</a>만 사용해서 구현하는게 성능이 좋습니다.</p>
<p>9.<br />
<a href="http://docs.clutter-project.org/docs/cogl/stable/">Cogl</a> 함수를 이용해 직접 그리는 방식과 모든 것을 그림 이미지로 처리하는 <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterTexture.html">텍스쳐(ClutterTexture)</a>를 이용하는 방식의 장단점을 아직 잘 모르겠습니다. 다만, 텍스쳐는 내부적으로 사용하는 메모리량이 더 많은 것이 분명하고, 현재 개발 중인 시스템에서는 수많은 채널의 비디오 동시 재생을 위해 어차피 많은 텍스쳐가 사용되기 때문에 가능한 텍스쳐 사용을 자제했습니다. 하지만 영역 크기에 따라 크기가 달라지는 GUI 부분을 구현할때는 이미지 기반 텍스쳐보다 일종의 벡터 그래픽이라고 할 수 있는 Cogl 함수를 이용해 직접 그리면 훨씬 깔끔한 GUI를 얻을 수 있는 것도 사실인 것 같습니다.</p>
<p>10.<br />
비디오 재생을 위해 <a href="http://developer.gnome.org/clutter-gst/1.3/ClutterGstVideoSink.html">비디오싱크(ClutterGstVideoSink)</a> 객체를 사용할 때 <a href="http://developer.gnome.org/clutter-gst/1.3/ClutterGstVideoSink.html#ClutterGstVideoSink--update-priority">갱신 우선순위 (<code>update-priority</code>)</a> 속성을 <a href="http://docs.clutter-project.org/docs/clutter/stable/clutter-Events.html#CLUTTER-PRIORITY-REDRAW:CAPS"><code>CLUTTER_PRIORITY_REDRAW</code></a> 값으로 낮추면 마우스 이벤트 반응 속도를 개선할 수 있습니다.</p>
<p>11.<br />
정말로 빈번한 애니메이션을 구현할때는, 사용하기 쉽지만, 내부적으로 수많은 객체가 생성되고 소멸되는 <a href="http://docs.clutter-project.org/docs/clutter/stable/clutter-Implicit-Animations.html#clutter-actor-animate"><code>clutter_actor_animate()</code></a> 대신, 번거롭지만, <a href="http://docs.clutter-project.org/docs/clutter/stable/ClutterTimeline.html">타임라인(ClutterTimeline)</a> 등을 이용해 구현하는게 CPU / 메모리 사용량을 줄이는데 도움이 됩니다.</p>
<p>12.<br />
AMD(ATI) 그래픽 카드를 장착한 리눅스 상에서 클러터를 실행할때 Catalyst 상용 X 드라이버와 최신 오픈소스 X 드라이버와 성능 차이가 거의 없어진 것 같습니다. 물론 NVidia는 상용 드라이버 성능이 월등이 더 좋고, 인텔 칩셋은 오픈 소스 드라이버만 있고 성능도 좋습니다.</p>
<p>이해에 도움이 될까 싶어, 아직 프로토타입이고 많은 기능이 빠져있지만, 현재 개발 중인 시스템의 동작 화면을 녹화한 영상을 보여드립니다. 녹화에 사용한 프로그램은 <a href="http://recordmydesktop.sourceforge.net/about.php">gtk-recordMyDesktop</a>입니다.</p>
<p><iframe src="http://www.youtube.com/embed/1w0fjm0MYo8?hl=en&amp;fs=1" frameborder="0" width="425" height="349"></iframe></p>
<p>GUI 프로그래밍을 할 때마다 느끼는 점은 구현하기 위한 기술도 중요하지만, 결국 사용자를 배려하면서도 아름다움을 잃지 않는 참신한 아이디어 기반의 디자인이 더 중요하다는 점입니다. 물론 그렇기 때문에 디자이너라는 직업이 따로 있는 것이겠지만, 좋은 프로그램과 삶의 다양한 모습을 많이 보고, 많이 경험하고, 많이 참고해야 하는 지적 즐거움을 언제부터인가 프로그래머들은 남의 영역이라 멀리한 채 무미건조한 기술에만 전념하고 있는 건 아닌지 모르겠습니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/09/15/note-about-using-clutter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>GNOME 개발 설명서 / 동영상</title>
		<link>http://lethean.pe.kr/2011/07/15/gnome-development-screencasts-and-tutorials/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gnome-development-screencasts-and-tutorials&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gnome-%25ea%25b0%259c%25eb%25b0%259c-%25ec%2584%25a4%25eb%25aa%2585%25ec%2584%259c-%25eb%258f%2599%25ec%2598%2581%25ec%2583%2581</link>
		<comments>http://lethean.pe.kr/2011/07/15/gnome-development-screencasts-and-tutorials/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=gnome-development-screencasts-and-tutorials#comments</comments>
		<pubDate>Fri, 15 Jul 2011 10:39:08 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Clutter]]></category>
		<category><![CDATA[GNOME]]></category>
		<category><![CDATA[GStreamer]]></category>
		<category><![CDATA[GTK+]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1741</guid>
		<description><![CDATA[오랜만에 GNOME 개발자 센터를 들어갔더니, 모양 뿐 아니라 내용도 확 바뀌어 있습니다. 예전에도 있었는데 제가 몰랐던 건지도 모르지만, 10분짜리 설명서(10-minute tutorials)가 가장 먼저 눈에 띄었습니다. (접속한 페이지의 실제 이름은 GNOME 개발자 플랫폼 데모입니다) 이미지 보기, 기타 튜너, 메시지 보드 등과 같은 &#8230; <a href="http://lethean.pe.kr/2011/07/15/gnome-development-screencasts-and-tutorials/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/07/15/gnome-development-screencasts-and-tutorials/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=gnome-development-screencasts-and-tutorials">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>오랜만에 <a href="http://developer.gnome.org/">GNOME 개발자 센터</a>를 들어갔더니, 모양 뿐 아니라 내용도 확 바뀌어 있습니다. 예전에도 있었는데 제가 몰랐던 건지도 모르지만, <a href="http://developer.gnome.org/gnome-devel-demos/unstable/">10분짜리 설명서(10-minute tutorials)</a>가 가장 먼저 눈에 띄었습니다. (접속한 페이지의 실제 이름은 GNOME 개발자 플랫폼 데모입니다) 이미지 보기, 기타 튜너, 메시지 보드 등과 같은 여러 예제를 통해 단순한 GTK+ 위젯 라이브러리 사용법만 보여주는것 뿐 아니라, 말 그대로 GNOME 플랫폼의 중심이 되는 <a href="http://www.gtk.org/">GTK+</a> / <a href="http://www.clutter-project.org/">Clutter</a> / <a href="http://gstreamer.freedesktop.org/">GStreamer</a> / <a href="https://live.gnome.org/WebKitGtk">WebKitGtk</a> 라이브러리 등을 이용하여 유용하게 참고할 수 있는 간단한 응용 프로그램을 <a href="http://www.anjuta.org/">Anjuta</a> 통합 개발 도구, <a href="http://glade.gnome.org/">Glade</a> UI 편집기를 이용하여 개발하는 방법을 설명합니다. 또한 C / C++ / JavaScript / Python / <a href="https://live.gnome.org/Vala">Vala</a> 등과 같은 언어별 예제도 각각 제공하고 있습니다.</p>
<p>최근 계속 연재되는 <a href="http://www.python.org/">파이썬(Python)</a> 언어와 <a href="http://www.gtk.org/">GTK+</a> / <a href="http://www.clutter-project.org/">Clutter</a> / <a href="http://gstreamer.freedesktop.org/">GStreamer</a> 라이브러리를 이용한 GNOME 개발 동영상(screencast)도 볼만합니다. 몇몇 예제는 그놈 개발자 사이트 데모 프로그램과 겹치는 것도 있습니다.</p>
<ol>
<li><a href="http://vimeo.com/25185245">GNOME 스크린캐스트 &#8211; 01. 첫번째 GTK+ 어플리케이션</a> <em>(2011-06-16)</em>: 파이썬을 이용해 기본 기능을 가진 GTK+ 프로그램 만들기</li>
<li><a href="http://vimeo.com/25483019">GNOME 스크린캐스트 &#8211; 02. 화려한 사진 어플리케이션 만들기</a> <em>(2011-06-22)</em>: 파이썬과 GTK+를 이용해 간단한 사진 프로그램 만들기</li>
<li><a href="http://vimeo.com/25796446">GNOME 스크린캐스트 &#8211; 03. 멋진 계산기 만들기</a> <em>(2011-06-29)</em>: 파이썬과 GTK+를 이용해 간단한 계산기 프로그램 만들기</li>
<li><a href="http://vimeo.com/26100971">GNOME 스크린캐스트 &#8211; 04. 우아한 기타 튜너 만들기</a> <em>(2011-07-07)</em>: 파이썬과 GTK+, GStreamer를 이용해 기타 튜너 프로그램 만들기</li>
<li><a href="http://vimeo.com/26452876">GNOME 스크린캐스트 &#8211; 05. 매력적인 동영상 재생기 만들기</a> <em>(2011-07-15)</em>: 파이썬과 GTK+, GStreamer, Clutter를 이용해 동영상 재생기 만들기</li>
</ol>
<p><a href="http://projects.gnome.org/gedit/">gedit</a> 텍스트 편집기와 <a href="http://glade.gnome.org/">Glade</a> UI 편집기만을 이용해 파이썬 언어의 간결함과 GNOME 플랫폼 라이브러리의 강력함을 잘 보여주고 있습니다. 여담이지만, 영어가 짧아 단어만 알아듣는 본인도 코드만 보고 이해할 수 있었습니다. :)</p>
<p>물론 이 글에서 소개한 설명서는 대부분 아마도 많은 개발자에게 GNOME 플랫폼의 우수성을 전파하고 사용을 독려하기 위해 매우 기본적인 내용만 맛보기로 소개하기 때문에 더 심각하고(?) 자세한 내용을 알고 싶다면 각 기술에 대한 심층적인 공부가 필요합니다.</p>
<p>또한 GNOME 플랫폼 라이브러리라는 제목을 달고 있지만 대부분의 기술이 반드시 GNOME 환경에서만 동작하는 게 아니므로 리눅스 관련 개발자라면 한 번 들여다보는 것도 좋을 것 같습니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/07/15/gnome-development-screencasts-and-tutorials/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>eventfd 소개</title>
		<link>http://lethean.pe.kr/2011/07/07/eventfd/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=eventfd&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=eventfd-%25ec%2586%258c%25ea%25b0%259c</link>
		<comments>http://lethean.pe.kr/2011/07/07/eventfd/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=eventfd#comments</comments>
		<pubDate>Thu, 07 Jul 2011 08:36:13 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[glibc]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1731</guid>
		<description><![CDATA[리눅스에서 비단 부모 자식 프로세스간 통신 뿐 아니라, 쓰레드간 메시지 전달에도 pipe()를 자주 이용합니다. 읽거나 쓸때 별도로 뮤텍스로 보호해줄 필요가 없기 때문이기도 하지만, 무엇보다도 poll(), select(), epoll() 등과 함께 사용할 수 있기 때문입니다. 예를 들어 예전에 적었던 GLib 쓰레드 프로그래밍에서 쓰레드간 통신에 g_async_queue()를 &#8230; <a href="http://lethean.pe.kr/2011/07/07/eventfd/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/07/07/eventfd/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=eventfd">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>리눅스에서 비단 부모 자식 프로세스간 통신 뿐 아니라, 쓰레드간 메시지 전달에도 <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/pipe.2.html">pipe()</a>를 자주 이용합니다. 읽거나 쓸때 별도로 뮤텍스로 보호해줄 필요가 없기 때문이기도 하지만, 무엇보다도 poll(), select(), epoll() 등과 함께 사용할 수 있기 때문입니다. 예를 들어 예전에 적었던 <a href="http://lethean.pe.kr/2008/08/06/glib-thread-programming/">GLib 쓰레드 프로그래밍</a>에서 쓰레드간 통신에 g_async_queue()를 이용하는데, 이 방법의 단점은 쓰레드가 오직 이 메시지가 도착했을때만 깨어난다는 점입니다. 만일 이 쓰레드가 네트웍 소켓 작업이나 파일 읽기 쓰기 작업을 비동기적으로 계속 처리해야 한다면 타임아웃을 주어 처리하거나 반대로 다시 주기적으로 메시지큐를 검사하는 방법밖에 없습니다. 하지만, 리눅스에서 모든 소켓 작업, 파일 작업은 디스크립터(descriptor)로 단일화되어 있기 때문에 pipe()로 생성된 디스크립터와 실제 작업 디스크립터를 한꺼번에 epoll() 등을 이용해 처리하면 불필요한 오버헤드 없이 정확하게 작업을 처리해야할 시점에 깨어나 필요한 작업을 처리하게 됩니다. 즉, 메시지큐에 실제 메시지를 넣고 파이프의 쓰기 디스크립터에 더미 데이터를 쓰면, 작업 쓰레드에서는 파이프 읽기 디스크립터에 내용이 있을 경우 poll() 등이 감지하기 때문에 자동으로 깨어나 처리하는 방식입니다. 심지어, 파이프 전송시 더미 데이터가 아닌 메시지 내용 혹은 주소(pointer)를 쓰고, 읽는 쓰레드에서 이를 읽어 처리하면 별도의 메시지큐도 불필요하게 됩니다.</p>
<p>이 글에서 소개하려는 <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/eventfd.2.html">eventfd()</a>는 파이프 역할을 어느 정도 대체하기 위해 최근(?) 리눅스 커널에 추가된 API입니다. 읽고 쓰기에 각각 다른 두 개의 파일 디스크립터를 사용하는 파이프와 달리 eventfd는 한 개의 파일 디스크립터를 가지고 동시에 읽고 쓰기 작업을 처리합니다. 또한 별도 커널 버퍼와 복사 과정이 필요한 파이프와 달리 정수 값을 더하고(쓰고) 읽는 작업만 처리하기 때문에 성능도 훨씬 좋다고 합니다. 물론 파일 디스크립터이기 때문에 poll() 등과 함께 사용할 수 있습니다.</p>
<p>동작 방식을 간단하게 설명하면, write() 호출시 64비트 정수값을 쓰면 내부 버퍼 값에 더하면서, read() 호출시 내부 버퍼 값이 0일 경우 기다리다가, 값이 바뀌면 그 값을 읽어오고 0으로 초기화합니다.(세마포어 방식일 경우 1을 읽어오고 그 값에서 1을 감소합니다) 즉, 읽기 작업에 대한 poll() 호출은 내부 버퍼 값이 0일 경우 입력이 없는 것으로, 1 이상의 값일 경우 입력이 있는 것으로 간주하고 디스크립터를 감지하게 됩니다. (예제 코드는 매뉴얼 페이지에 포함된 코드를 확인하시길&#8230; 물론 예제 코드는 쓰레드간 통신에도 잘 동작합니다)</p>
<p>매뉴얼에 의하면 리눅스 커널 2.6.22, glibc 2.8 버전부터 eventfd() 함수를 지원합니다. 대부분의 요즘 리눅스 데스크탑 / 서버 배포판에서는 당연히 사용할 수 있지만 임베디드 시스템에서는 버전을 확인해야할 필요가 있습니다. 물론, eventfd가 메시지 내용 자체를 전송할 수 없다는 단점도 있지만, 이와 함께 리눅스 커널이 제공하는 <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/signalfd.2.html">signalfd()</a>, <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/timerfd_create.2.html">timerfd()</a>, <a href="http://linux.die.net/man/4/epoll">epoll()</a> 등을 함께 사용하면 고전 유닉스 프로그래밍의 한계에서 벗어나 마음껏 이벤트 기반 코드를 만들 수 있습니다.</p>
<p>물론 이미 잘 만들어진 <a href="http://lethean.pe.kr/2009/09/21/using-glib-mainloop/">GLib 메인루프</a>나 <a href="http://bebop.emstone.com/2011/05/18/libevent/">libevent</a> 등과 같은 라이브러리를 사용하는 것도 좋지만&#8230; :)</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/07/07/eventfd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>Vala 언어 소개</title>
		<link>http://lethean.pe.kr/2011/06/15/vala-language-introduction/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=vala-language-introduction&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=vala-%25ec%2596%25b8%25ec%2596%25b4-%25ec%2586%258c%25ea%25b0%259c</link>
		<comments>http://lethean.pe.kr/2011/06/15/vala-language-introduction/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=vala-language-introduction#comments</comments>
		<pubDate>Tue, 14 Jun 2011 15:15:01 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[GLib]]></category>
		<category><![CDATA[Vala]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1695</guid>
		<description><![CDATA[Vala 언어는 C# 언어와 문법이 비슷한 객체 지향 언어입니다. Vala 언어로 작성한 소스를 이용해 실행 파일을 직접 만들 수도 있지만 C 소스 코드로 변환할 수도 있는데, 더 정확히 말하면, GObject 프레임워크를 이용하는 순수 GLib 기반 C 언어 코드를 생성한 뒤 &#8230; <a href="http://lethean.pe.kr/2011/06/15/vala-language-introduction/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/06/15/vala-language-introduction/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=vala-language-introduction">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="https://live.gnome.org/Vala">Vala</a> 언어는 C# 언어와 문법이 비슷한 객체 지향 언어입니다. Vala 언어로 작성한 소스를 이용해 실행 파일을 직접 만들 수도 있지만 C 소스 코드로 변환할 수도 있는데, 더 정확히 말하면, GObject 프레임워크를 이용하는 순수 GLib 기반 C 언어 코드를 생성한 뒤 이를 다시 C 컴파일를 이용해 실행 파일을 생성합니다. 따라서 이렇게 생성된 C 소스 코드는 이론적으로 GLib 라이브러리가 포팅된 어떤 플랫폼에서든 동작할 수 있고, 실행 속도 역시 C 언어로 작성된 코드와 거의 동일한 성능을 보여 줍니다. 생성된 소스 코드나 라이브러리는 GLib 외의 다른 라이브러리 의존성이 없기 때문에(posix 프로파일을 사용하면 GLib 의존성도 없어짐) 당연히 다른 C 언어에서도 이용할 수 있고, 반대로 C 언어로 개발된 라이브러리를 별다른 바인딩 코드 없이 VAPI 기법을 통해 사용할 수도 있습니다.</p>
<p>요즘 GNOME 프로젝트 개발 흐름을 보면 크게 두 가지 언어, JavaScript와 Vala가 대두되고 있는데, GUI 같은 상위 제어 모듈은 JavaScript로 구현하고, 성능이 중요한 하위 모듈은 C + Vala로 구현한 뒤 이를 하나의 프로그램에서 합쳐서 성능과 개발 효율을 동시에 얻고자 하는 것 같습니다.</p>
<p>사실, GObject 프레임워크가 좋긴 하지만, 여러 고수준 언어에서 사용할 때와는 달리 C 언어에서 사용하려면 어려움이 많아서 비판을 많이 받습니다. Vala 언어는, 말하자면, 이러한 반복되는 코드 재작성(boilerplate code)과 자잘한 코딩을 획기적으로 줄여주면서 C 언어로 GObject 객체 지향 프로그램을 할 수 있도록 도와주는 역할을 하는 겁니다. C++의 복잡함은 싫고, 인터프리터 언어의 느림은 견디기 힘들고&#8230; 결국 목마른 사람들이 직접 우물을 판 셈입니다.</p>
<p>그렇다고 Vala 언어는 비단 GTK+ / Clutter 기반 GUI 프로그램을 개발하는데만 사용되지 않고, 서버 데몬[<a href="http://www.freedesktop.org/wiki/Software/systemd">systemd</a>] 같은 콘솔 프로그램 개발에도 사용합니다. 이미 <a href="http://live.gnome.org/Vala/Documentation#Projects_Developed_in_Vala">수많은 프로그램이 Vala를 이용해 개발</a>되었는데, C 언어로 개발되었던 기존 프로그램을 Vala 언어로 다시 작성한 것[<a href="http://live.gnome.org/Cheese">Cheese</a>]도 눈에 띕니다.</p>
<p>그러나, Vala 언어의 단점이라면, C 언어 부류인 C#과 문법이 비슷하긴 하지만, 무엇보다도 새 언어를 익혀야 한다는 점, 그리고 GLib / GObject 개념에 익숙하지 않을 경우 익히는데 조금 더 시간과 노력이 필요하다는 점입니다. 물론, 오픈 소스 리눅스 개발자 커뮤니티에서 개발되어, 아직은, 그 안에서만 사용하는 마이너 언어라는 한계 때문에, 즉 상용 벤더의 지원이나 Visual Studio, XCode 등과 같은 완벽한 통합 개발 환경도 없기 때문에, 많은 개발자를 끌어당길 매력이 부족한 것도 사실입니다. 하지만 한편으로는, 오픈 소스이기 때문에 오히려 미래가 더 투명한게 아닐까 하는 생각도 듭니다.</p>
<p>아무튼, Vala 언어에 대해 더 관심이 생기는 분은 <a href="http://live.gnome.org/Vala/Documentation">소개, FAQ, 튜토리얼 문서</a> 등을 한 번 훑어보시길 바랍니다. 샘플 코드도 많고, 튜토리얼도 참 많습니다. 아마 C++ / C# / Java / Python 등과 같은 객체 지향 언어에 익숙한 개발자라면 생각보다 어렵지 않다는 사실을 알게 될 겁니다. 더불어, Vala 컴파일러가 생성한 C 소스 코드를 한 번 확인해 보시면, 객체 지향 개념을 이런 식으로 코딩하고 구현할 수도 있구나 하는, 결국 중요한 건 개발자의 능력이지, 사용하는 언어나 개발도구가 전부가 아니란 것도 느끼게 됩니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/06/15/vala-language-introduction/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>라자냐 코드 (Lasagna Code)</title>
		<link>http://lethean.pe.kr/2011/06/10/lasagna-code/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lasagna-code&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25eb%259d%25bc%25ec%259e%2590%25eb%2583%2590-%25ec%25bd%2594%25eb%2593%259c-lasagna-code</link>
		<comments>http://lethean.pe.kr/2011/06/10/lasagna-code/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lasagna-code#comments</comments>
		<pubDate>Fri, 10 Jun 2011 07:37:05 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Agile]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1677</guid>
		<description><![CDATA[요즘은 예전에 작성한 라자냐 코드(Lasagna Code)의 굴레에서 벗어나기 위해 노력하고 있습니다. 스파게티 코드(Spaghetti Code)가 아닌 라자냐 코드라고? 처음 들어보시는 분을 위해 위키피디어 설명을 날림으로 번역해 보면 다음과 같습니다. 라자냐 코드는 일종의 프로그램 구조인데, 잘 정의되어 분리된 여러 계층(layer)을 가지는 것이 &#8230; <a href="http://lethean.pe.kr/2011/06/10/lasagna-code/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/06/10/lasagna-code/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=lasagna-code">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://lethean.pe.kr/wp-content/uploads/2011/06/400px-Lasagna_NIH.jpg" rel="lightbox[1677]"><img class="aligncenter" title="Lasagna" src="http://lethean.pe.kr/wp-content/uploads/2011/06/400px-Lasagna_NIH-266x400.jpg" alt="Lasagna" width="266" height="400" /></a><br />
요즘은 예전에 작성한 <a href="http://en.wikipedia.org/wiki/Spaghetti_code#Lasagna_code">라자냐 코드(Lasagna Code)</a>의 굴레에서 벗어나기 위해 노력하고 있습니다. 스파게티 코드(Spaghetti Code)가 아닌 라자냐 코드라고? 처음 들어보시는 분을 위해 위키피디어 설명을 날림으로 번역해 보면 다음과 같습니다.</p>
<blockquote><p>라자냐 코드는 일종의 프로그램 구조인데, 잘 정의되어 분리된 여러 계층(layer)을 가지는 것이 특징입니다. 각각의 코드 계층은 잘 정의된 인터페이스를 통해 아래 계층의 서비스에 접근합니다. 이 용어는 프로그램 구조를 파스타에 비유하는 스파케티 코드와 비교되곤 하는데, 다른 재료(고기, 소스, 채소, 치즈 등)가 각각 파스타 조각으로 분리되어 하나의 접시에 담긴 라자냐의 계층 구조에 기인합니다.</p>
<p>라자냐 코드의 흔한 예 중 하나는 다른 하부 시스템 , 가령 웹 어플리케이션과 비즈니스 로직, 관계형 데이터베이스 사이에 존재하는 인터페이스입니다. 또한 프로그래밍 기법 중에, 프로그램 전체 구조에서 레벨마다 다른 프로그래밍 언어를 사용하는 경우에도 이를 연결하는 계층이 존재하는데 이 역시 라자냐 코드의 일종입니다. 일반적인 클라이언트-서버 응용 프로그램 역시 대부분 잘 정의된 인터페이스를 통해 통신하므로 라자냐 코드라고 할 수 있습니다.</p>
<p>대개 라자냐 코드는 다른 계층간에 인캡슐레이션(encapsulation)을 강요하기 때문에, 문제의 하부 시스템은 잘 정의된 메카니즘(SQL, RPC, FFI 등)을 제외한 다른 통신 수단이 없습니다. 물론, 시스템의 개별적인 레이어는 덜 구조화되어 있거나 엉망으로 조직화되어 있을 수도 있습니다.</p></blockquote>
<p>위 설명을 보면 라자냐 코드는 전혀 나쁜 것 같지 않은데 도대체 무슨 굴레를 벗어난다고 하는 걸까, 모든 진리가 말하듯이, 과하면 부족함만 못한 법입니다. 너무 많은 계층화는 성능 개선 / 기능 확장 / 유지 보수 디버깅에 오히려 방해가 되어 버리고 맙니다. 예를 들어 GNOME 2 플랫폼에서는 용도별로 개발된 수많은 libgnome* 라이브러리가 존재했지만 GNOME 3 개발 과정에서 대부분 기능을 GLib / GTK+ 라이브러리에 통합한 이유 중 하나도 마찬가지일 겁니다. 여담이지만, 사실 그래서 GTK+는 모든 기능이 종합 선물 셋트처럼 제공되는 QT 애호가들에게 많은 비난을 받아왔었던 것도 사실입니다. 무슨 라이브러리 의존성이 이렇게 많고 복잡한지&#8230; 물론 아직도 GTK+ 툴킷 자체는 여전히 기능별 라이브러리에 의존하고 있지만 예전에 비해 정말 많이 정리된 셈입니다.</p>
<p>아무튼, 스스로 만든 라자냐 코드의 굴레 중에서 가장 문제가 되는 부분은, 멀티 플랫폼을 고려하는 것과 더불어 향후 라이브러리 교체시 수고를 덜기 위해 어떤 라이브러리 API를 그대로 사용하지 않고 일종의 확장성있는 랩퍼(wrapper) API를 따로 만들어 사용한 점입니다.  결과적으로, 라이브러리 자체도 계속 업그레이드 되기 때문에 이를 반영해야 하고, 다른 라이브러리로 교체하는 경우도 별로 없고, 성능 개선이나 기능 추가를 위해 끊임없이 랩퍼 API를 추가하면서, 디버깅할 때는 한 동작을 위해 두 세 단계 이상의 계층을 따라 가야하고&#8230; 배보다 배꼽이 더 커지는 경우가 발생해 버리는 상황에 이르게 됩니다.</p>
<p>두번째로 문제가 되는 부분은, 기능 하나를 구현할때 구성 모듈을 너무 세분하게 나눈 점입니다. 특히, 수평적이 아닌 수직적으로 기능을 나눌때 적절한 범위를 넘어가버리면, 새 기능 추가시 매우 많은 모듈에 대한 의존성 검사, 부작용 검사 등의 작업이 몇 배나 어렵습니다. 예를 들어 상위 계층에 있는 기능을 하위 계층에서 사용해야 하는 경우가 발생하면 이를 위한 인터페이스를 설계하는데 시간이 더 걸리는 경우도 많습니다. 그냥 간단하게 하나의 모듈로 작성하면 되었을 걸&#8230;</p>
<p>과하면 부족함만 못하다&#8230; 언제 어떻게 무엇이 될 지 모르는 미래를 위해 미리 고민해서 확장성 있는 구조를 설계하는데 노력하는 것보다, 지금 당장의 요구 사항 수준에서 아무 문제없이 잘 돌아가는, 향후 쉽게 이해하고 확장할 수 있는 간단한 구조의 코드를 작성하는게 맞는 것 같습니다. 게다가 향후 발생할 요구사항을 미리 알 지 못하는데 미리 확장성있게 설계한다는 것 자체가 모순이 아닌가 하는 생각도 들고&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/06/10/lasagna-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>PCD – Process Control Daemon</title>
		<link>http://lethean.pe.kr/2011/05/30/pcd-process-control-daemon/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pcd-process-control-daemon&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pcd-%25e2%2580%2593-process-control-daemon</link>
		<comments>http://lethean.pe.kr/2011/05/30/pcd-process-control-daemon/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pcd-process-control-daemon#comments</comments>
		<pubDate>Mon, 30 May 2011 03:49:14 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1660</guid>
		<description><![CDATA[아치리눅스를 비롯한 몇몇 리눅스 배포판은 여전히 시스템 부팅 초기화에 필요한 작업, 예를 들어 로컬 파일 시스템을 마운트하거나 웹서버, X서버 같은 시스템 프로그램을 자동으로 실행하기 위해 전통적인 유닉스의 SysV 시스템 구동 스크립트 방식(런레벨, rc.d 스크립트 등) 혹은 비슷한 방식을 이용하고 있습니다. &#8230; <a href="http://lethean.pe.kr/2011/05/30/pcd-process-control-daemon/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/05/30/pcd-process-control-daemon/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=pcd-process-control-daemon">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>아치리눅스를 비롯한 몇몇 리눅스 배포판은 여전히 시스템 부팅 초기화에 필요한 작업, 예를 들어 로컬 파일 시스템을 마운트하거나 웹서버, X서버 같은 시스템 프로그램을 자동으로 실행하기 위해 전통적인 유닉스의 SysV 시스템 구동 스크립트 방식(런레벨, rc.d 스크립트 등) 혹은 비슷한 방식을 이용하고 있습니다. 하지만 오래된 이 방식은 셸 스크립트 기반이라 전반적인 실행 속도가 느릴 뿐 아니라 프로세스간 의존성, 프로세스 종료시 예외처리(예: 자동 재실행) 등과 같은 기능을 지원하지 않아 많은 시스템 관리자 및 개발자의 불만을 산 것도 사실입니다. 특히 최근 몇 년동안 이슈가 되었던 리눅스 부팅 속도 단축을 위해 제일 먼저 처리되어야 하는 걸림돌로 여겨지기도 했습니다. 이런 이유로, 우분투(Ubuntu)는 오래전부터 자체적으로 개발한 <a href="http://upstart.ubuntu.com/">Upstart</a> 프로그램으로 이를 교체했고, 페도라(Fedora) 역시 Fedora 15부터 <a href="http://www.freedesktop.org/wiki/Software/systemd">Systemd</a> 프로그램을 이용해 구동 과정을 관리합니다. 즉, 요즘 리눅스 서버 / 데스크탑 시스템에서 시스템 초기 부팅 작업을 위한 솔루션은, 가히 춘추전국시대라고 할 수 있을만큼, 각각을 리눅스 표준으로 정착하려고 노력하는 이들이 있는가 하면, 그냥 옛것이 좋은 것이라고 고수하는 이도 있고, 더 단순하고 본인 입맛에 맞는 시스템을 직접 개발해서 사용하는 이도 있을만큼 다양합니다.</p>
<p>그런데 여담이지만, 아치리눅스 부팅 과정 커스터마이징과 속도를 경험해봐서 그런 건지, 범용 배포판은 어쩔 수 없이 모든 사용자가 만족할 수 있도록 가능한 많은 서비스 프로그램을 기본적으로 설치하고 이를 모두 시작하기 때문에 느려질 수 밖에 없는 건데, 부팅 속도 향상을 위해 시작 프로세스 관리 데몬의 성능과 기능을 개선하는 방향으로만 접근하고 있는 게 아닌가 하는 생각도 듭니다. 물론 다른 고급 기능을 제공한다고 하지만, 어차피 대부분의 기능은 배포판 개발자들만 사용하는 거고&#8230; :) 참고로, 이 <a href="http://free-electrons.com/blog/boot-time-genivi-2011/">발표자료</a>만 봐도 부팅 속도와 초기화 프로그램의 능력은 무관한 것 같습니다.</p>
<p>아무튼, 지금까지 설명한 배경이 최근 <a href="http://free-electrons.com/blog/elc-2011-videos/">임베디드 리눅스 컨퍼런스 2011 발표 슬라이드</a>를 읽다가 <a href="http://elinux.org/images/b/ba/Elc2011_shalom.odp">PCD(Process Control Daemon)라는 프로세스 관리 데몬을 소개하는 내용</a>을 보고 흥미를 가질 수 밖에 없었던 이유입니다. 위에 소개한 최신 프로그램들이 제공하는 기본 기능을 충실히 구현한 것은 물론, 임베디드 시스템을 우선 대상으로 개발했기 때문에 실행파일 크기가 매우 작고 빠르다는 점이 가장 매력적인 장점인 것 같습니다. (자세한 기능은 직접 확인해 보시길&#8230; :)</p>
<p>Systemd / Upstart 프로그램은 기능은 강력하지만 임베디드 시스템에 적용하기에는 너무 덩치가 크고 라이브러리 의존성도 무시하지 못할만큼 무겁습니다. 또한 임베디드 시스템은 개발자가 시스템의 모든 프로세스를 통제하고 완벽하게 관리해야 하기 때문에, 시스템에 대해 배포판 개발자와 동등하거나 더 많은 이해를 필요로 하므로 이러한 도구를 이용하면 작업이 수월해질 수 있습니다. 더 나아가, 이 프로그램을 조금 더 응용하면 데스크탑 / 서버용 시스템에서 여러 프로세스로 동작하는 시스템을 개발할 때도 유용하지 않을까 하는 생각도 듭니다.</p>
<p>물론 임베디드 리눅스 개발시 하나의 셸 스크립트 안에서 부팅 과정에 필요한 모든 작업을 처리하는 방식이 무조건 나쁜 건 아닙니다. 다만 복잡도가 더 높은 시스템을 설계할 때는 반드시 이런 프로세스 / 세션 관리 / 예외 처리 프로그램을 사용하거나 알아두면 나중에 참고하는 데 도움이 되지 않을까 생각해 봅니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/05/30/pcd-process-control-daemon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>libmicrohttpd 내장 웹서버 라이브러리</title>
		<link>http://lethean.pe.kr/2011/05/02/libmicrohttpd-embedded-web-server-library/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=libmicrohttpd-embedded-web-server-library&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=libmicrohttpd-%25eb%2582%25b4%25ec%259e%25a5-%25ec%259b%25b9%25ec%2584%259c%25eb%25b2%2584-%25eb%259d%25bc%25ec%259d%25b4%25eb%25b8%258c%25eb%259f%25ac%25eb%25a6%25ac</link>
		<comments>http://lethean.pe.kr/2011/05/02/libmicrohttpd-embedded-web-server-library/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=libmicrohttpd-embedded-web-server-library#comments</comments>
		<pubDate>Mon, 02 May 2011 04:26:52 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1656</guid>
		<description><![CDATA[최근 프로젝트에서 내장 웹서버를 운영하기 위해 libmicrohttpd 라이브러리를 적용해 보았습니다. 물론, 임베디드 시스템에서 많이 사용하는 GoAhead 등과 같은 상용 라이브러리를 사용하거나, BusyBox 내장 웹서버, 또는 다른 많은 오픈소스 라이브러리를 사용할 수도 있지만, 라이센스도(LGPL 또는 eCos) 괜찮고, 성능과 API 구성이 단순하고 &#8230; <a href="http://lethean.pe.kr/2011/05/02/libmicrohttpd-embedded-web-server-library/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/05/02/libmicrohttpd-embedded-web-server-library/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=libmicrohttpd-embedded-web-server-library">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>최근 프로젝트에서 내장 웹서버를 운영하기 위해 <a href="http://www.gnu.org/software/libmicrohttpd/">libmicrohttpd</a> 라이브러리를 적용해 보았습니다. 물론, 임베디드 시스템에서 많이 사용하는 <a href="http://www.goahead.com/">GoAhead</a> 등과 같은 상용 라이브러리를 사용하거나, <a href="http://www.busybox.net/">BusyBox</a> 내장 웹서버, 또는 다른 많은 오픈소스 라이브러리를 사용할 수도 있지만, 라이센스도(LGPL 또는 eCos) 괜찮고, 성능과 API 구성이 단순하고 명쾌한 것 같아서 시도해 보았습니다. (물론 아직도 주변에는 라이센스 무시하고 상용 라이브러리 몰래 사용하는 곳이 많긴 하지만&#8230; :-) 참고로, 이 라이브러리는 <a href="http://xbmc.org/">XBMC</a> 프로젝트를 들여다보다가 내부에서 사용하는 걸 우연하게 발견했습니다.</p>
<p>내장 웹서버 라이브러리를 사용하면 얻을 수 있는 가장 좋은 장점은 MJPEG, RTSP-over-HTTP 등과 같은 웹기반 스트리밍 서버를 만들때 매우 편리하다는 점입니다. 한 프로세스 안에서 웹서버 + 스트리밍 생성 루틴이 함께 동작하므로 메모리 복사 오버헤드가 줄어들고 프로그래밍 복잡도 역시 감소합니다. 또한 CGI 프로세스가 따로 동작할 필요가 없으므로 웹을 통해 설정을 변경해도 별도의 프로세스간 통신이 불필요합니다.</p>
<p>물론, 내장 웹서버 방식이 장점만 있는 건 아닙니다. 기존 스탠드얼론 웹서버가 알아서 자동으로 해주던 부분, 예를 들어 디렉토리 인덱스 파일 생성, 동시 접속 클라이언트 수 관리, 클라이언트 캐시를 위한 수정 시각 고려 등을 프로그래머가 직접 작성해야 합니다. 특히 libmicrohttpd 라이브리는 GoAhead 등과 같은 상용 라이브러리에 비하면 자동화 부분이 조금 부족합니다. 예를 들어 파일 시스템의 일반 파일에 대한 웹서비스 처리도 직접 만들어야 합니다. 물론, 대부분 필요한 기능은 예제 소스를 참고하면 어렵지 않게 구현할 수 있습니다. 하지만 제 생각에는, 웹서버 라이브러리가 너무 많은 기능을 자동화하지 않는게 오히려 더 맞다고 생각하는데, 왜냐하면 대부분 응용 프로그램에서 웹서버를 내장하는 경우는 특수한 용도(RESTful / SOAP)이거나 필요한 기능만 구현하기 위해서이기 때문에 나머지는 모두 개발자가 제어하는게 라이브러리의 제 역할이 아닌가 생각합니다.</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/05/02/libmicrohttpd-embedded-web-server-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
		<item>
		<title>도메인 메일 호스트(MX) 주소 얻기</title>
		<link>http://lethean.pe.kr/2011/04/05/get-domain-mx-host-name/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=get-domain-mx-host-name&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=%25eb%258f%2584%25eb%25a9%2594%25ec%259d%25b8-%25eb%25a9%2594%25ec%259d%25bc-%25ed%2598%25b8%25ec%258a%25a4%25ed%258a%25b8mx-%25ec%25a3%25bc%25ec%2586%258c-%25ec%2596%25bb%25ea%25b8%25b0</link>
		<comments>http://lethean.pe.kr/2011/04/05/get-domain-mx-host-name/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=get-domain-mx-host-name#comments</comments>
		<pubDate>Tue, 05 Apr 2011 07:03:05 +0000</pubDate>
		<dc:creator>lethean</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[glibc]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[카스탈리엔]]></category>

		<guid isPermaLink="false">http://lethean.pe.kr/?p=1646</guid>
		<description><![CDATA[예를 들어 nobody@hades.net이라는 메일 주소의 서버는 hades.net인 것 같지만 실제로 메일을 호스팅하는 서버는 해당 도메인 서버에 질의해서 MX 레코드에 기록된 호스트를 찾아야 합니다. 그리고 이 작업을 위해 DNS 관련 프로토콜을 직접 구현하거나. djbdns 등과 같은 라이브러리를 이용합니다. 그런데, 요즘 기존 &#8230; <a href="http://lethean.pe.kr/2011/04/05/get-domain-mx-host-name/">Continue reading <span>&#8594;</span></a> <a href="http://lethean.pe.kr/2011/04/05/get-domain-mx-host-name/?utm_source=rss&#38;utm_medium=rss&#38;utm_campaign=get-domain-mx-host-name">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>예를 들어 nobody@hades.net이라는 메일 주소의 서버는 hades.net인 것 같지만 실제로 메일을 호스팅하는 서버는 해당 도메인 서버에 질의해서 MX 레코드에 기록된 호스트를 찾아야 합니다. 그리고 이 작업을 위해 DNS 관련 프로토콜을 직접 구현하거나. <a href="http://cr.yp.to/djbdns.html">djbdns</a> 등과 같은 라이브러리를 이용합니다.</p>
<p>그런데, 요즘 기존 코드를 리팩토링하면서 가능한 오래된(?) 라이브러리에 대한 의존성을 없애고 있는데 위에서 설명한 작업을 하는 함수가 리눅스 기본 glibc 라이브러리가 <em>당연히</em> 제공하는 걸 알게 되어 잠시 허탈했습니다.</p>
<p>다음은 도메인 이름을 인수로 주면 해당 도메인의 MX 레코드, 즉 메일서버 호스트를 glibc API를 이용해 작성한 코드입니다.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;netinet/in.h&gt;</span>
<span style="color: #339933;">#include &lt;arpa/nameser.h&gt;</span>
<span style="color: #339933;">#include &lt;resolv.h&gt;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>
lookup_mx <span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>name<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> response<span style="color: #009900;">&#91;</span>NS_PACKETSZ<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>  <span style="color: #808080; font-style: italic;">/* big enough, right? */</span>
  ns_msg        handle<span style="color: #339933;">;</span>
  <span style="color: #993333;">int</span>           ns_index<span style="color: #339933;">;</span>
  <span style="color: #993333;">int</span>           len<span style="color: #339933;">;</span>
&nbsp;
  len <span style="color: #339933;">=</span> res_search <span style="color: #009900;">&#40;</span>name<span style="color: #339933;">,</span> C_IN<span style="color: #339933;">,</span> T_MX<span style="color: #339933;">,</span> response<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span> <span style="color: #009900;">&#40;</span>response<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>len <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #808080; font-style: italic;">/* failed to search MX records */</span>
      <span style="color: #b1b100;">return</span> strdup <span style="color: #009900;">&#40;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ns_initparse <span style="color: #009900;">&#40;</span>response<span style="color: #339933;">,</span> len<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>handle<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;">&#123;</span>
      <span style="color: #808080; font-style: italic;">/* failed to parse MX records for '%s'&quot;, name); */</span>
      <span style="color: #b1b100;">return</span> strdup <span style="color: #009900;">&#40;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  len <span style="color: #339933;">=</span> ns_msg_count <span style="color: #009900;">&#40;</span>handle<span style="color: #339933;">,</span> ns_s_an<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>len <span style="color: #339933;">&lt;=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #808080; font-style: italic;">/* no mx records */</span>
      <span style="color: #b1b100;">return</span> strdup <span style="color: #009900;">&#40;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>ns_index <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> ns_index <span style="color: #339933;">&lt;</span> len<span style="color: #339933;">;</span> ns_index<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      ns_rr rr<span style="color: #339933;">;</span>
      <span style="color: #993333;">char</span>  dispbuf<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4096</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ns_parserr <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>handle<span style="color: #339933;">,</span> ns_s_an<span style="color: #339933;">,</span> ns_index<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>rr<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
          <span style="color: #808080; font-style: italic;">/* WARN: ns_parserr failed */</span>
          <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      ns_sprintrr <span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>handle<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>rr<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> dispbuf<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span> <span style="color: #009900;">&#40;</span>dispbuf<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>ns_rr_class <span style="color: #009900;">&#40;</span>rr<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> ns_c_in <span style="color: #339933;">&amp;&amp;</span> ns_rr_type <span style="color: #009900;">&#40;</span>rr<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> ns_t_mx<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
          <span style="color: #993333;">char</span> mxname<span style="color: #009900;">&#91;</span>MAXDNAME<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
          dn_expand <span style="color: #009900;">&#40;</span>ns_msg_base <span style="color: #009900;">&#40;</span>handle<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                     ns_msg_base <span style="color: #009900;">&#40;</span>handle<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> ns_msg_size <span style="color: #009900;">&#40;</span>handle<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                     ns_rr_rdata<span style="color: #009900;">&#40;</span>rr<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> NS_INT16SZ<span style="color: #339933;">,</span>
                     mxname<span style="color: #339933;">,</span>
                     <span style="color: #993333;">sizeof</span> <span style="color: #009900;">&#40;</span>mxname<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
          <span style="color: #b1b100;">return</span> strdup <span style="color: #009900;">&#40;</span>mxname<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">return</span> strdup <span style="color: #009900;">&#40;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>관련 자료는 <a href="http://stackoverflow.com/">Stack Overflow</a>에서 본 것 같기도 하고&#8230; 아무튼, 명색이 전문 리눅스 C 프로그래머로서 15년 넘게 버티고 있으면서도 아직까지도 기본 C 라이브러리가 제공하는 함수도 제대로 알지 못하는 스스로를 돌아보게 됩니다. :(</p>
]]></content:encoded>
			<wfw:commentRss>http://lethean.pe.kr/2011/04/05/get-domain-mx-host-name/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/kr/</creativeCommons:license>
	</item>
	</channel>
</rss>

