<?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>ryukware</title>
	<atom:link href="http://zzz.zggg.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://zzz.zggg.com</link>
	<description>is not a blog</description>
	<lastBuildDate>Sun, 01 Apr 2012 17:18:44 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Wander Alone Like Rhinoceros Horn</title>
		<link>http://zzz.zggg.com/2010/11/01/wander-alone-like-rhinoceros-horn/</link>
		<comments>http://zzz.zggg.com/2010/11/01/wander-alone-like-rhinoceros-horn/#comments</comments>
		<pubDate>Sun, 31 Oct 2010 16:46:52 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[sup]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=569</guid>
		<description><![CDATA[多忙な過去2年間が過ぎ、荷を降ろしてみると、見過ごしていた(あるいは故意に目を逸らしていた?)様々な事柄が眼に飛び込んでくる。そして、2年の月日は、諸々の事象を眺める私の眼そのものをも変容させていた。変容は、フィジカル、 [...]]]></description>
			<content:encoded><![CDATA[<p>多忙な過去2年間が過ぎ、荷を降ろしてみると、見過ごしていた(あるいは故意に目を逸らしていた?)様々な事柄が眼に飛び込んでくる。そして、2年の月日は、諸々の事象を眺める私の眼そのものをも変容させていた。変容は、フィジカル、メタフィジカル、両面に及んでいる。回復された視力、衰えた肉体、削ぎ落とされた関心、獲得した視座。</p>
<p>過去に書いた文章を読み直すと、自分の変化と世界の変化が響き合うとともに軋み合い、交錯に眩暈を覚える。たとえば4年前に<a href="http://zzz.zggg.com/2006/11/12/server-push-today-marginal-ajax/" target="_blank">AJAXやFlashを題材にして書いた記事</a>では、Webページがアプリになる可能性を考察していた。その可能性の一端は現在HTML5として実現している。ただし、HTML5には技術的に新しいことは何もなく、政治的理由により遅れてやってきた標準化にすぎない。また、同じく2006年に、今回と同じく過去を回顧している<a href="http://zzz.zggg.com/2006/11/30/shonuff/" target="_blank">文章</a>では、「無駄な部分を省いたコミュニケーションの需要は残るはずであり、むしろ参入障壁が十分に低ければシンプルなものがリッチなものを出し抜く可能性が十分にある」と書いており、こちらはTwitterとして顕在化してきた。しかし2006年の時点では、巨大なデータを合成してシンプルなインターフェイスに落とし込む処理を、自分では全くイメージできなかった。</p>
<p>8bit時代のビデオゲームは、表現能力を欠いたことにより洋の東西を問わない普遍性を獲得した。21世紀的なシンプルさの形式が普遍性を備えるには、世界中のユーザーの要求に即座に応答できるシステムを背後に組織化しなければならない。スマートフォン、クラウド&#8230; ハードウェアにいくつセンサーやプロセッサーが導入されようが、ソフトウェアデザインは本質的に自由だ。その広すぎる可能性の中から、有限の資源に応じた、核心を衝く着想が常に求められている。</p>
<p>この2年間は、専らWebブラウザーの発展に注目してきた。Jargon Fileにも載っている用語で<a href="http://www.catb.org/jargon/html/W/wheel-of-reincarnation.html" target="_blank">wheel of reincarnation</a>(輪廻)というものがある。ある処理に特化したプロセッサ(たとえばGPU)をCPUから分離した場合に、後年そのプロセッサの汎用計算性能が強化されるにつれ結局はCPU上でソフトウェア実装した方が効率的になり、再度CPUに吸収される&#8230;というサイクルが反復されることを指して輪廻と呼ぶ。Webブラウザーも、PCの本質的な機能であるということになれば、<a href="http://zzz.zggg.com/2009/08/19/red-pill-or-blue-pill/" target="_blank">OSに統合されるのが望ましい</a>。ところが、政治的事情からWindowsではそうはなっていない。iOSやAndroid、Chrome OSでは統合されているというのにWindowsではそうはなっていないというのは笑うしかない。どちらが望ましいのだろうか。一つだけ明らかなのは、私は自由なソフトウェアを支持するということである。つまり、iOSの現状が、競争を排除するようなものであるとすれば、私はそれを忌避するし、Apple社の製品は購入しない。私にとってのiPhoneとは、Androidの健全な発展を促す触媒でしかない。</p>
<p>Webブラウザーに関して、直近の動きで一番注目しているのは<a href="http://mozillalabs.com/chromeless/2010/10/21/chromeless-build-your-own-browser-ui-using-html-css-js/" target="_blank">Chromeless</a>だ。XULがHTMLに溶け出している。自分が欲しかったコンセプトがそのままプロジェクトになっていて、嬉しかった。他に興味深かったのは、Beyond3Dで<a href="http://forum.beyond3d.com/showpost.php?p=1483011&amp;postcount=155" target="_blank">教えてもらった</a>、EAによるPS3/Xbox360への<a href="http://gpl.ea.com/skate3.html" target="_blank">WebKit移植</a>のベースに利用されていた<a href="http://en.wikipedia.org/wiki/Origyn_Web_Browser" target="_blank">Origyn Web Browser</a>。現在サイトが落ちているようなのでEA側のコードしか見ることは出来ない。EA側コードは、Paul Pedriana氏による<a href="https://github.com/paulhodge/EASTL" target="_blank">EASTL</a>実装を含む(ドキュメントには<a href="http://beta.boost.org/doc/libs/1_42_0/doc/html/intrusive.html" target="_blank">Boost.Intrusive</a>みたいなコンテナーが入っていると書かれているが見つからなかった)。</p>
<p>次に向けて、学ばなければならないことは山ほどある。</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2010/11/01/wander-alone-like-rhinoceros-horn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dissecting WebKit2 Implementation as of October 2010</title>
		<link>http://zzz.zggg.com/2010/10/11/webkit2-implementation-overview-as-of-october-2010-2-2/</link>
		<comments>http://zzz.zggg.com/2010/10/11/webkit2-implementation-overview-as-of-october-2010-2-2/#comments</comments>
		<pubDate>Mon, 11 Oct 2010 11:19:40 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=497</guid>
		<description><![CDATA[WebKit2 was first disclosed to the public in April 2010. Now half a year has passed, has there been any notice [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://trac.webkit.org/wiki/WebKit2" target="_blank">WebKit2</a> was first disclosed to the public in April 2010. Now half a year has passed, has there been any noticeable progress? This time I delve into the WebKit2 from the source-code point of view.</p>
<p>First let me recap what WebKit2 actually is and how it&#8217;s related to the current WebKit with the <a href="http://trac.webkit.org/wiki/WebKit2" target="_blank">official high level design document</a> as the reference.</p>
<p>For those who are not very familiar with WebKit, it may be confusing that WebKit as a whole contains a part that shares the same <em>WebKit</em> name. WebKit as the framework has 3 major components &#8211; <a href="http://trac.webkit.org/browser/trunk/WebKit" target="_blank">WebKit</a>, <a href="http://trac.webkit.org/browser/trunk/WebCore" target="_blank">WebCore</a>, and <a href="http://trac.webkit.org/browser/trunk/JavaScriptCore" target="_blank">JavaScriptCore</a> &#8211; as you see in the <a href="http://trac.webkit.org/browser/trunk" target="_blank">source directory</a>. WebCore is the layout engine that parses an HTML5 web page into a DOM tree and renders a render tree created out of a DOM tree with CSS information computed on each node. In addition to the abstract or platform-agnostic parts, it contains platform-specific implementations such as graphics and I/O if necessary. JavaScriptCore is the JavaScript engine. Google Chrome swaps it with its own <a href="http://code.google.com/p/v8/" target="_blank">V8</a> engine whereas Safari uses JavaScriptCore under the name Nitro. JavaScriptCore/V8 bindings to DOM live in the <a href="http://trac.webkit.org/browser/trunk/WebCore/bindings" target="_blank">bindings directory</a> in the WebCore. A WebKit user controls WebCore through a high-level API set which is differently implemented for each platform. The WebKit directory contains such an API set. For example, the Windows version of Safari implements it by COM classes in C++ in the <a href="http://trac.webkit.org/browser/trunk/WebKit/win" target="_blank">win</a> directory while the Mac version does it with Objective-C in the <a href="http://trac.webkit.org/browser/trunk/WebKit/mac" target="_blank">mac</a> directory. Due to some dependency on proprietary libraries owned by Apple found in the Windows implementation for Safari, WebKit embedders should try other API layer implementations such as Gtk+ or Qt unless adopting <a href="http://code.google.com/chromium/" target="_blank">Chromium</a> suits the need.</p>
<p><span id="more-497"></span></p>
<p>WebKit2 effectively splits this WebKit API layer into two. The first part, UI Process, is obviously the interface accessed by the platform API user. Inside this shell, or outside if you follow its process model, there are Web Processes that implement the second layer of the new WebKit2 API. The UI Process controls multiple Web Processes through accessing the API based on an IPC protocol agreed by them. The API of the UI Process should work in almost the same way for a user as the old API except that the WebKit2 API are non-blocking. Most likely the underlying WebCore doesn&#8217;t change much as a multiprocess architecture has typically a lot less synchronization issues than a multithreaded architecture. Also the current WebKit API should continue to work alongside of the WebKit2 development unless Chromium tries to merge it, but the prospect looks unlikely at this point.</p>
<p>Let&#8217;s take a look at the source code itself. The most easiest entry point would be an example that uses WebKit2 API. Fortunately it&#8217;s already available as the <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser" target="_blank">MiniBrowser</a>. Right now there are 3 implementations: Mac, Windows, and Qt. The Mac version seems the most active, the next is the Qt version. The Windows version is a plain Windows application that is not related to the current Windows version of Safari for some reason. Since it&#8217;s the most simple, I start from there. The <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/main.cpp" target="_blank">main.cpp</a> has its message loop.</p>
<pre class="brush: cpp; title: ; notranslate">
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow)
{
    MiniBrowser::shared().initialize(hInstance);

    // Create and show our initial window.
    MiniBrowser::shared().createNewWindow();

    MSG message;
    while (BOOL result = ::GetMessage(&amp;message, 0, 0, 0)) {
        if (result == -1)
            break;
        ::TranslateMessage(&amp;message);

        if (!MiniBrowser::shared().handleMessage(&amp;message))
            ::DispatchMessage(&amp;message);
    }

    return 0;
}
</pre>
<p><code>MiniBrowser::shared()</code> returns the static singleton of the <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/MiniBrowser.h" target="_blank">MiniBrowser</a> object. So it calls <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/MiniBrowser.cpp" target="_blank"><code>MiniBrowser::createNewWindow()</code></a> which then creates a <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserWindow.h" target="_blank">BrowserWindow</a> object with its member BrowserView object (<code>m_browserView</code>). The actual browser view is created at the end of <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserWindow.cpp" target="_blank"><code>BrowserWindow::onCreate</code></a>. It calls <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserView.cpp" target="_blank"><code>BrowserView::create</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
void BrowserView::create(RECT webViewRect, BrowserWindow* parentWindow)
{
    assert(!m_webView);

    bool isShiftKeyDown = ::GetKeyState(VK_SHIFT) &amp; HIGH_BIT_MASK_SHORT;

    WKContextRef context;
    if (isShiftKeyDown)
        context = WKContextGetSharedThreadContext();
    else
        context = WKContextGetSharedProcessContext();

    WKPageNamespaceRef pageNamespace = WKPageNamespaceCreate(context);

    m_webView = WKViewCreate(webViewRect, pageNamespace, parentWindow-&gt;window());

    WKPageUIClient uiClient = {
        0,              /* version */
        parentWindow,   /* clientInfo */
        createNewPage,
        showPage,
        closePage,
        runJavaScriptAlert,
        runJavaScriptConfirm,
        runJavaScriptPrompt,
        setStatusText,
        mouseDidMoveOverElement,
        0               /* didNotHandleKeyEvent */
    };

    WKPageSetPageUIClient(WKViewGetPage(m_webView), &amp;uiClient);
}
</pre>
<p>A lot of things seem to happen, but apparently this is the starting point of embedding WebKit2. <code>isShiftKeyDown</code> is probably there for the debug purpose, it&#8217;s used to switch the context. <code>WKContextGetSharedThreadContext</code> is declared in <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/WKContextPrivate.h" target="_blank">WKContextPrivate.h</a> while <code>WKContextGetSharedProcessContext</code> is declared in <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/WKContext.h" target="_blank">WKContext.h</a>, both are WebKit2 C API functions. These actually refer to the <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebContext.cpp" target="_blank"><code>WebContext</code></a> object of the UI Process.</p>
<pre class="brush: cpp; title: ; notranslate">
WebContext* WebContext::sharedProcessContext()
{
    WTF::initializeMainThread();
    RunLoop::initializeMainRunLoop();
    static WebContext* context = adoptRef(new WebContext(ProcessModelSharedSecondaryProcess, String())).leakRef();
    return context;
}

WebContext* WebContext::sharedThreadContext()
{
    RunLoop::initializeMainRunLoop();
    static WebContext* context = adoptRef(new WebContext(ProcessModelSharedSecondaryThread, String())).leakRef();
    return context;
}
</pre>
<p>This <code>RunLoop</code> is declared in <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/RunLoop.h" target="_blank">RunLoop.h</a>,but most of its work is defined in the platform-specific implementation, for example the Windows version can be found in <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/win/RunLoopWin.cpp" target="_blank">RunLoopWin.cpp</a>. It&#8217;s a message queue window for WebKit work items. So, back to the <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserView.cpp" target="_blank"><code>BrowserView::create</code></a>, it creates a <code>WebContext</code> of some flavor. Its <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebContext.h" target="_blank">member declaration</a> is like this.</p>
<pre class="brush: cpp; title: ; notranslate">
class WebContext : public APIObject {
public:
    static const Type APIType = TypeContext;

    static WebContext* sharedProcessContext();
    static WebContext* sharedThreadContext();

    static PassRefPtr&lt;WebContext&gt; create(const String&amp; injectedBundlePath);

    ~WebContext();

// snip

private:
    WebContext(ProcessModel, const String&amp; injectedBundlePath);

    virtual Type type() const { return APIType; }

    void ensureWebProcess();
    bool hasValidProcess() const { return m_process &amp;&amp; m_process-&gt;isValid(); }
    void platformInitializeWebProcess(WebProcessCreationParameters&amp;);

    static void languageChanged(void* context);
    void languageChanged();

    ProcessModel m_processModel;

    // FIXME: In the future, this should be one or more WebProcessProxies.
    RefPtr&lt;WebProcessProxy&gt; m_process;

    HashSet&lt;WebPageNamespace*&gt; m_pageNamespaces;
    RefPtr&lt;WebPreferences&gt; m_preferences;

    String m_injectedBundlePath;
    WebContextInjectedBundleClient m_injectedBundleClient;

    WebHistoryClient m_historyClient;

    PluginInfoStore m_pluginInfoStore;
    VisitedLinkProvider m_visitedLinkProvider;

    HashSet&lt;String&gt; m_schemesToRegisterAsEmptyDocument;
    HashSet&lt;String&gt; m_schemesToRegisterAsSecure;
    HashSet&lt;String&gt; m_schemesToSetDomainRelaxationForbiddenFor;

    Vector&lt;pair&lt;String, RefPtr&lt;APIObject&gt; &gt; &gt; m_pendingMessagesToPostToInjectedBundle;

    CacheModel m_cacheModel;

#if PLATFORM(WIN)
    bool m_shouldPaintNativeControls;
#endif
};
</pre>
<p>It has document-related objects such as <code>WebHistoryClient</code> and <code>VisitedLinkProvider</code>, also it has <code>WebPreferences</code> that should be applied to all pages. So <code>WebContext</code> is the class that represents a single web browser.</p>
<p>The other important member object is <code>WebProcessProxy</code> that is a proxy to a renderer process. As the comment suggests, it will be the proxy to multiple Web Processes in the future. The web process proxy is initialized before creating a web page by <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebProcessProxy.cpp" target="_blank"><code>WebContext::ensureWebProcess</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
void WebContext::ensureWebProcess()
{
    if (m_process)
        return;

    m_process = WebProcessManager::shared().getWebProcess(this);

    WebProcessCreationParameters parameters;

    parameters.applicationCacheDirectory = applicationCacheDirectory();

    if (!injectedBundlePath().isEmpty()) {
        parameters.injectedBundlePath = injectedBundlePath();

#if ENABLE(WEB_PROCESS_SANDBOX)
        char* sandboxBundleTokenUTF8 = 0;
        CString injectedBundlePathUTF8 = injectedBundlePath().utf8();
        sandbox_issue_extension(injectedBundlePathUTF8.data(), &amp;sandboxBundleTokenUTF8);
        String sandboxBundleToken = String::fromUTF8(sandboxBundleTokenUTF8);
        if (sandboxBundleTokenUTF8)
            free(sandboxBundleTokenUTF8);

        parameters.injectedBundlePathToken = sandboxBundleToken;
#endif
    }

    parameters.shouldTrackVisitedLinks = m_historyClient.shouldTrackVisitedLinks();
    parameters.cacheModel = m_cacheModel;
    parameters.languageCode = defaultLanguage();
    parameters.applicationCacheDirectory = applicationCacheDirectory();

    copyToVector(m_schemesToRegisterAsEmptyDocument, parameters.urlSchemesRegistererdAsEmptyDocument);
    copyToVector(m_schemesToRegisterAsSecure, parameters.urlSchemesRegisteredAsSecure);
    copyToVector(m_schemesToSetDomainRelaxationForbiddenFor, parameters.urlSchemesForWhichDomainRelaxationIsForbidden);

    // Add any platform specific parameters
    platformInitializeWebProcess(parameters);

    m_process-&gt;send(Messages::WebProcess::InitializeWebProcess(parameters), 0);
}
</pre>
<p><a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebProcessManager.cpp" target="_blank"><code>WebProcessManager</code></a> does simple creation of a Web Process proxy via <code>WebProcessProxy::create</code> dependent on the process model: Shared Secondary Process, Shared Secondary Thread, Secondary Process. The names are a bit confusing but Shared Secondary Thread means using threads for Web Processes, and Shared Secondary Process means using multiple processes. The last one manages multiple WebContext objects and correspondent Web Proxy objects in a hash map.</p>
<pre class="brush: cpp; title: ; notranslate">
WebProcessProxy* WebProcessManager::getWebProcess(WebContext* context)
{
    switch (context-&gt;processModel()) {
        case ProcessModelSharedSecondaryProcess: {
            if (!m_sharedProcess)
                m_sharedProcess = WebProcessProxy::create(context);
            return m_sharedProcess.get();
        }
        case ProcessModelSharedSecondaryThread: {
            if (!m_sharedThread)
                m_sharedThread = WebProcessProxy::create(context);
            return m_sharedThread.get();
        }
        case ProcessModelSecondaryProcess: {
            std::pair&lt;ProcessMap::iterator, bool&gt; result = m_processMap.add(context, 0);
            if (result.second) {
                ASSERT(!result.first-&gt;second);
                result.first-&gt;second = WebProcessProxy::create(context);
            }

            ASSERT(result.first-&gt;second);
            return result.first-&gt;second.get();
        }
    }

    ASSERT_NOT_REACHED();
    return 0;
}
</pre>
<p><code>WebProcessProxy::create</code> is just a call to <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebProcessProxy.cpp" target="_blank"><code>WebProcessProxy::connect</code></a> via its constructor.</p>
<pre class="brush: cpp; title: ; notranslate">
PassRefPtr&lt;WebProcessProxy&gt; WebProcessProxy::create(WebContext* context)
{
    return adoptRef(new WebProcessProxy(context));
}

WebProcessProxy::WebProcessProxy(WebContext* context)
    : m_responsivenessTimer(this)
    , m_context(context)
{
    connect();
}

WebProcessProxy::~WebProcessProxy()
{
    ASSERT(!m_connection);

    for (size_t i = 0; i &lt; m_pendingMessages.size(); ++i)
        m_pendingMessages[i].releaseArguments();

    if (m_processLauncher) {
        m_processLauncher-&gt;invalidate();
        m_processLauncher = 0;
    }

    if (m_threadLauncher) {
        m_threadLauncher-&gt;invalidate();
        m_threadLauncher = 0;
    }
}

void WebProcessProxy::connect()
{
    if (m_context-&gt;processModel() == ProcessModelSharedSecondaryThread) {
        ASSERT(!m_threadLauncher);
        m_threadLauncher = ThreadLauncher::create(this);
    } else {
        ASSERT(!m_processLauncher);

        ProcessLauncher::LaunchOptions launchOptions;
        launchOptions.processType = ProcessLauncher::WebProcess;
#if PLATFORM(MAC)
        // We want the web process to match the architecture of the UI process.
        launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
#endif
        m_processLauncher = ProcessLauncher::create(this, launchOptions);
    }
}
</pre>
<p>If the process model is Shared Secondary Thread, it creates a <code>ThreadLauncher</code> instance by its <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/ThreadLauncher.h" target="_blank"><code>create</code></a> method.</p>
<pre class="brush: cpp; title: ; notranslate">
class ThreadLauncher : public ThreadSafeShared&lt;ThreadLauncher&gt; {
public:
    class Client {
    public:
        virtual ~Client() { }
        virtual void didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier) = 0;
    };

    static PassRefPtr&lt;ThreadLauncher&gt; create(Client* client)
    {
        return adoptRef(new ThreadLauncher(client));
    }
</pre>
<p>Again, it&#8217;s just a proxy to <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/ThreadLauncher.cpp" target="_blank"><code>ThreadLauncher::launchThread</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
ThreadLauncher::ThreadLauncher(Client* client)
    : m_client(client)
{
    launchThread();
}

void ThreadLauncher::launchThread()
{
    m_isLaunching = true;

    CoreIPC::Connection::Identifier connectionIdentifier = createWebThread();

    // We've finished launching the thread, message back to the main run loop.
    RunLoop::main()-&gt;scheduleWork(WorkItem::create(this, &amp;ThreadLauncher::didFinishLaunchingThread, connectionIdentifier));
}
</pre>
<p>ThreadLauncher::createWebThread is a platform-specific method. It&#8217;s defined in <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/win/ThreadLauncherWin.cpp" target="_blank">ThreadLauncherWin.cpp</a> for Windows.</p>
<pre class="brush: cpp; title: ; notranslate">
CoreIPC::Connection::Identifier ThreadLauncher::createWebThread()
{
    // First, create the server and client identifiers.
    HANDLE serverIdentifier, clientIdentifier;
    if (!CoreIPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) {
        // FIXME: What should we do here?
        ASSERT_NOT_REACHED();
    }

    if (!createThread(webThreadBody, reinterpret_cast&lt;void*&gt;(clientIdentifier), &quot;WebKit2: WebThread&quot;)) {
        ::CloseHandle(serverIdentifier);
        ::CloseHandle(clientIdentifier);
        return 0;
    }

    return serverIdentifier;
}
</pre>
<p><a href="http://trac.webkit.org/browser/trunk/JavaScriptCore/wtf/Threading.h" target="_blank"><code>createThread</code></a> is a utility function declared in the WTF namespace of JavaScriptCore. In <a href="http://trac.webkit.org/browser/trunk/JavaScriptCore/wtf/Threading.cpp" target="_blank"><code>wtf/Threading.cpp</code></a>, it calls platform-specific <code>createThreadInternal</code>.</p>
<pre class="brush: cpp; title: ; notranslate">
ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* name)
{
    // Visual Studio has a 31-character limit on thread names. Longer names will
    // be truncated silently, but we'd like callers to know about the limit.
#if !LOG_DISABLED
    if (strlen(name) &gt; 31)
        LOG_ERROR(&quot;Thread name \&quot;%s\&quot; is longer than 31 characters and will be truncated by Visual Studio&quot;, name);
#endif

    NewThreadContext* context = new NewThreadContext(entryPoint, data, name);

    // Prevent the thread body from executing until we've established the thread identifier.
    MutexLocker locker(context-&gt;creationMutex);

    return createThreadInternal(threadEntryPoint, context, name);
}
</pre>
<p>For example, the Windows version is defined in <a href="http://trac.webkit.org/browser/trunk/JavaScriptCore/wtf/ThreadingWin.cpp" target="_blank"><code>wtf/ThreadingWin.cpp</code></a> (for some reason this is not in a separate folder).</p>
<pre class="brush: cpp; title: ; notranslate">
ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, const char* threadName)
{
    unsigned threadIdentifier = 0;
    ThreadIdentifier threadID = 0;
    ThreadFunctionInvocation* invocation = new ThreadFunctionInvocation(entryPoint, data);
#if OS(WINCE)
    // This is safe on WINCE, since CRT is in the core and innately multithreaded.
    // On desktop Windows, need to use _beginthreadex (not available on WinCE) if using any CRT functions
    HANDLE threadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)wtfThreadEntryPoint, invocation, 0, (LPDWORD)&amp;threadIdentifier);
#else
    HANDLE threadHandle = reinterpret_cast&lt;HANDLE&gt;(_beginthreadex(0, 0, wtfThreadEntryPoint, invocation, 0, &amp;threadIdentifier));
#endif
    if (!threadHandle) {
#if OS(WINCE)
        LOG_ERROR(&quot;Failed to create thread at entry point %p with data %p: %ld&quot;, entryPoint, data, ::GetLastError());
#elif defined(NO_ERRNO)
        LOG_ERROR(&quot;Failed to create thread at entry point %p with data %p.&quot;, entryPoint, data);
#else
        LOG_ERROR(&quot;Failed to create thread at entry point %p with data %p: %ld&quot;, entryPoint, data, errno);
#endif
        return 0;
    }

    threadID = static_cast&lt;ThreadIdentifier&gt;(threadIdentifier);
    storeThreadHandleByIdentifier(threadIdentifier, threadHandle);

    return threadID;
}
</pre>
<p><a href="http://msdn.microsoft.com/en-us/library/kdzttdcb.aspx" target="_blank"><code>_beginthreadex</code></a> is the underlying thread creation function on Windows. In this model, the thread ID is used as the return value which becomes CoreIPC::Connection::Identifier.</p>
<p>You may remember the <a href="http://www.chromium.org/developers/design-documents/process-models#TOC-Single-process" target="_blank">single process model</a> in Chromium as a mode akin to this Shared Secondary Thread prcess model in WebKit2.</p>
<p>OK let&#8217;s get back to the more interesting one, the Shared Secondary Process model that sports <code>ProcessLauncher</code>. When created via the <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/ProcessLauncher.h" target="_blank"><code>create</code></a> method, its <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/ProcessLauncher.cpp" target="_blank">constructor</a> adds a function call to <code>ProcessLauncher::launchProcess</code> to the end of its <code>WorkQueue</code> singleton.</p>
<pre class="brush: cpp; title: ; notranslate">
class ProcessLauncher : public ThreadSafeShared&lt;ProcessLauncher&gt; {
public:
    class Client {
    public:
        virtual ~Client() { }

        virtual void didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier) = 0;
    };
// snip

    static PassRefPtr&lt;ProcessLauncher&gt; create(Client* client, const LaunchOptions&amp; launchOptions)
    {
        return adoptRef(new ProcessLauncher(client, launchOptions));
    }
</pre>
<pre class="brush: cpp; title: ; notranslate">
static WorkQueue&amp; processLauncherWorkQueue()
{
    DEFINE_STATIC_LOCAL(WorkQueue, processLauncherWorkQueue, (&quot;com.apple.WebKit.ProcessLauncher&quot;));
    return processLauncherWorkQueue;
}

ProcessLauncher::ProcessLauncher(Client* client, const LaunchOptions&amp; launchOptions)
    : m_client(client)
    , m_launchOptions(launchOptions)
    , m_processIdentifier(0)
{
    // Launch the process.
    m_isLaunching = true;
    processLauncherWorkQueue().scheduleWork(WorkItem::create(this, &amp;ProcessLauncher::launchProcess));
}
</pre>
<p><a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/win/WorkQueueWin.cpp" target="_blank"><code>WorkQueue::scheduleWork</code></a> is defined as a platform-specific function. In the case of Windows, it&#8217;s based on the <a href="http://msdn.microsoft.com/en-us/library/ms684957.aspx" target="_blank"><code>QueueUserWorkItem</code></a> API that uses the thread pool of Windows OS. Again, <code>ProcessLauncher::launchProcess</code> is implemented in the platform-specific form. For Windows, it&#8217;s in <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/win/ProcessLauncherWin.cpp" target="_blank">win/ProcessLauncherWin.cpp</a>.</p>
<pre class="brush: cpp; title: ; notranslate">
void ProcessLauncher::launchProcess()
{
    // First, create the server and client identifiers.
    HANDLE serverIdentifier, clientIdentifier;
    if (!CoreIPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) {
        // FIXME: What should we do here?
        ASSERT_NOT_REACHED();
    }

    // Ensure that the child process inherits the client identifier.
    ::SetHandleInformation(clientIdentifier, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);

    // To get the full file path to WebKit2WebProcess.exe, we fild the location of WebKit.dll,
    // remove the last path component, and then append WebKit2WebProcess(_debug).exe.
    HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName);
    ASSERT(webKitModule);
    if (!webKitModule)
        return;

    WCHAR pathStr[MAX_PATH];
    if (!::GetModuleFileNameW(webKitModule, pathStr, WTF_ARRAY_LENGTH(pathStr)))
        return;

    ::PathRemoveFileSpecW(pathStr);
    if (!::PathAppendW(pathStr, webProcessName))
        return;

    String commandLine(pathStr);

    // FIXME: It would be nice if we could just create a CommandLine object and output a command line vector from it.
    Vector&lt;UChar&gt; commandLineVector;
    append(commandLineVector, commandLine);
    append(commandLineVector, &quot; -type webprocess&quot;);
    append(commandLineVector, &quot; -clientIdentifier &quot;);
    append(commandLineVector, String::number(reinterpret_cast&lt;uintptr_t&gt;(clientIdentifier)));
    commandLineVector.append('&#92;&#48;');

    STARTUPINFO startupInfo = { 0 };
    startupInfo.cb = sizeof(startupInfo);
    PROCESS_INFORMATION processInformation = { 0 };
    BOOL result = ::CreateProcessW(0, commandLineVector.data(), 0, 0, true, 0, 0, 0, &amp;startupInfo, &amp;processInformation);

    // We can now close the client identifier handle.
    ::CloseHandle(clientIdentifier);

    if (!result) {
        // FIXME: What should we do here?
        DWORD error = ::GetLastError();
        ASSERT_NOT_REACHED();
    }

    // Don't leak the thread handle.
    ::CloseHandle(processInformation.hThread);

    // We've finished launching the process, message back to the run loop.
    RunLoop::main()-&gt;scheduleWork(WorkItem::create(this, &amp;ProcessLauncher::didFinishLaunchingProcess, processInformation.hProcess, serverIdentifier));
}
</pre>
<p><code>CoreIPC::Connection::createServerAndClientIdentifiers</code> creates a platform primitive for IPC (InterProcess Communication) between the UI Process and Web Processes. The whole implementation of IPC for WebKit2 is found in the <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/CoreIPC" target="_blank">CoreIPC</a> directory. The <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp" target="_blank">Windows version of <code>Connection::createServerAndClientIdentifiers</code></a> uses <a href="http://msdn.microsoft.com/en-us/library/aa365590.aspx" target="_blank">Named Pipe</a> for its IPC channel.</p>
<pre class="brush: cpp; title: ; notranslate">
bool Connection::createServerAndClientIdentifiers(HANDLE&amp; serverIdentifier, HANDLE&amp; clientIdentifier)
{
    String pipeName;

    while (true) {
        unsigned uniqueID = randomNumber() * std::numeric_limits&lt;unsigned&gt;::max();
        pipeName = String::format(&quot;\\\\.\\pipe\\com.apple.WebKit.%x&quot;, uniqueID);

        serverIdentifier = ::CreateNamedPipe(pipeName.charactersWithNullTermination(),
                                             PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
                                             PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, inlineMessageMaxSize, inlineMessageMaxSize,
                                             0, 0);
        if (!serverIdentifier &amp;&amp; ::GetLastError() == ERROR_PIPE_BUSY) {
            // There was already a pipe with this name, try again.
            continue;
        }

        break;
    }

    if (!serverIdentifier)
        return false;

    clientIdentifier = ::CreateFileW(pipeName.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
    if (!clientIdentifier) {
        ::CloseHandle(serverIdentifier);
        return false;
    }

    DWORD mode = PIPE_READMODE_MESSAGE;
    if (!::SetNamedPipeHandleState(clientIdentifier, &amp;mode, 0, 0)) {
        ::CloseHandle(serverIdentifier);
        ::CloseHandle(clientIdentifier);
        return false;
    }

    return true;
}
</pre>
<p>In Chromium, a similar operation is handled by its IPC <a href="http://src.chromium.org/viewvc/chrome/trunk/src/ipc/ipc_channel_win.cc" target="_blank"><code>Channel</code></a> implementation. It may be interesting to compare it with the one in WebKit2.</p>
<pre class="brush: cpp; title: ; notranslate">
bool Channel::ChannelImpl::CreatePipe(const std::string&amp; channel_id,
                                      Mode mode) {
  DCHECK(pipe_ == INVALID_HANDLE_VALUE);
  const std::wstring pipe_name = PipeName(channel_id);
  if (mode == MODE_SERVER) {
    SECURITY_ATTRIBUTES security_attributes = {0};
    security_attributes.bInheritHandle = FALSE;
    security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
    if (!GetLogonSessionOnlyDACL(
        reinterpret_cast&lt;SECURITY_DESCRIPTOR**&gt;(
            &amp;security_attributes.lpSecurityDescriptor))) {
      NOTREACHED();
    }

    pipe_ = CreateNamedPipeW(pipe_name.c_str(),
                             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
                                FILE_FLAG_FIRST_PIPE_INSTANCE,
                             PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
                             1,         // number of pipe instances
                             // output buffer size (XXX tune)
                             Channel::kReadBufferSize,
                             // input buffer size (XXX tune)
                             Channel::kReadBufferSize,
                             5000,      // timeout in milliseconds (XXX tune)
                             &amp;security_attributes);
    LocalFree(security_attributes.lpSecurityDescriptor);
  } else {
    pipe_ = CreateFileW(pipe_name.c_str(),
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
                            FILE_FLAG_OVERLAPPED,
                        NULL);
  }
  if (pipe_ == INVALID_HANDLE_VALUE) {
    // If this process is being closed, the pipe may be gone already.
    LOG(WARNING) &lt;&lt; &quot;failed to create pipe: &quot; &lt;&lt; GetLastError();
    return false;
  }

  // Create the Hello message to be sent when Connect is called
  scoped_ptr&lt;Message&gt; m(new Message(MSG_ROUTING_NONE,
                                    HELLO_MESSAGE_TYPE,
                                    IPC::Message::PRIORITY_NORMAL));
  if (!m-&gt;WriteInt(GetCurrentProcessId())) {
    CloseHandle(pipe_);
    pipe_ = INVALID_HANDLE_VALUE;
    return false;
  }

  output_queue_.push(m.release());
  return true;
}
</pre>
<p>Going back to <code>ProcessLauncher::launchProcess</code>, it locates the executable module for the Web Process and creates a new process with the given parameters. When it&#8217;s done, the callback function <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/Launcher/ProcessLauncher.cpp" target="_blank"><code>ProcessLauncher::didFinishLaunchingProcess</code></a> is put on the work queue of the <code>RunLoop</code>. It then calls <code>WebProcessProxy::didFinishLaunching</code> since m_client is actually <code>WebProcessProxy</code> as you may notice if you remember what was going on in <code>WebProcessProxy::connect</code>. <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebProcessProxy.h" target="_blank"><code>WebProcessProxy</code></a> inherits <code>ProcessLauncher::Client</code>.</p>
<pre class="brush: cpp; title: ; notranslate">
void ProcessLauncher::didFinishLaunchingProcess(PlatformProcessIdentifier processIdentifier, CoreIPC::Connection::Identifier identifier)
{
    m_processIdentifier = processIdentifier;
    m_isLaunching = false;

    if (!m_client) {
        // FIXME: Dispose of the connection identifier.
        return;
    }

    m_client-&gt;didFinishLaunching(this, identifier);
}
</pre>
<p>It then opens an IPC server connection (<code>RefPtr&lt;CoreIPC::Connection&gt; m_connection</code>) in <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebProcessProxy.cpp" target="_blank"><code>WebProcessProxy::didFinishLaunching</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
{
    didFinishLaunching(connectionIdentifier);
}

void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
{
    didFinishLaunching(connectionIdentifier);
}

void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
{
    ASSERT(!m_connection);

    m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
    m_connection-&gt;open();

    for (size_t i = 0; i &lt; m_pendingMessages.size(); ++i) {
        CoreIPC::Connection::OutgoingMessage&amp; outgoingMessage = m_pendingMessages[i];
        m_connection-&gt;sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()));
    }

    m_pendingMessages.clear();

    // Tell the context that we finished launching.
    m_context-&gt;processDidFinishLaunching(this);
}
</pre>
<p>The IPC server in the UI Process hosts Web Processes. <code>Connection::open</code> is also implemented for a specific platform. Its <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp" target="_blank">Windows version</a> starts listening for read and write state events on event handles to communicate with Web Processes. It&#8217;s a very standard server behavior.</p>
<pre class="brush: cpp; title: ; notranslate">
bool Connection::open()
{
    // Start listening for read and write state events.
    m_connectionQueue.registerHandle(m_readState.hEvent, WorkItem::create(this, &amp;Connection::readEventHandler));
    m_connectionQueue.registerHandle(m_writeState.hEvent, WorkItem::create(this, &amp;Connection::writeEventHandler));

    // Schedule a read.
    m_connectionQueue.scheduleWork(WorkItem::create(this, &amp;Connection::readEventHandler));

    return true;
}
</pre>
<p>Finally, <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebContext.cpp" target="_blank"><code>WebContext::processDidFinishLaunching</code></a> is called to do some preparation for its internal history and pending IPC messages.</p>
<pre class="brush: cpp; title: ; notranslate">
void WebContext::processDidFinishLaunching(WebProcessProxy* process)
{
    // FIXME: Once we support multiple processes per context, this assertion won't hold.
    ASSERT(process == m_process);

    m_visitedLinkProvider.populateVisitedLinksIfNeeded();

    for (size_t i = 0; i != m_pendingMessagesToPostToInjectedBundle.size(); ++i) {
        pair&lt;String, RefPtr&lt;APIObject&gt; &gt;&amp; message = m_pendingMessagesToPostToInjectedBundle[i];
        m_process-&gt;send(InjectedBundleMessage::PostMessage, 0, CoreIPC::In(message.first, WebContextUserMessageEncoder(message.second.get())));
    }
    m_pendingMessagesToPostToInjectedBundle.clear();
}
</pre>
<p>The above call stack is what happens when a new <code>WebContext</code> is initialized in <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserView.cpp" target="_blank"><code>BrowserView::create</code></a>. The next thing it does is to call the <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/WKPageNamespace.cpp" target="_blank"><code>WKPageNamespaceCreate</code></a> API.</p>
<pre class="brush: cpp; title: ; notranslate">
WKPageNamespaceRef WKPageNamespaceCreate(WKContextRef ownerContextRef)
{
    return toAPI(toImpl(ownerContextRef)-&gt;createPageNamespace());
}
</pre>
<p>It calls <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebContext.cpp" target="_blank"><code>WebContext::createPageNamespace</code></a> then <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebPageNamespace.h" target="_blank"><code>WebPageNamespace::create</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
class WebPageNamespace : public APIObject {
public:
    static const Type APIType = TypePageNamespace;

    static PassRefPtr&lt;WebPageNamespace&gt; create(WebContext* context)
    {
        return adoptRef(new WebPageNamespace(context));
    }
</pre>
<p>For now it seems <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebPageNamespace.cpp" target="_blank"><code>WebPageNamespace</code></a> does nothing when created except for some reference counting.</p>
<pre class="brush: cpp; title: ; notranslate">
#ifndef NDEBUG
static WTF::RefCountedLeakCounter webPageNamespaceCounter(&quot;WebPageNamespace&quot;);
#endif

WebPageNamespace::WebPageNamespace(WebContext* context)
    : m_context(context)
{
#ifndef NDEBUG
    webPageNamespaceCounter.increment();
#endif
}
</pre>
<p>After creating a namespace for scripting, <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserView.cpp" target="_blank"><code>BrowserView::create</code></a> calls the <code>WKViewCreate</code> API. For Windows, it&#8217;s just a <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/win/WKView.cpp" target="_blank">call</a> to <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/win/WebView.h" target="_blank"><code>WebView::create</code></a> which instanciates <code>WebView</code> via its <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/win/WebView.cpp" target="_blank">constructor</a>.</p>
<pre class="brush: cpp; title: ; notranslate">
WKViewRef WKViewCreate(RECT rect, WKPageNamespaceRef pageNamespaceRef, HWND parentWindow)
{
    RefPtr&lt;WebView&gt; view = WebView::create(rect, toImpl(pageNamespaceRef), parentWindow);
    return toAPI(view.release().releaseRef());
}
</pre>
<pre class="brush: cpp; title: ; notranslate">
class WebView : public APIObject, public PageClient, WebCore::WindowMessageListener {
public:
    static PassRefPtr&lt;WebView&gt; create(RECT rect, WebPageNamespace* pageNamespace, HWND parentWindow)
    {
        return adoptRef(new WebView(rect, pageNamespace, parentWindow));
    }
    ~WebView();

// snip

virtual HWND nativeWindow();

    // WebCore::WindowMessageListener
    virtual void windowReceivedMessage(HWND, UINT message, WPARAM, LPARAM);

    RECT m_rect;
    HWND m_window;
    HWND m_topLevelParentWindow;
    HWND m_toolTipWindow;

    HCURSOR m_lastCursorSet;
    HCURSOR m_webCoreCursor;
    HCURSOR m_overrideCursor;

    bool m_trackingMouseLeave;
    bool m_isBeingDestroyed;

    RefPtr&lt;WebPageProxy&gt; m_page;
};
</pre>
<pre class="brush: cpp; title: ; notranslate">
WebView::WebView(RECT rect, WebPageNamespace* pageNamespace, HWND parentWindow)
    : m_rect(rect)
    , m_topLevelParentWindow(0)
    , m_toolTipWindow(0)
    , m_lastCursorSet(0)
    , m_webCoreCursor(0)
    , m_overrideCursor(0)
    , m_trackingMouseLeave(false)
    , m_isBeingDestroyed(false)
{
    registerWebViewWindowClass();

    m_page = pageNamespace-&gt;createWebPage();
    m_page-&gt;setPageClient(this);
    m_page-&gt;setDrawingArea(ChunkedUpdateDrawingAreaProxy::create(this));

    m_window = ::CreateWindowEx(0, kWebKit2WebViewWindowClassName, 0, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
        rect.top, rect.left, rect.right - rect.left, rect.bottom - rect.top, parentWindow ? parentWindow : HWND_MESSAGE, 0, instanceHandle(), this);
    ASSERT(::IsWindow(m_window));

    m_page-&gt;initializeWebPage(IntRect(rect).size());

    ::ShowWindow(m_window, SW_SHOW);

    // FIXME: Initializing the tooltip window here matches WebKit win, but seems like something
    // we could do on demand to save resources.
    initializeToolTipWindow();

    // Initialize the top level parent window and register it with the WindowMessageBroadcaster.
    windowAncestryDidChange();
}
</pre>
<p><code>WebView</code> has a native window handle (HWND) and a reference to a <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebPageProxy.h" target="_blank"><code>WebPageProxy</code></a> object which is also initialized here. It has a <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/DrawingAreaProxy.h" target="_blank"><code>DrawingAreaProxy</code></a> as a member. Sometimes it receives an inter-process draw message via <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/WebPageProxy.cpp" target="_blank"><code>WebPageProxy::didReceiveMessage</code></a>. <code>DrawingAreaProxy</code> is the proxy in the UI Process to the <a href="http://trac.webkit.org/browser/trunk/WebKit2/WebProcess/WebPage/DrawingArea.h" target="_blank"><code>DrawingArea</code></a> object in a Web Process.</p>
<pre class="brush: cpp; title: ; notranslate">
void WebPageProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
{
    if (messageID.is&lt;CoreIPC::MessageClassDrawingAreaProxy&gt;()) {
        m_drawingArea-&gt;didReceiveMessage(connection, messageID, arguments);
        return;
    }

    didReceiveWebPageProxyMessage(connection, messageID, arguments);
}
</pre>
<p>From here on, I&#8217;ll show you what the graphics update loop is like in WebKit2. You&#8217;d notice that in <code>WebView::WebView</code> the <code>WebPageProxy</code> object is initialized with <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/ChunkedUpdateDrawingAreaProxy.h" target="_blank"><code>ChunkedUpdateDrawingAreaProxy</code></a> as its <code>DrawingAreaProxy</code> object. It is the default drawing strategy for the Windows version. It is a proxy to a <a href="http://trac.webkit.org/browser/trunk/WebKit2/WebProcess/WebPage/ChunkedUpdateDrawingArea.cpp" target="_blank"><code>ChunkedUpdateDrawingArea</code></a> object in a Web Process.</p>
<pre class="brush: cpp; title: ; notranslate">
ChunkedUpdateDrawingArea::ChunkedUpdateDrawingArea(DrawingAreaID identifier, WebPage* webPage)
    : DrawingArea(ChunkedUpdateDrawingAreaType, identifier, webPage)
    , m_isWaitingForUpdate(false)
    , m_paintingIsSuspended(false)
    , m_displayTimer(WebProcess::shared().runLoop(), this, &amp;ChunkedUpdateDrawingArea::display)
{
}

// snip

void ChunkedUpdateDrawingArea::scheduleDisplay()
{
    if (m_paintingIsSuspended)
        return;

    if (m_isWaitingForUpdate)
        return;

    if (m_dirtyRect.isEmpty())
        return;

    if (m_displayTimer.isActive())
        return;

    m_displayTimer.startOneShot(0);
}
</pre>
<p>It schedules the first update of the drawing area by pushing the <code>ChunkedUpdateDrawingArea::display</code> function into the <code>RunLoop</code>.</p>
<pre class="brush: cpp; title: ; notranslate">
void ChunkedUpdateDrawingArea::display()
{
    ASSERT(!m_isWaitingForUpdate);

    if (m_paintingIsSuspended)
        return;

    if (m_dirtyRect.isEmpty())
        return;

    // Layout if necessary.
    m_webPage-&gt;layoutIfNeeded();

    IntRect dirtyRect = m_dirtyRect;
    m_dirtyRect = IntRect();

    // Create a new UpdateChunk and paint into it.
    UpdateChunk updateChunk(dirtyRect);
    paintIntoUpdateChunk(&amp;updateChunk);

    WebProcess::shared().connection()-&gt;send(DrawingAreaProxyMessage::Update, m_webPage-&gt;pageID(), CoreIPC::In(updateChunk));

    m_isWaitingForUpdate = true;
    m_displayTimer.stop();
}
</pre>
<p>When there is a dirty rect as the result of modified page layout, it creates an <code>UpdateChunk</code> object. The Windows version of <a href="http://trac.webkit.org/browser/trunk/WebKit2/Shared/win/UpdateChunk.cpp" target="_blank"><code>UpdateChunk</code></a> is a shared memory bitmap created with the <a href="http://msdn.microsoft.com/en-us/library/aa366537.aspx" target="_blank"><code>CreateFileMapping</code></a> API to make it accessible from multiple processes. Then the content of the dirty rect is written into the bitmap with <a href="http://trac.webkit.org/browser/trunk/WebKit2/WebProcess/WebPage/win/ChunkedUpdateDrawingAreaWin.cpp" target="_blank"><code>ChunkedUpdateDrawingArea::paintIntoUpdateChunk</code></a>.</p>
<pre class="brush: cpp; title: ; notranslate">
UpdateChunk::UpdateChunk(const IntRect&amp; rect)
    : m_rect(rect)
{
    // Create our shared memory mapping.
    unsigned memorySize = rect.height() * rect.width() * 4;
    m_bitmapSharedMemory = ::CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, memorySize, 0);
}
</pre>
<pre class="brush: cpp; title: ; notranslate">
void ChunkedUpdateDrawingArea::paintIntoUpdateChunk(UpdateChunk* updateChunk)
{
    OwnPtr&lt;HDC&gt; hdc(::CreateCompatibleDC(0));

    void* bits;
    BitmapInfo bmp = BitmapInfo::createBottomUp(updateChunk-&gt;rect().size());
    OwnPtr&lt;HBITMAP&gt; hbmp(::CreateDIBSection(0, &amp;bmp, DIB_RGB_COLORS, &amp;bits, updateChunk-&gt;memory(), 0));

    HBITMAP hbmpOld = static_cast&lt;HBITMAP&gt;(::SelectObject(hdc.get(), hbmp.get()));

    GraphicsContext gc(hdc.get());
    gc.save();

    // FIXME: Is this white fill needed?
    RECT rect = updateChunk-&gt;rect();
    ::FillRect(hdc.get(), &amp;rect, (HBRUSH)::GetStockObject(WHITE_BRUSH));
    gc.translate(-updateChunk-&gt;rect().x(), -updateChunk-&gt;rect().y());

    m_webPage-&gt;drawRect(gc, updateChunk-&gt;rect());

    gc.restore();

    // Re-select the old HBITMAP
    ::SelectObject(hdc.get(), hbmpOld);
}
</pre>
<p>When it&#8217;s done, the <code>DrawingAreaProxyMessage::Update</code> IPC message is sent to the <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/ChunkedUpdateDrawingAreaProxy.h" target="_blank"><code>ChunkedUpdateDrawingAreaProxy</code></a> in the UI Process with the bitmap created. It receives the message in <code>ChunkedUpdateDrawingAreaProxy::didReceiveMessage</code> and decodes the bitmap packed as an IPC payload.</p>
<pre class="brush: cpp; title: ; notranslate">
void ChunkedUpdateDrawingAreaProxy::update(UpdateChunk* updateChunk)
{
    if (!m_isVisible) {
        // We got an update request that must have been sent before we told the web process to suspend painting.
        // Don't paint this into the backing store, because that could leave the backing store in an inconsistent state.
        // Instead, we will just tell the drawing area to repaint everything when we resume painting.
        m_forceRepaintWhenResumingPainting = true;
    } else {
        // Just paint into backing store.
        drawUpdateChunkIntoBackingStore(updateChunk);
    }

    WebPageProxy* page = this-&gt;page();
    page-&gt;process()-&gt;send(DrawingAreaMessage::DidUpdate, page-&gt;pageID(), CoreIPC::In(info().id));
}

void ChunkedUpdateDrawingAreaProxy::didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
{
    switch (messageID.get&lt;DrawingAreaProxyMessage::Kind&gt;()) {
        case DrawingAreaProxyMessage::Update: {
            UpdateChunk updateChunk;
            if (!arguments-&gt;decode(updateChunk))
                return;

            update(&amp;updateChunk);
            break;
        }
        case DrawingAreaProxyMessage::DidSetSize: {
            UpdateChunk updateChunk;
            if (!arguments-&gt;decode(CoreIPC::Out(updateChunk)))
                return;

            didSetSize(&amp;updateChunk);
            break;
        }
        default:
            ASSERT_NOT_REACHED();
    }
}
</pre>
<p>Then, in <code>ChunkedUpdateDrawingAreaProxy::update</code> it calls <code>ChunkedUpdateDrawingAreaProxy::drawUpdateChunkIntoBackingStore</code> to BitBlt from the updated image to the backing store.</p>
<pre class="brush: cpp; title: ; notranslate">
void ChunkedUpdateDrawingAreaProxy::drawUpdateChunkIntoBackingStore(UpdateChunk* updateChunk)
{
    ensureBackingStore();

    OwnPtr&lt;HDC&gt; updateChunkBitmapDC(::CreateCompatibleDC(m_backingStoreDC.get()));

    // Create a bitmap.
    BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(updateChunk-&gt;rect().size());

    // Duplicate the update chunk handle.
    HANDLE updateChunkHandle;
    BOOL result = ::DuplicateHandle(m_webView-&gt;page()-&gt;process()-&gt;processIdentifier(), updateChunk-&gt;memory(),
                                    ::GetCurrentProcess(), &amp;updateChunkHandle, STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ | FILE_MAP_WRITE, false, DUPLICATE_CLOSE_SOURCE);

    void* pixels = 0;
    OwnPtr&lt;HBITMAP&gt; hBitmap(::CreateDIBSection(0, &amp;bitmapInfo, DIB_RGB_COLORS, &amp;pixels, updateChunkHandle, 0));
    ::SelectObject(updateChunkBitmapDC.get(), hBitmap.get());

    // BitBlt from the UpdateChunk to the backing store.
    ::BitBlt(m_backingStoreDC.get(), updateChunk-&gt;rect().x(), updateChunk-&gt;rect().y(), updateChunk-&gt;rect().width(), updateChunk-&gt;rect().height(), updateChunkBitmapDC.get(), 0, 0, SRCCOPY);

    // FIXME: We should not do this here.
    ::CloseHandle(updateChunkHandle);

    // Invalidate the WebView's HWND.
    RECT rect = updateChunk-&gt;rect();
    ::InvalidateRect(m_webView-&gt;window(), &amp;rect, false);
}
</pre>
<p>As the event notification, the <code>DrawingAreaMessage::DidUpdate</code> IPC message is sent to the Web Process which triggers a subsequent drawing operation.</p>
<p>Now the page view is ready. After that, in <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/win/BrowserView.cpp" target="_blank"><code>BrowserView::create</code></a>, it sets application-defined callbacks with the <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/WKPage.h" target="_blank"><code>WKPageSetPageUIClient</code></a> API to invoke appropriate UI elements on events returned from WebKit.</p>
<pre class="brush: cpp; title: ; notranslate">
WKPageUIClient uiClient = {
        0,              /* version */
        parentWindow,   /* clientInfo */
        createNewPage,
        showPage,
        closePage,
        runJavaScriptAlert,
        runJavaScriptConfirm,
        runJavaScriptPrompt,
        setStatusText,
        mouseDidMoveOverElement,
        0,          /* didNotHandleKeyEvent */
        0,          /* toolbarsAreVisible */
        0,          /* setToolbarsAreVisible */
        0,          /* menuBarIsVisible */
        0,          /* setMenuBarIsVisible */
        0,          /* statusBarIsVisible */
        0,          /* setStatusBarIsVisible */
        0,          /* isResizable */
        0,          /* setIsResizable */
        0,          /* getWindowFrame */
        0,          /* setWindowFrame */
        0,          /* runBeforeUnloadConfirmPanel */
        0,          /* didDraw */
        0           /* pageDidScroll */
    };

    WKPageSetPageUIClient(WKViewGetPage(m_webView), &amp;uiClient);
</pre>
<p>Though this article uses the Windows version as the primary example, the <a href="http://trac.webkit.org/browser/trunk/WebKitTools/MiniBrowser/mac/BrowserWindowController.m" target="_blank">Mac version of MiniBrowser</a> in Objective-C has more features implemented already by using other WebKit2 APIs. Besides <code>WKPageUIClient</code>, <a href="http://trac.webkit.org/browser/trunk/WebKit2/UIProcess/API/C/WKPage.h" target="_blank"><code>WKPage.h</code></a> offers other kinds of clients such as <code>WKPageLoaderClient</code>, <code>WKPagePolicyClient</code> and <code>WKPageFindClient</code> for embedders to customize the application behavior by defining and plugging in their own callback functions.</p>
<p>As for other multiprocess-related implementation details, the Web Process has a <a href="http://trac.webkit.org/browser/trunk/WebKit2/Shared/VisitedLinkTable.cpp" target="_blank"><code>VisitedLinkTable</code></a> object as its member. Its hash table is on the <a href="http://trac.webkit.org/browser/trunk/WebKit2/Platform/win/SharedMemoryWin.cpp?" target="_blank"><code>SharedMemory</code></a> object for cross-process update.</p>
<p>Examples of WebKit2 usage are also found in the <a href="http://trac.webkit.org/browser/trunk/WebKitTools/TestWebKitAPI/Tests/WebKit2" target="_blank">tests for the WebKit2 API</a> so browse them if you are interested.</p>
<p>Since WebKit2 is in its very early stage, the code size is still kept compact so reading its source code and comprehending its structure is super easy and fun. Going back to my original question at the beginning of this article, it seems the basic functions of WebKit2 are all in after 6 months. Though my personal attention has been on Chromium development rather than on WebKit, it may be interesting to see how these 2 interact each other in future.</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2010/10/11/webkit2-implementation-overview-as-of-october-2010-2-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preliminary Look into libevent 2 for Windows</title>
		<link>http://zzz.zggg.com/2010/09/10/preliminary-look-into-libevent2-for-windows/</link>
		<comments>http://zzz.zggg.com/2010/09/10/preliminary-look-into-libevent2-for-windows/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 14:02:13 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=493</guid>
		<description><![CDATA[The libevent library is probably best known by its use in memcached. memcached is one of the key components of [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://monkey.org/~provos/libevent/" target="_blank">libevent</a> library is probably best known by its use in <a href="http://memcached.org/" target="_blank">memcached</a>. memcached is one of the key components of LAMP stack though the recent trend seems to instead highlight NoSQL solutions where typical RDBMS and memcached are replaced with more optimized and dedicated systems. The importance of libevent is not affected at all since libevent itself is not tied to applications that use it and NoSQL solutions can be constructed with libevent too. Other clients of libevent include <a href="http://www.torproject.org/" target="_blank">Tor</a>. libevent is crucial for its cross-platform availability. After all, one of the developers of libevent is Nick Mathewson who is also the head honcho behind the Tor project.</p>
<p>My interest in libevent comes from my own program, <a href="http://zzz.zggg.com/dice/" target="_blank">DICE</a>. From the beginning of the development in 2002, its I/O is fully optimized to Windows and <a href="http://msdn.microsoft.com/en-us/library/aa365198.aspx" target="_blank">I/O Completion Ports</a> (IOCP) without using any middleware or libraries. It&#8217;s old and not often updated, but works flawlessly. However, replacing it with a decent OSS library can be a good chance to make it more simple and robust. The concern from the performance point of view is the only obstacle left, but libevent 2 is supposed to come with the IOCP support. That was the news that let me start the evaluation.</p>
<p>The libevent version for this article is 2.0.7 RC. I built it with Visual Studio 2010 (VC10). Since I wanted to use the debugger to trace its flow, I built it as the debug version by changing the CFLAGS compiler options <code>/Ox</code> to <code>/Od /MDd /Zi</code> in the Makefile.nmake in the main directory and the test directory. &#8216;<code>nmake -f Makefile.nmake</code>&#8216; produces the libevent.lib static library.</p>
<p>Before building a project with libevent, you need to manually copy WIN32-Code\event2\event-config.h to include\event2\event-config.h. Then add libevent.lib to the linker input (if you use socket, ws2_32.lib too), and add libevent and libevent\include directories to the include directory.</p>
<p>Then I wrote a test code with its evhttp &#8216;Event-driven HTTP servers&#8217; functions. It&#8217;s a simple Web server that shows requested URI and quits if /quit is requested. It listens to the port 8080.</p>
<p><span id="more-493"></span></p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;iostream&gt;
#include &lt;cmath&gt;
#include &lt;ctime&gt;

#include &lt;event.h&gt;
#include &lt;evhttp.h&gt;
#include &lt;event2/thread.h&gt;

void handlerRoot(evhttp_request* request, void* args)
{
	std::cout &lt;&lt; &quot;Request URI: &quot; &lt;&lt; request-&gt;uri &lt;&lt; std::endl;

	evbuffer* buffer = evbuffer_new();

	evkeyvalq* headers = evhttp_request_get_output_headers(request);
	evhttp_add_header(headers, &quot;Content-Type&quot;, &quot;text/html; charset=UTF-8&quot;);
	evbuffer_add_printf(buffer, &quot;Request URI: %s&quot;, request-&gt;uri);

	evhttp_send_reply(request, HTTP_OK, &quot;OK&quot;, buffer);

	evbuffer_free(buffer);
}

void handlerQuit(evhttp_request* request, void* args)
{
	event_base* eventBase = (event_base*)args;
	event_base_loopbreak(eventBase);
}

int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData = {0};
	::WSAStartup(MAKEWORD(2, 2), &amp;wsaData);

	event_config* eventConfig = event_config_new();
	event_config_set_flag(eventConfig, EVENT_BASE_FLAG_STARTUP_IOCP);
	event_config_set_num_cpus_hint(eventConfig, 8);

	event_base* eventBase = event_base_new_with_config(eventConfig);

	evthread_use_windows_threads();

	evhttp* eventHttp = evhttp_new(eventBase);

	evhttp_set_gencb(eventHttp, handlerRoot, eventBase);
	evhttp_set_cb(eventHttp, &quot;/quit&quot;, handlerQuit, eventBase);

	evhttp_bind_socket(eventHttp, &quot;0.0.0.0&quot;, 8080);

	timeval tv = {::pow(2.0, 31) - ::time(NULL) - 1000, 0};

	event_base_loopexit(eventBase, &amp;tv);

	event_base_dispatch(eventBase);

	evhttp_free(eventHttp);
	event_base_free(eventBase);

	::WSACleanup();

	return 0;
}
</pre>
<p>The document is not yet complete for the recently added functions and I had to read the libevent code to add some function calls that enable IOCP. As the whatsnew-2.0.txt suggests, it&#8217;s disabled by default. The wierdest part is probably this:</p>
<pre class="brush: cpp; title: ; notranslate">
	timeval tv = {::pow(2.0, 31) - ::time(NULL) - 1000, 0};

	event_base_loopexit(eventBase, &amp;tv);

	event_base_dispatch(eventBase);
</pre>
<p><code>event_base_dispatch</code> starts the event dispatching loop, but if you enable IOCP it doesn&#8217;t block and the program just exits. So you have to manually set its lifetime. I tried to set the largest signed integer (::pow(2.0, 31)), but unfortunately <code>event_base_loopexit</code> internally calls <code>event_base_once</code> which calls <code>event_add_internal</code> with tv_is_absolute = 0. The tricky code above is just a quick fix.</p>
<pre class="brush: cpp; title: ; notranslate">
/* Implementation function to add an event.  Works just like event_add,
 * except: 1) it requires that we have the lock.  2) if tv_is_absolute is set,
 * we treat tv as an absolute time, not as an interval to add to the current
 * time */
static inline int
event_add_internal(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
</pre>
<p><code>event_config_set_num_cpus_hint</code> sets the CPU number as 8, it&#8217;s because I use Core i7 with 8 SMT threads. Internally, it spawns (num_cpus * 2) threads in its thread pool for IOCP.</p>
<pre class="brush: cpp; title: ; notranslate">
struct event_iocp_port *
event_iocp_port_launch(int n_cpus)
{
	struct event_iocp_port *port;
	int i;

	if (!extension_fns_initialized)
		init_extension_functions(&amp;the_extension_fns);

	if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
		return NULL;

	if (n_cpus &lt;= 0)
		n_cpus = N_CPUS_DEFAULT;
	port-&gt;n_threads = n_cpus * 2;
	port-&gt;threads = calloc(port-&gt;n_threads, sizeof(HANDLE));
	if (!port-&gt;threads)
		goto err;

	port-&gt;port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
			n_cpus);
	port-&gt;ms = -1;
	if (!port-&gt;port)
		goto err;

	port-&gt;shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
	if (!port-&gt;shutdownSemaphore)
		goto err;

	for (i=0; i&lt;port-&gt;n_threads; ++i) {
		ev_uintptr_t th = _beginthread(loop, 0, port);
		if (th == (ev_uintptr_t)-1)
			goto err;
		port-&gt;threads[i] = (HANDLE)th;
		++port-&gt;n_live_threads;
	}

	InitializeCriticalSectionAndSpinCount(&amp;port-&gt;lock, 1000);

	return port;
err:
	if (port-&gt;port)
		CloseHandle(port-&gt;port);
	if (port-&gt;threads)
		mm_free(port-&gt;threads);
	if (port-&gt;shutdownSemaphore)
		CloseHandle(port-&gt;shutdownSemaphore);
	mm_free(port);
	return NULL;
}
</pre>
<p>The threads in the pool then block with <a href="http://msdn.microsoft.com/en-us/library/aa364986.aspx" target="_blank"><code>GetQueuedCompletionStatus</code></a> that waits for I/O completion notification.</p>
<pre class="brush: cpp; title: ; notranslate">
static void
loop(void *_port)
{
	struct event_iocp_port *port = _port;
	long ms = port-&gt;ms;
	HANDLE p = port-&gt;port;

	if (ms &lt;= 0)
		ms = INFINITE;

	while (1) {
		OVERLAPPED *overlapped=NULL;
		ULONG_PTR key=0;
		DWORD bytes=0;
		int ok = GetQueuedCompletionStatus(p, &amp;bytes, &amp;key,
			&amp;overlapped, ms);
		EnterCriticalSection(&amp;port-&gt;lock);
		if (port-&gt;shutdown) {
			if (--port-&gt;n_live_threads == 0)
				ReleaseSemaphore(port-&gt;shutdownSemaphore, 1,
						NULL);
			LeaveCriticalSection(&amp;port-&gt;lock);
			return;
		}
		LeaveCriticalSection(&amp;port-&gt;lock);

		if (key != NOTIFICATION_KEY &amp;&amp; overlapped)
			handle_entry(overlapped, key, bytes, ok);
		else if (!overlapped)
			break;
	}
	event_warnx(&quot;GetQueuedCompletionStatus exited with no event.&quot;);
	EnterCriticalSection(&amp;port-&gt;lock);
	if (--port-&gt;n_live_threads == 0)
		ReleaseSemaphore(port-&gt;shutdownSemaphore, 1, NULL);
	LeaveCriticalSection(&amp;port-&gt;lock);
}
</pre>
<p>So I built the above code and ran it. It worked. But when I set breakpoints in the debugger, it turned out that things were not working as expected. It breaks at the line after <code>GetQueuedCompletionStatus</code> only when accepting a new connection. I suspected only the accept operation was overlapped.</p>
<pre class="brush: cpp; title: ; notranslate">
static int
start_accepting(struct accepting_socket *as)
{
	/* requires lock */
	const struct win32_extension_fns *ext = event_get_win32_extension_fns();
	DWORD pending = 0;
	SOCKET s = socket(as-&gt;family, SOCK_STREAM, 0);
	if (s == INVALID_SOCKET)
		return -1;

	setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
	    (char *)&amp;as-&gt;lev-&gt;fd, sizeof(&amp;as-&gt;lev-&gt;fd));

	if (!(as-&gt;lev-&gt;base.flags &amp; LEV_OPT_LEAVE_SOCKETS_BLOCKING))
		evutil_make_socket_nonblocking(s);

	if (event_iocp_port_associate(as-&gt;lev-&gt;port, s, 1) &lt; 0) {
		closesocket(s);
		return -1;
	}

	as-&gt;s = s;

	if (ext-&gt;AcceptEx(as-&gt;lev-&gt;fd, s, as-&gt;addrbuf, 0,
		as-&gt;buflen/2, as-&gt;buflen/2, &amp;pending, &amp;as-&gt;overlapped.overlapped))
	{
		/* Immediate success! */
		accepted_socket_cb(&amp;as-&gt;overlapped, 1, 0, 1);
	} else {
		int err = WSAGetLastError();
		if (err != ERROR_IO_PENDING) {
			event_warnx(&quot;AcceptEx: %s&quot;, evutil_socket_error_to_string(err));
			return -1;
		}
	}

	return 0;
}
</pre>
<p>In the debugger, it surely calls <a href="http://msdn.microsoft.com/en-us/library/ms737524.aspx" target="_blank"><code>AcceptEx</code></a> in <code>start_accepting</code>. The problem is, it uses the non-IOCP version of the read operation function.</p>
<pre class="brush: cpp; title: ; notranslate">
evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
{
// snip

#ifdef WIN32
		{
			DWORD bytesRead;
			DWORD flags=0;
			if (WSARecv(fd, vecs, nvecs, &amp;bytesRead, &amp;flags, NULL, NULL)) {
				/* The read failed. It might be a close,
				 * or it might be an error. */
				if (WSAGetLastError() == WSAECONNABORTED)
					n = 0;
				else
					n = -1;
			} else
				n = bytesRead;
		}
#else
		n = readv(fd, vecs, nvecs);
#endif
</pre>
<pre class="brush: cpp; title: ; notranslate">
int
evbuffer_launch_read(struct evbuffer *buf, size_t at_most,
		struct event_overlapped *ol)
{
// snip

	_evbuffer_incref(buf);
	if (WSARecv(buf_o-&gt;fd, buf_o-&gt;buffers, nvecs, &amp;bytesRead, &amp;flags,
		    &amp;ol-&gt;overlapped, NULL)) {
		int error = WSAGetLastError();
		if (error != WSA_IO_PENDING) {
			/* An actual error. */
			pin_release(buf_o, EVBUFFER_MEM_PINNED_R);
			evbuffer_unfreeze(buf, 0);
			evbuffer_free(buf); /* decref */
			goto done;
		}
	}
</pre>
<p>The latter one gives an <a href="http://msdn.microsoft.com/en-us/library/ms741665.aspx" target="_blank"><code>OVERLAPPED</code></a> structure to initiate overlapped read, but it was not actually called.</p>
<p>I tracked where it went wrong. The culprit was in <code>http.c</code>. It used the <code>bufferevent_new</code> that doesn&#8217;t support IOCP.</p>
<pre class="brush: cpp; title: ; notranslate">
struct evhttp_connection *
evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
    const char *address, unsigned short port)
{
// snip

	if ((evcon-&gt;bufev = bufferevent_new(-1,
		    evhttp_read_cb,
		    evhttp_write_cb,
		    evhttp_error_cb, evcon)) == NULL) {
		event_warn(&quot;%s: bufferevent_new failed&quot;, __func__);
		goto error;
	}
</pre>
<p>Instead, it has to use <code>bufferevent_socket_new</code>. But other parts of <code>http.c</code> have to be modified to work correctly, so I gave up there.</p>
<pre class="brush: cpp; title: ; notranslate">
struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
    int options)
{
	struct bufferevent_private *bufev_p;
	struct bufferevent *bufev;

#ifdef WIN32
	if (base &amp;&amp; event_base_get_iocp(base))
		return bufferevent_async_new(base, fd, options);
#endif
</pre>
<p>Though my time ran out, you may test if the async read/write does work or not by running the iocp/bufferevent_async and other regression tests defined in <code>regress_iocp.c</code> in the test folder. Don&#8217;t forget to add the <code>--no-fork</code> option.</p>
<p>Will it be improved? I hope so, these IOCP details should be hidden from a user.</p>
<p>Another thing to look at is the thread pool. Since Windows 2000, the <a href="http://msdn.microsoft.com/en-us/magazine/cc163327.aspx" target="_blank">thread pool</a> is an OS component that is optimized to the OS inner working. <a href="http://msdn.microsoft.com/en-us/library/aa363484.aspx" target="_blank"><code>BindIoCompletionCallback</code></a> is available since Windows 2000, and <a href="http://msdn.microsoft.com/en-us/library/ms682456.aspx" target="_blank"><code>CreateThreadpool</code></a> and other related API have been added in Windows Vista. It seems it&#8217;s still far away that libevent is fully optimized to Windows.</p>
<p>However, as an easy-going framework to save time, it&#8217;s in a good state already as shown in my example. A bit more polishing will make it shine.</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2010/09/10/preliminary-look-into-libevent2-for-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>js-ctypes実装に見るlibffiの利用(&amp; Windows-MSVCでのビルド法)</title>
		<link>http://zzz.zggg.com/2010/08/26/playing-with-js-ctypes-libffi-msvc/</link>
		<comments>http://zzz.zggg.com/2010/08/26/playing-with-js-ctypes-libffi-msvc/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 19:48:08 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=333</guid>
		<description><![CDATA[Firefox 3.6から入った、chrome権限のJavaScriptから外部バイナリコンポーネントのネイティブ関数を呼び出す機構であるjs-ctypesの実装が、libffiに基づいているということだったので、昔見た [...]]]></description>
			<content:encoded><![CDATA[<p>Firefox 3.6から入った、chrome権限のJavaScriptから外部バイナリコンポーネントのネイティブ関数を呼び出す機構である<a href="https://wiki.mozilla.org/JSctypes" target="_blank">js-ctypes</a>の実装が、<a href="http://sourceware.org/libffi/" target="_blank">libffi</a>に基づいているということだったので、昔見たときはlibffiはVisual C++はサポートしてなかった記憶があったがFirefoxでビルドできるんだったら単体でもいけるよねーということで<a href="http://mxr.mozilla.org/mozilla-central/source/js/src/ctypes/" target="_blank">js-ctypesのソース</a>を追いつつ試してみた。</p>
<p>結果から先に述べると、若干手間を要するものの問題なくビルドでき、closureも利用できた。ここでいうclosureとは、呼び出された際にユーザー指定コールバック関数(元の呼び出しに使われたlibffiフォーマットの引数データが渡ってくる)を起動してくれる関数コードを、ユーザーが動的に指定したシグニチャで、ランタイムに実行可能メモリ上に構築してくれるlibffiのAPIが用意されているので、それを利用して作成したバイナリコードを指す。</p>
<p>js-ctypes実装の構造は至極直截的で、JSのオブジェクトとネイティブオブジェクトのバインダとしての<a href="http://mxr.mozilla.org/mozilla-central/source/js/src/ctypes/CTypes.h" target="_blank"><code>CTypes</code>クラス</a>と、dll/so/dylibみたいなバイナリコンポーネントのラッパーの<a href="http://mxr.mozilla.org/mozilla-central/source/js/src/ctypes/Library.h" target="_blank"><code>Library</code>クラス</a>から成っている。<code>Library::Declare</code>でシンボルからバイナリ内の関数アドレスを得るときは、<code>PR_FindFunctionSymbol</code>を呼ぶ。これは<a href="http://www.mozilla.org/projects/nspr/" target="_blank">NSPR</a>の関数で、Windows上では、なんのことはない<a href="http://mxr.mozilla.org/mozilla-central/source/nsprpub/pr/src/linking/prlink.c" target="_blank"><code>GetProcAddress</code>が呼ばれる</a>。なんでlibffiなんてものが必要かというと、荒っぽく言ってしまえば、Cでは関数ポインタを宣言しておけばコンパイラが良きに計らってくれるところ、動的言語で同じことをランタイムに行うために、その辺の呼び出し規約上のお膳立てをlibffiが整えてくれるというわけだ。</p>
<p>上述のclosureは、js-ctypesでは、ネイティブコード側にJavascriptの関数をコールバックとして渡す時に利用されている。Javascript関数オブジェクトに関連づけたclosureを作成し、それが呼び出された場合には<a href="http://mxr.mozilla.org/mozilla-central/source/js/src/ctypes/CTypes.cpp" target="_blank"><code>CClosure::ClosureStub</code></a>が呼び出され、関連づけられていたJavascript関数オブジェクトが実行されるようになっている。closureは、コールバック用のプロキシとして働いており、この利用法自体は、<a href="http://github.com/atgreen/libffi/blob/master/src/x86/ffi.c" target="_blank">libffiの実装</a>内でffi_prep_closure_locの実体がFFI_INIT_TRAMPOLINE呼び出しで、closure用のメモリ領域が「トランポリン」と呼ばれていることからわかるように、想定の範囲内と言える。</p>
<p>Windowsアプリのメッセージハンドラ=ウィンドウプロシージャとしておなじみの<a href="http://msdn.microsoft.com/en-us/library/ms633573.aspx" target="_blank"><code>WindowProc</code></a>コールバックは、js-ctypesでは以下のように表現される。</p>
<pre class="brush: jscript; title: ; notranslate">
var WNDPROC = ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int, [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;
</pre>
<p>Windows APIの呼び出し規約は<code>WINAPI(__stdcall)</code>なので<code>stdcall_abi</code>が指定されている。これを元にしてlibffiがclosureを作成し、closureが起動されるとjs-ctypesが再度Javascriptの関数に戻して実行してやる。これが何を意味するかというと、js-ctypesがあればJavascriptでWindowsアプリのイベント駆動モデルすらも代替できる、つまりMFCとかイラネーよなということになる。これだけ強力なら、<a href="https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0" target="_blank">Firefox 4のGecko 2がfrozenインターフェイスを破棄</a>してjs-ctypesを媒介にXPCOMを脱構築するという流れも必然であると納得できる。</p>
<p>Windows上でのVisual Studio 2010(VC10)を使ったlibffiのビルド手順としては、以下になる:</p>
<p><span id="more-333"></span></p>
<ol>
<li>Cygwinをインストール。デフォルトのパッケージに加え、Develのmakeが必要なので含めておく。(msysはcygpathが無いので駄目)</li>
<li>Gitをインストール。改行コードの扱いは、チェックアウト=as-is、チェックイン=LFで。cygwinのshは、configureやconfig.sub等のスクリプトが改行コードLFでないと処理できないため。</li>
<li>Gitで<a href="http://github.com/atgreen/libffi" target="_blank">libffiのGitHubレポジトリ</a>からソース取得。</li>
<li>Visual StudioのVisual Studio Toolsからコマンドプロンプトを起動。Cygwinのフォルダに移動し、Cygwin.batを起動。bash内で/cygdrive/の中のlibffiのソースが置いてあるディレクトリへ移動。</li>
<li>configureオプションについては、libffiのREADME内に簡単な指示はあるものの、Firefoxでのjs-ctypes用<a href="http://mxr.mozilla.org/mozilla-central/source/js/src/configure.in">configure.in</a>を参考にすべきだろう。
<pre class="brush: bash; title: ; notranslate">
# Build jsctypes if it's enabled.
if test &quot;$JS_HAS_CTYPES&quot;; then
  # Run the libffi 'configure' script.
  ac_configure_args=&quot;--disable-shared --enable-static --disable-raw-api&quot;
  if test &quot;$MOZ_DEBUG&quot;; then
    ac_configure_args=&quot;$ac_configure_args --enable-debug&quot;
  fi
  if test &quot;$DSO_PIC_CFLAGS&quot;; then
    ac_configure_args=&quot;$ac_configure_args --with-pic&quot;
  fi
  if test &quot;$CROSS_COMPILE&quot;; then
    case &quot;$target&quot; in
    *-mingw*)
      ac_configure_args=&quot;$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\&quot;$HOST_CC\&quot; CC=\&quot;$CC\&quot;&quot;
      ;;
    *-android*)
      CFLAGS=&quot;$ANDROID_CFLAGS&quot;
      CPPFLAGS=&quot;$ANDROID_CPPFLAGS&quot;
      LDFLAGS=&quot;$ANDROID_LDFLAGS&quot;

      export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS

      ac_configure_args=&quot;$ac_configure_args --build=$build --host=${target_cpu}-${target_os} HOST_CC=\&quot;$HOST_CC\&quot;&quot;
      ;;
    *)
      ac_configure_args=&quot;$ac_configure_args --build=$build --host=$target HOST_CC=\&quot;$HOST_CC\&quot; CC=\&quot;$CC\&quot;&quot;
      ;;
    esac
  fi
  if test &quot;$_MSC_VER&quot;; then
    # Use a wrapper script for cl and ml that looks more like gcc.
    # autotools can't quite handle an MSVC build environment yet.
    ac_configure_args=&quot;$ac_configure_args LD=link CPP=\&quot;cl -nologo -EP\&quot; SHELL=sh.exe&quot;
    case &quot;${target_cpu}&quot; in
    x86_64)
      # Need target since MSYS tools into mozilla-build may be 32bit
      ac_configure_args=&quot;$ac_configure_args CC=\&quot;$_topsrcdir/ctypes/libffi/msvcc.sh -m64\&quot; --build=$build --host=$target&quot;
      ;;
    *)
      ac_configure_args=&quot;$ac_configure_args CC=$_topsrcdir/ctypes/libffi/msvcc.sh&quot;
      ;;
    esac
  fi
  if test &quot;$SOLARIS_SUNPRO_CC&quot;; then
    # Always use gcc for libffi on Solaris
    if test ! &quot;$HAVE_64BIT_OS&quot;; then
      ac_configure_args=&quot;$ac_configure_args CC=gcc CFLAGS=-m32&quot;
    else
      ac_configure_args=&quot;$ac_configure_args CC=gcc CFLAGS=-m64&quot;
    fi
  fi
  if test &quot;$OS_ARCH&quot; = &quot;OS2&quot;; then
    ac_configure_args=&quot;$ac_configure_args CFLAGS=-Zomf AR=emxomfar&quot;
  fi
  if test -n &quot;$MOZ_THUMB2&quot;; then
    ac_configure_args=&quot;$ac_configure_args --enable-thumb2&quot;
  fi

  # Use a separate cache file for libffi, since it does things differently
  # from our configure.
  mkdir -p $_objdir/ctypes/libffi
  old_cache_file=$cache_file
  cache_file=$_objdir/ctypes/libffi/config.cache
  old_config_files=$CONFIG_FILES
  unset CONFIG_FILES
  AC_OUTPUT_SUBDIRS(ctypes/libffi)
  cache_file=$old_cache_file
  ac_configure_args=&quot;$_SUBDIR_CONFIG_ARGS&quot;
  CONFIG_FILES=$old_config_files
fi
</pre>
<p>リリース版は<br />
<code>./configure --disable-shared --enable-static CC=./msvcc.sh LD=link CPP="cl -nologo -EP"</code><br />
デバッグ版は<br />
<code>./configure --disable-shared --enable-static --enable-debug CC=./msvcc.sh LD=link CPP="cl -nologo -EP"</code></li>
<li>ここでmakeしようとすると以下のエラーに遭遇する:<br />
<blockquote><p><code>makelibtool: compile:  ./msvcc.sh -DHAVE_CONFIG_H -I. -I. -I./include -Iinclude -I./<br />
src -Wall -g -fexceptions -O2 -c src\\debug.c  -DDLL_EXPORT -DPIC<br />
cl -MD -nologo -W3 -DHAVE_CONFIG_H -I. -I. -I./include -Iinclude -I./src -Zi -DE<br />
BUG -O2 -OPT:REF -OPT:ICF -INCREMENTAL:NO -c src\debug.c -DDLL_EXPORT -DPIC<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OP' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OT' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-O:' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OR' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OE' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OF' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OP' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OT' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-O:' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OI' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OC' を無視します<br />
cl : コマンド ライン warning D9002 : 不明なオプション '-OF' を無視します<br />
srcdebug.c<br />
c1 : fatal error C1083: ソース ファイルを開けません。'srcdebug.c': No such file or directory</code></p></blockquote>
<p>どうやらsrc\debug.cのバックスラッシュがおかしいというのがわかるので、libtool内の</p>
<pre class="brush: bash; title: ; notranslate">
# Fix the shell variable $srcfile for the compiler.
fix_srcfile_path=&quot;\`cygpath -w \&quot;\$srcfile\&quot;\`&quot;
</pre>
<p>の-wを-uに変更</li>
<li>ここでmakeしようとすると今度は以下のエラーに遭遇する:<br />
<blockquote><p><code>E:\program\src\libffi\libffi-github\include\ffitarget.h : warning C4819: ファイ<br />
ルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を<br />
防ぐために、ファイルを Unicode 形式で保存してください。<br />
E:\program\src\libffi\libffi-github\include\ffitarget.h(1) : error C2059: 構文エ<br />
ラー : '!'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(91) : error C2061: 構文エラー : 識別子 'size_t'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(92) : error C2061: 構文エラー : 識別子 'ValidBytesConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(92) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(97) : error C2061: 構文エラー : 識別子 'WritableElementsConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(97) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(98) : error C2061: 構文エラー : 識別子 'WritableBytesConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(98) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(103) : error C2061: 構文エラー : 識別子 'ElementSizeConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(103) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(107) : error C2059: 構文エラー : '}'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(122) : error C2061: 構文エラー : 識別子 'size_t'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(123) : error C2061: 構文エラー : 識別子 'ValidBytesConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(123) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(128) : error C2061: 構文エラー : 識別子 'WritableElementsConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(128) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(129) : error C2061: 構文エラー : 識別子 'WritableBytesConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(129) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(134) : error C2061: 構文エラー : 識別子 'ElementSizeConst'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(134) : error C2059: 構文エラー : ';'<br />
c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sour<br />
ceannotations.h(139) : error C2059: 構文エラー : '}'<br />
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\crtdefs.h(409) :<br />
error C2061: 構文エラー : 識別子 'rsize_t'<br />
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\crtdefs.h(409) :<br />
error C2059: 構文エラー : ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(97) : error C2016: C では、構<br />
造体または共用体に少なくとも 1 つのメンバーが必要です。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(97) : error C2061: 構文エラー<br />
: 識別子 'size_t'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(101) : error C2059: 構文エラー<br />
: '}'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(153) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_void'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(153) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(154) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_uint8'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(154) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(155) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_sint8'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(155) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(156) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_uint16'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(156) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(157) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_sint16'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(157) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(158) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_uint32'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(158) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(159) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_sint32'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(159) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(160) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_uint64'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(160) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(161) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_sint64'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(161) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(162) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_float'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(162) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(163) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_double'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(163) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(164) : error C2061: 構文エラー<br />
: 識別子 'ffi_type_pointer'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(164) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(182) : error C2016: C では、構<br />
造体または共用体に少なくとも 1 つのメンバーが必要です。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(182) : error C2061: 構文エラー<br />
: 識別子 'ffi_abi'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(184) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(185) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(191) : error C2059: 構文エラー<br />
: '}'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(208) : error C2016: C では、構<br />
造体または共用体に少なくとも 1 つのメンバーが必要です。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(208) : error C2061: 構文エラー<br />
: 識別子 'ffi_sarg'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(209) : error C2061: 構文エラー<br />
: 識別子 'uint'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(209) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(213) : error C2059: 構文エラー<br />
: '}'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(226) : error C2061: 構文エラー<br />
: 識別子 'ffi_java_raw'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(226) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(230) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(230) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(231) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(235) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2143: 構文エラー<br />
: ';' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(236) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2061: 構文エラー<br />
: 識別子 'ffi_raw_size'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(237) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(243) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(243) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(244) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(248) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2143: 構文エラー<br />
: ';' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(249) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2061: 構文エラー<br />
: 識別子 'ffi_java_raw_size'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2059: 構文エラー<br />
: ';'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(250) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(358) : error C2143: 構文エラー<br />
: ')' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(358) : error C2143: 構文エラー<br />
: '{' が '*' の前にありません。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(359) : error C2146: 構文エラー<br />
: ';' が、識別子 'abi' の前に必要です。<br />
E:\program\src\libffi\libffi-github\include\ffi.h(360) : error C2059: 構文エラー<br />
: '型'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(362) : error C2059: 構文エラー<br />
: ')'<br />
E:\program\src\libffi\libffi-github\include\ffi.h(362) : fatal error C1003: プロ<br />
グラム内のエラーが 100 個を超えました。コンパイルは中断されます。<br />
make[2]: *** [src/debug.lo] Error 1<br />
make[2]: Leaving directory `/cygdrive/e/program/src/libffi/libffi-github'<br />
make[1]: *** [all-recursive] Error 1<br />
make[1]: Leaving directory `/cygdrive/e/program/src/libffi/libffi-github'<br />
make: *** [all] Error 2</code></p></blockquote>
<p>include/ffitarget.hのsymlinkが機能していないことによるエラーなので、src/x86/ffitarget.hをinclude/ffitarget.hに上書きコピーする。</li>
<li>再度make。.libsにlibffi.libスタティックリンクライブラリができる。</li>
</ol>
<p>libffiを使うプロジェクトのリンカーインプットにlibffi.libを指定してやればビルドが通る。libffiの利用例は、testsuite内のコードを参照すればよい。</p>
<p>EnumWindows APIからclosureを呼び出すサンプルコードは以下。</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include &lt;ffi.h&gt;

static void closure_stub(ffi_cif* cif, void* resp, void** args, void* userdata)
{
	++(*((DWORD*)userdata));

	wchar_t buf[256];
	HWND hwnd = *(HWND*)(args[0]);

	if (::GetWindowTextW(hwnd, buf, 256) != 0 &amp;&amp; ::IsWindowVisible(hwnd))
	{
		::wprintf_s(L&quot;HWND: 0x%08x - %s\r\n&quot;, DWORD(hwnd), buf);
	}

	*(BOOL*)resp = TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
	::setlocale(LC_ALL, &quot;Japanese&quot;);

	void* code;
	ffi_closure* pcl = (ffi_closure*)ffi_closure_alloc(sizeof(ffi_closure), &amp;code);

	ffi_type* cl_arg_types[2];
	cl_arg_types[0] = &amp;ffi_type_pointer;
	cl_arg_types[1] = &amp;ffi_type_pointer;

	ffi_cif cif;
	_ASSERTE(ffi_prep_cif(&amp;cif, FFI_STDCALL, 2, &amp;ffi_type_uint32, cl_arg_types) == FFI_OK);

	static DWORD dwInvokeCount = 0;

	_ASSERTE(ffi_prep_closure_loc(pcl, &amp;cif, closure_stub, (void*)&amp;dwInvokeCount, code) == FFI_OK);

	_ASSERTE(::EnumWindows((WNDENUMPROC)code, NULL) != 0);

	::wprintf_s(L&quot;Closure - invoked %d times\r\n&quot;, dwInvokeCount);

	ffi_closure_free(pcl);

	return 0;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2010/08/26/playing-with-js-ctypes-libffi-msvc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>新BitTorrentプロトコルµTPを実装するlibutpソースコードの概観</title>
		<link>http://zzz.zggg.com/2010/07/11/peek-over-libutp-utp-implementation/</link>
		<comments>http://zzz.zggg.com/2010/07/11/peek-over-libutp-utp-implementation/#comments</comments>
		<pubDate>Sat, 10 Jul 2010 17:59:25 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=529</guid>
		<description><![CDATA[5月21日に、libutpソースコードがMITライセンスで公開された。libutpとは、µTP (Micro Transport Protocol)と呼ばれるプロトコルの実装ライブラリである(BitTorrent.org [...]]]></description>
			<content:encoded><![CDATA[<p>5月21日に、<a href="http://github.com/bittorrent/libutp" target="_blank">libutp</a>ソースコードがMITライセンスで<a href="http://forum.utorrent.com/viewtopic.php?id=76640" target="_blank">公開された</a>。libutpとは、<a href="http://www.utorrent.com/documentation/utp" target="_blank">µTP</a> (<a href="http://en.wikipedia.org/wiki/Micro_Transport_Protocol" target="_blank">Micro Transport Protocol</a>)と呼ばれるプロトコルの実装ライブラリである(BitTorrent.orgでは<a href="http://bittorrent.org/beps/bep_0029.html" target="_blank">BEP 29</a>として提案され、IETFでは<a href="http://datatracker.ietf.org/wg/ledbat/charter/" target="_blank">LEDBAT</a>として提案された)。今回は、そのコードを見てみたい。</p>
<p>libutpを公開したのは<a href="http://www.bittorrent.com/" target="_blank">BitTorrent, Inc.</a>で、彼らが配布するBitTorrentクライアント<a href="http://www.utorrent.com/" target="_blank">μTorrent</a>のバージョン1.8 betaがµTPを最初に実装した。BitTorrent, Inc.が元々持っていたオリジナルのBitTorrent実装(Mainline)は、Pythonで書かれたソフトウェアとして有名だが、μTorrentはC++で実装されたWindows用ソフトウェアである。μTorrentはスウェーデン人の<a href="http://en.wikipedia.org/wiki/Ludvig_Strigeus" target="_blank">Ludvig Strigeus</a>氏が開発したが、2006年にBitTorrent, Incに買収されている。μTorrentが登場したとき、備えている機能に比して、GUIアプリにしては(パックされている可能性を勘案しても)きわめて小さいバイナリサイズに感心した。プログラマの力量を誇示するかのようなコンパクトで尖ったソフトウェアだったので、後日の買収のニュースには、落ち着くところに落ち着いたなと感じたのを記憶している。</p>
<p>従来のBitTorrentによるファイル転送がTCPを経由して行われていたのに対し、µTPは、UDP上に構築されたプロトコルを用いる。既にDHTやトラッカーのプロトコルには<a href="http://en.wikipedia.org/wiki/UDP_tracker" target="_blank">UDPが利用されていた</a>(ただしμTorrentによる実装はかなり後になった)が、µTPは、トランスポートプロトコルとしてもUDP上に構築した独自プロトコルを利用する。</p>
<p>BitTorrentクライアントが実装した<a href="http://en.wikipedia.org/wiki/Distributed_hash_table" target="_blank">DHT</a>(分散ハッシュテーブル)は、<a href="http://en.wikipedia.org/wiki/Kademlia" target="_blank">Kademlia</a>というアルゴリズムの実装で、トラッカーに依存しないリソース探索が可能となった。Gnutellaライクな、しかしより構造化された分散キー管理により、トラッカーがダウンしていても目的のリソースを保持するピアのリストを得られる。ネットワークの単一障害点を無くすという建前だが、違法にアップロードされたデータを配布するトラッカーが検挙されつつあった情勢に対抗するものという見方もあった。</p>
<p>今回のµTP実装は、ネットワークの反応が悪くなってきた場合に、自動的に他のトラフィックに道を譲ることで輻輳を防ぐのが目的とされている。オンラインゲームなどのリアルタイム性が重視されるアプリケーションでは一定のレイテンシ以下にping値が収まっていることが要求されるが、TCPのFIFOキューではサイズの大きいP2Pパケットが転送される場合にジッターが発生しやすくサービスの品質に影響を及ぼす。現在のTCPでは、輻輳制御アルゴリズムとして、<a href="http://en.wikipedia.org/wiki/CUBIC_TCP" target="_blank">CUBIC TCP</a>(Linux)、<a href="http://en.wikipedia.org/wiki/Compound_TCP" target="_blank">Compound TCP</a>(Windows)が用いられている。µTPは、BitTorrentのアップロード時に起こりやすい輻輳を特に回避するという目的に適う制御アルゴリズムを、UDP上で実装したものということになる。現在、P2Pアプリケーションを対象としてISPによるトラフィックシェイピングが行われているが、これに対しての回答ともいえるだろう。</p>
<p>前置きは以上で、以下コードを見ていく。libutpは、Windows用のdllとして公開されており、VC9用のソリューションが添付されている。<a href="http://github.com/bittorrent/libutp/blob/master/utp.def" target="_blank">utp.def</a>に公開されているCのAPI関数は以下である。</p>
<p><span id="more-529"></span></p>
<pre class="brush: cpp; title: ; notranslate">
   UTP_Create        @1
   UTP_SetCallbacks  @2
   UTP_SetSockopt    @3
   UTP_Connect       @4
   UTP_IsIncomingUTP @5
   UTP_HandleICMP    @6
   UTP_Write         @7
   UTP_RBDrained     @8
   UTP_CheckTimeouts @9
   UTP_GetPeerName   @10
   UTP_GetDelays     @11
   UTP_Close         @12
   inet_ntop         @13
   inet_pton         @14
</pre>
<p>このうち<code>inet_ntop</code>/<code>inet_pton</code>は、Windows VistaからWinsockに実装されているので、古いバージョンのWindows用の実装である。</p>
<p>とりあえずは、µTP接続を生成すると思われる<a href="http://github.com/bittorrent/libutp/blob/master/utp.cpp" target="_blank"><code>UTP_Create</code></a>を見てみよう。</p>
<pre class="brush: cpp; title: ; notranslate">
// Create a UTP socket
UTPSocket *UTP_Create(SendToProc *send_to_proc, void *send_to_userdata, const struct sockaddr *addr, socklen_t addrlen)
{
	UTPSocket *conn = (UTPSocket*)calloc(1, sizeof(UTPSocket));

	g_current_ms = UTP_GetMilliseconds();

	UTP_SetCallbacks(conn, NULL, NULL);
	conn-&gt;our_hist.clear();
	conn-&gt;their_hist.clear();
	conn-&gt;rto = 3000;
	conn-&gt;rtt_var = 800;
	conn-&gt;seq_nr = 1;
	conn-&gt;ack_nr = 0;
	conn-&gt;max_window_user = 255 * PACKET_SIZE;
	conn-&gt;addr = PackedSockAddr((const SOCKADDR_STORAGE*)addr, addrlen);
	conn-&gt;send_to_proc = send_to_proc;
	conn-&gt;send_to_userdata = send_to_userdata;
	conn-&gt;ack_time = g_current_ms + 0x70000000;
	conn-&gt;last_got_packet = g_current_ms;
	conn-&gt;last_sent_packet = g_current_ms;
	conn-&gt;last_measured_delay = g_current_ms + 0x70000000;
	conn-&gt;last_rwin_decay = int32(g_current_ms) - MAX_WINDOW_DECAY;
	conn-&gt;last_send_quota = g_current_ms;
	conn-&gt;send_quota = PACKET_SIZE * 100;
	conn-&gt;cur_window_packets = 0;
	conn-&gt;fast_resend_seq_nr = conn-&gt;seq_nr;

	// default to version 1
	UTP_SetSockopt(conn, SO_UTPVERSION, 1);

	// we need to fit one packet in the window
	// when we start the connection
	conn-&gt;max_window = conn-&gt;get_packet_size();
	conn-&gt;state = CS_IDLE;

	conn-&gt;outbuf.mask = 15;
	conn-&gt;inbuf.mask = 15;

	conn-&gt;outbuf.elements = (void**)calloc(16, sizeof(void*));
	conn-&gt;inbuf.elements = (void**)calloc(16, sizeof(void*));

	conn-&gt;idx = g_utp_sockets.Append(conn);

	LOG_UTPV(&quot;0x%08x: UTP_Create&quot;, conn);

	return conn;
}
</pre>
<pre class="brush: cpp; title: ; notranslate">
// The uTP socket layer calls this to send UDP packets
typedef void SendToProc(void *userdata, const byte *p, size_t len, const struct sockaddr *to, socklen_t tolen);
</pre>
<p><code>SendToProc</code>は、ユーザー定義のパケット送信関数で、UDPなので<a href="http://msdn.microsoft.com/en-us/library/ms740148.aspx" target="_blank"><code>sendto</code></a>を呼ぶことになるだろう。対象のソケットは、そのユーザー定義関数からアクセスできるところにあらかじめ開いておかなければならない。コネクションレスのUDPなのでソケットは使い回すことになる。対して、ここで作成している<code>UTPSocket</code>オブジェクトは仮想的なソケットで、TCP風に対象アドレス毎に作成して<code>g_utp_sockets</code>グローバル配列に追加する。</p>
<p>ライブラリで利用する順序上は<code>UTP_Connect</code>を見るべきだが、単にSYNパケットを作成して送信するだけのAPIなので、ここで次に注目すべきはパケット受信時に呼ぶAPIである<a href="http://github.com/bittorrent/libutp/blob/master/utp.h" target="_blank"><code>UTP_IsIncomingUTP</code></a>だ。</p>
<pre class="brush: cpp; title: ; notranslate">
// Process a UDP packet from the network. This will process a packet for an existing connection,
// or create a new connection and call incoming_proc. Returns true if the packet was processed
// in some way, false if the packet did not appear to be uTP.
bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc,
					   SendToProc *send_to_proc, void *send_to_userdata,
					   const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
</pre>
<p>ネットワークから受け取ったデータをまずこのAPIに読ませ、µTPのパケットかどうかを判定する。</p>
<pre class="brush: cpp; title: ; notranslate">
bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc,
					   SendToProc *send_to_proc, void *send_to_userdata,
					   const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen)
{
	const PackedSockAddr addr((const SOCKADDR_STORAGE*)to, tolen);

	if (len &lt; sizeof(PacketFormat) &amp;&amp; len &lt; sizeof(PacketFormatV1)) {
		LOG_UTPV(&quot;recv %s len:%u too small&quot;, addrfmt(addr, addrbuf), (uint)len);
		return false;
	}

	const PacketFormat* p = (PacketFormat*)buffer;
	const PacketFormatV1* p1 = (PacketFormatV1*)buffer;

	const byte version = UTP_IsV1(p1);
	const uint32 id = (version == 0) ? p-&gt;connid : uint32(p1-&gt;connid);

	if (version == 0 &amp;&amp; len &lt; sizeof(PacketFormat)) {
		LOG_UTPV(&quot;recv %s len:%u version:%u too small&quot;, addrfmt(addr, addrbuf), (uint)len, version);
		return false;
	}
</pre>
<p>生データ<code>buffer</code>を<code>PacketFormat</code>にキャストして、パケットの中身を見ていく。</p>
<pre class="brush: cpp; title: ; notranslate">
	for (size_t i = 0; i &lt; g_utp_sockets.GetCount(); i++) {
		UTPSocket *conn = g_utp_sockets[i];
		//LOG_UTPV(&quot;Examining UTPSocket %s for %s and (seed:%u s:%u r:%u) for %u&quot;,
		//		addrfmt(conn-&gt;addr, addrbuf), addrfmt(addr, addrbuf2), conn-&gt;conn_seed, conn-&gt;conn_id_send, conn-&gt;conn_id_recv, id);
		if (conn-&gt;addr != addr)
			continue;

		if (flags == ST_RESET &amp;&amp; (conn-&gt;conn_id_send == id || conn-&gt;conn_id_recv == id)) {
			LOG_UTPV(&quot;0x%08x: recv RST for existing connection&quot;, conn);
			if (!conn-&gt;userdata || conn-&gt;state == CS_FIN_SENT) {
				conn-&gt;state = CS_DESTROY;
			} else {
				conn-&gt;state = CS_RESET;
			}
			if (conn-&gt;userdata) {
				conn-&gt;func.on_overhead(conn-&gt;userdata, false, len + conn-&gt;get_udp_overhead(),
									   close_overhead);
				const int err = conn-&gt;state == CS_SYN_SENT ?
					ECONNREFUSED :
					ECONNRESET;
				conn-&gt;func.on_error(conn-&gt;userdata, err);
			}
			return true;
		} else if (flags != ST_SYN &amp;&amp; conn-&gt;conn_id_recv == id) {
			LOG_UTPV(&quot;0x%08x: recv processing&quot;, conn);
			const size_t read = UTP_ProcessIncoming(conn, buffer, len);
			if (conn-&gt;userdata) {
				conn-&gt;func.on_overhead(conn-&gt;userdata, false,
					(len - read) + conn-&gt;get_udp_overhead(),
					header_overhead);
			}
			return true;
		}
	}
</pre>
<p>UTPSocketの接続先を比較して、受信パケットが既に管理中のUTPSocketに属する物であれば、ここで処理される。SYNパケット(ST_SYN)でない場合は、送信データの内容を受け取ったことになるので、<code>UTP_ProcessIncoming</code>関数で処理する。その後RSTパケットの処理が続いてから、最後はSYNパケットを受け取って、ピアからの接続要求を処理する。</p>
<pre class="brush: cpp; title: ; notranslate">
	if (incoming_proc) {
		LOG_UTPV(&quot;Incoming connection from %s uTP version:%u&quot;, addrfmt(addr, addrbuf), version);

		// Create a new UTP socket to handle this new connection
		UTPSocket *conn = UTP_Create(send_to_proc, send_to_userdata, to, tolen);
		// Need to track this value to be able to detect duplicate CONNECTs
		conn-&gt;conn_seed = id;
		// This is value that identifies this connection for them.
		conn-&gt;conn_id_send = id;
		// This is value that identifies this connection for us.
		conn-&gt;conn_id_recv = id+1;
		conn-&gt;ack_nr = seq_nr;
		conn-&gt;seq_nr = UTP_Random();
		conn-&gt;fast_resend_seq_nr = conn-&gt;seq_nr;

		UTP_SetSockopt(conn, SO_UTPVERSION, version);
		conn-&gt;state = CS_CONNECTED;

		const size_t read = UTP_ProcessIncoming(conn, buffer, len, true);

		LOG_UTPV(&quot;0x%08x: recv send connect ACK&quot;, conn);
		conn-&gt;send_ack(true);

		incoming_proc(send_to_userdata, conn);

		// we report overhead after incoming_proc, because the callbacks are setup now
		if (conn-&gt;userdata) {
			// SYN
			conn-&gt;func.on_overhead(conn-&gt;userdata, false, (len - read) + conn-&gt;get_udp_overhead(),
								   header_overhead);
			// SYNACK
			conn-&gt;func.on_overhead(conn-&gt;userdata, true, conn-&gt;get_overhead(),
								   ack_overhead);
		}
	}
</pre>
<p><code>incoming_proc</code>はアプリケーション定義コールバックで、ACK送信後に呼ばれる。</p>
<p>それでは、<code>UTP_ProcessIncoming</code>関数を見てみよう。</p>
<pre class="brush: cpp; title: ; notranslate">
// Process an incoming packet
// syn is true if this is the first packet received. It will cut off parsing
// as soon as the header is done
size_t UTP_ProcessIncoming(UTPSocket *conn, const byte *packet, size_t len, bool syn = false)
{
	UTP_RegisterRecvPacket(conn, len);

	g_current_ms = UTP_GetMilliseconds();

	conn-&gt;update_send_quota();

	const PacketFormat *pf = (PacketFormat*)packet;
	const PacketFormatV1 *pf1 = (PacketFormatV1*)packet;
	const byte *packet_end = packet + len;

	// snip

	// mark receipt time
	uint64 time = UTP_GetMicroseconds();

	// snip

	uint64 p;

	if (conn-&gt;version == 0) {
		p = uint64(pf-&gt;tv_sec) * 1000000 + pf-&gt;tv_usec;
	} else {
		p = pf1-&gt;tv_usec;
	}

	conn-&gt;last_measured_delay = g_current_ms;

	// get delay in both directions
	// record the delay to report back
	const uint32 their_delay = (uint32)(p == 0 ? 0 : time - p);
	conn-&gt;reply_micro = their_delay;
	uint32 prev_delay_base = conn-&gt;their_hist.delay_base;
	if (their_delay != 0) conn-&gt;their_hist.add_sample(their_delay);

	// if their new delay base is less than their previous one
	// we should shift our delay base in the other direction in order
	// to take the clock skew into account
	if (prev_delay_base != 0 &amp;&amp;
		wrapping_compare_less(conn-&gt;their_hist.delay_base, prev_delay_base)) {
		// never adjust more than 10 milliseconds
		if (prev_delay_base - conn-&gt;their_hist.delay_base &lt;= 10000) {
			conn-&gt;our_hist.shift(prev_delay_base - conn-&gt;their_hist.delay_base);
		}
	}

	const uint32 actual_delay = conn-&gt;version==0
		?(pf-&gt;reply_micro==INT_MAX?0:(uint)pf-&gt;reply_micro)
		:(uint)pf1-&gt;reply_micro;

	assert(conn-&gt;our_hist.get_value() &gt;= 0);
	// if the actual delay is 0, it means the other end
	// hasn't received a sample from us yet, and doesn't
	// know what it is. We can't update out history unless
	// we have a true measured sample
	prev_delay_base = conn-&gt;our_hist.delay_base;
	if (actual_delay != 0) conn-&gt;our_hist.add_sample(actual_delay);
	assert(conn-&gt;our_hist.get_value() &gt;= 0);

	// if our new delay base is less than our previous one
	// we should shift the other end's delay base in the other
	// direction in order to take the clock skew into account
	// This is commented out because it creates bad interactions
	// with our adjustment in the other direction. We don't really
	// need our estimates of the other peer to be very accurate
	// anyway. The problem with shifting here is that we're more
	// likely shift it back later because of a low latency. This
	// second shift back would cause us to shift our delay base
	// which then get's into a death spiral of shifting delay bases
/*	if (prev_delay_base != 0 &amp;&amp;
		wrapping_compare_less(conn-&gt;our_hist.delay_base, prev_delay_base)) {
		// never adjust more than 10 milliseconds
		if (prev_delay_base - conn-&gt;our_hist.delay_base &lt;= 10000) {
			conn-&gt;their_hist.Shift(prev_delay_base - conn-&gt;our_hist.delay_base);
		}
	}
*/
	// only apply the congestion controller on acks
	// if we don't have a delay measurement, there's
	// no point in invoking the congestion control
	if (actual_delay != 0 &amp;&amp; acked_bytes &gt;= 1)
		conn-&gt;apply_ledbat_ccontrol(acked_bytes, actual_delay, min_rtt);
</pre>
<p><code>UTP_GetMicroseconds</code>は、<a href="http://msdn.microsoft.com/en-us/library/ms644904.aspx" target="_blank"><code>QueryPerformanceCounter</code></a>を用いて<code>(</code>monotonicになるように修正した上で)マイクロ秒単位の時間を取得する。それと、パケットに記録されている時間との差分を取っている。</p>
<p>ここでわかるのは、アップロードされた送信パケットが実際に着信するまでにかかった時間(<code>their_delay</code>)を<code>reply_micro</code>として保存し、返信して、それを受け取った側で遅延(<code>actual_delay</code>)として解釈しているということだ。つまり、パケットが行って帰ってくるまでのラウンドトリップタイム(RTT)ではなく、アップロード時の遅延を計測して輻輳を検出しようとしている。この後、<code>apply_ledbat_ccontrol</code>関数によって、場合によってはウィンドウサイズを変化させて他のTCP接続を優先することになる。</p>
<pre class="brush: cpp; title: ; notranslate">
void UTPSocket::apply_ledbat_ccontrol(size_t bytes_acked, uint32 actual_delay, int64 min_rtt)
{
	// the delay can never be greater than the rtt. The min_rtt
	// variable is the RTT in microseconds

	assert(min_rtt &gt;= 0);
	int32 our_delay = min&lt;uint32&gt;(our_hist.get_value(), uint32(min_rtt));
	assert(our_delay != INT_MAX);
	assert(our_delay &gt;= 0);
	assert(our_hist.get_value() &gt;= 0);

	SOCKADDR_STORAGE sa = addr.get_sockaddr_storage();
	UTP_DelaySample((sockaddr*)&amp;sa, our_delay / 1000);

	// This test the connection under heavy load from foreground
	// traffic. Pretend that our delays are very high to force the
	// connection to use sub-packet size window sizes
	//our_delay *= 4;

	// target is microseconds
	int target = CCONTROL_TARGET;
	if (target &lt;= 0) target = 100000;

	double off_target = target - our_delay;

	// this is the same as:
	//
	//    (min(off_target, target) / target) * (bytes_acked / max_window) * MAX_CWND_INCREASE_BYTES_PER_RTT
	//
	// so, it's scaling the max increase by the fraction of the window this ack represents, and the fraction
	// of the target delay the current delay represents.
	// The min() around off_target protects against crazy values of our_delay, which may happen when th
	// timestamps wraps, or by just having a malicious peer sending garbage. This caps the increase
	// of the window size to MAX_CWND_INCREASE_BYTES_PER_RTT per rtt.
	// as for large negative numbers, this direction is already capped at the min packet size further down
	// the min around the bytes_acked protects against the case where the window size was recently
	// shrunk and the number of acked bytes exceeds that. This is considered no more than one full
	// window, in order to keep the gain within sane boundries.

	assert(bytes_acked &gt; 0);
	double window_factor = (double)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked);
	double delay_factor = off_target / target;
	double scaled_gain = MAX_CWND_INCREASE_BYTES_PER_RTT * window_factor * delay_factor;

	// since MAX_CWND_INCREASE_BYTES_PER_RTT is a cap on how much the window size (max_window)
	// may increase per RTT, we may not increase the window size more than that proportional
	// to the number of bytes that were acked, so that once one window has been acked (one rtt)
	// the increase limit is not exceeded
	// the +1. is to allow for floating point imprecision
	assert(scaled_gain &lt;= 1. + MAX_CWND_INCREASE_BYTES_PER_RTT * (int)min(bytes_acked, max_window) / (double)max(max_window, bytes_acked));

	if (scaled_gain &gt; 0 &amp;&amp; g_current_ms - last_maxed_out_window &gt; 300) {
		// if it was more than 300 milliseconds since we tried to send a packet
		// and stopped because we hit the max window, we're most likely rate
		// limited (which prevents us from ever hitting the window size)
		// if this is the case, we cannot let the max_window grow indefinitely
		scaled_gain = 0;
	}

	if (scaled_gain + max_window &lt; MIN_WINDOW_SIZE) {
		max_window = MIN_WINDOW_SIZE;
	} else {
		max_window = (size_t)(max_window + scaled_gain);
	}

	// make sure that the congestion window is below max
	// make sure that we don't shrink our window too small
	max_window = clamp&lt;size_t&gt;(max_window, MIN_WINDOW_SIZE, opt_sndbuf);
</pre>
<p><code>CCONTROL_TARGET</code>は今のところ100 * 1000µs = 100msで、100msを下回っていれば目標のレイテンシが達成できているということになる。ターゲットから外れている数値(<code>off_target</code>)に応じて<code>scaled_gain</code>を算出し、100msよりレイテンシが低ければウィンドウサイズ(<code>max_window</code>)を大きくし、100msを超えていたら輻輳とみなしてウィンドウサイズを小さくし、別のアプリケーションに道を譲るという輻輳制御が行われる。</p>
<p>この後、<code>UTP_ProcessIncoming</code>では、Selective ACKという処理でパケットロスを判定する。</p>
<pre class="brush: cpp; title: ; notranslate">
	// count bytes acked by EACK
	if (selack_ptr != NULL) {
		acked_bytes += conn-&gt;selective_ack_bytes((pk_ack_nr + 2) &amp; ACK_NR_MASK,
												 selack_ptr, selack_ptr[-1], min_rtt);
	}
</pre>
<pre class="brush: cpp; title: ; notranslate">
void UTPSocket::selective_ack(uint base, const byte *mask, byte len)
{
	// snip

	bool back_off = false;
	int i = 0;
	while (nr &gt; 0) {
		uint v = resends[--nr];
		// don't consider the tail of 0:es to be lost packets
		// only unacked packets with acked packets after should
		// be considered lost
		OutgoingPacket *pkt = (OutgoingPacket*)outbuf.get(v);

		// this may be an old (re-ordered) packet, and some of the
		// packets in here may have been acked already. In which
		// case they will not be in the send queue anymore
		if (!pkt) continue;

		// used in parse_log.py
		LOG_UTP(&quot;0x%08x: Packet %u lost. Resending&quot;, this, v);

		// On Loss
		back_off = true;
#ifdef _DEBUG
		++_stats._rexmit;
#endif
		send_packet(pkt);
		fast_resend_seq_nr = v + 1;

		// Re-send max 4 packets.
		if (++i &gt;= 4) break;
	}

	if (back_off)
		maybe_decay_win();

	duplicate_ack = count;
}
</pre>
<p>同じACKを3回受け取った場合、輻輳が激しくなってパケットロスが起きたとみなし、パケット再送を促すとともに、<code>maybe_decay_win</code>を呼んでウィンドウサイズを縮小する。ここは<a href="http://en.wikipedia.org/wiki/TCP_congestion_avoidance_algorithm" target="_blank">TCP Reno</a>同様である。</p>
<p>µTPの基本的な動作は、以上である。一見する限り、これでμTorrentを起動していてもWebブラウザを含む他のネットワークアプリの動作が重くならなくなるのであれば、万歳といったところだ。ところが、torrentコミュニティの中では、事実上μTorrentが(µTPをサポートする)μTorrentのみをピアとして優先するようになり他のクライアントが差別されかねないことや、µTP適用で絶対的転送速度が下がる可能性があることを危惧して、µTPに対しての批判や慎重論も根強いようである。とはいえ、μTorrentが現在非常に大きなシェアを占めていることは事実であり、µTPを実装するクライアントが増加するのも時間の問題だろう。<a href="http://www.bitcomet.com/" target="_blank">BitComet</a>や<a href="http://www.xunlei.com/" target="_blank">Xunlei</a>といった中国で人気のあるクライアントが追随すれば、さらに趨勢は決定的となる。</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2010/07/11/peek-over-libutp-utp-implementation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quid Pro Quo</title>
		<link>http://zzz.zggg.com/2009/12/14/quid-pro-quo/</link>
		<comments>http://zzz.zggg.com/2009/12/14/quid-pro-quo/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 16:21:15 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=631</guid>
		<description><![CDATA[One thing that I don&#8217;t like about lightweight languages (LL) is usage of bizarre identifiers. Compiled l [...]]]></description>
			<content:encoded><![CDATA[<p>One thing that I don&#8217;t like about lightweight languages (LL) is usage of bizarre identifiers. Compiled languages don&#8217;t care about verbose identifiers, but scripting languages often employ abbreviated names to gain run-time performance and typing speed.</p>
<pre class="brush: perl; title: ; notranslate">
my ( $x, $y ) = $self-&gt;invoke(
	+{
		METHOD =&gt; 'foo',
		PARAM =&gt; 'bar',
	},
	''
);
</pre>
<p>In this Perl snippet, I had no idea what &#8220;+{}&#8221; stands for. It looks like some kind of hash, but not sure. Googling it didn&#8217;t bring good results since Google doesn&#8217;t recognize a string made only of non-alphabetical characters such as braces and math operators.</p>
<p>To figure out its meaning I wasted so much time by trying many different words in Google. Anyway here&#8217;s the answer:</p>
<blockquote><p>or to force an anon hash constructor use <code>+{</code>:</p>
<pre>
<ol>
<li>   @hashes = <a href="http://perldoc.perl.org/functions/map.html">map</a> +{ <a href="http://perldoc.perl.org/functions/lc.html">lc</a>($_) =&gt; 1 }, @array # EXPR, so needs comma at end</li>
</ol>
</pre>
<p>to get a list of anonymous hashes each with only one entry apiece.</p></blockquote>
<p>It&#8217;s embedded in <a href="http://perldoc.perl.org/perlfunc.html" target="_blank">perlfunc</a> and I couldn&#8217;t find any other references in the official documents.</p>
<p>I had a hard time with Ruby too when the last argument for a method has an ampersand (&amp;) prepended. In the Japanese version of the Ruby manual, it&#8217;s obscurely explained in a <a href="http://www.ruby-lang.org/ja/man/html/FAQ_A5D6A5EDA5C3A5AFC9D5A4ADA5E1A5BDA5C3A5C9B8C6A4D3BDD0A4B7.html" target="_blank">single line</a>. It&#8217;s very hard to find since there&#8217;s no word for an ampersand in Japanese. It has no English version but The Ruby Programming Wikibooks has a <a href="http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Method_Calls#The_ampersand_.28.26.29" target="_blank">related part</a> which is a lot better with examples.</p>
<blockquote>
<h4>The ampersand (&amp;)</h4>
<p>The ampersand operator can be used to explicitly convert between  blocks and Procs in a couple of cases. It is worthy to understand how  these work.</p>
<p>Remember how I said that although an attached block is converted to a  Proc under the hood, it is not accessible as a Proc from inside the  method ? Well, if an ampersand is prepended to the last argument in the  argument list of a method, the block attached to this method is  converted to a Proc object and gets assigned to that last argument:</p>
<pre class="brush: ruby; title: ; notranslate">
def contrived(a, &amp;f)
     # the block can be accessed through f
     f.call(a)

     # but yield also works !
     yield(a)
 end

 # this works
 contrived(25) {|x| puts x}

 # this raises ArgumentError, because &amp;f
 # isn't really an argument - it's only there
 # to convert a block
 contrived(25, lambda {|x| puts x})
</pre>
</blockquote>
<p>Regarding manuals, MSDN is still the best place. Don&#8217;t know what &#8220;=&gt;&#8221; means in C#? OK search it in the <a href="http://msdn.microsoft.com/en-us/library/6a71f45d.aspx" target="_blank">C# operators</a>. It&#8217;s the <a href="http://msdn.microsoft.com/en-us/library/bb311046.aspx" target="_blank">lambda operator</a> introduced in C# 3.0. Since I always code with a language specification on my side when it&#8217;s not C++, the quality of reference documents can be directly reflected in productivity.</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2009/12/14/quid-pro-quo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++ Dependency Injection (or the next best thing) on Windows</title>
		<link>http://zzz.zggg.com/2009/09/01/cpp-dependency-injection-or-the-next-best-thing-on-windows/</link>
		<comments>http://zzz.zggg.com/2009/09/01/cpp-dependency-injection-or-the-next-best-thing-on-windows/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 20:50:51 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=397</guid>
		<description><![CDATA[Dependency Injection (DI) is one of the recent buzz phrases within the design pattern community after Martin F [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Dependency_injection" target="_blank">Dependency Injection</a> (DI) is one of the recent buzz phrases within the design pattern community after Martin Fowler picked it up with another related concept <a href="http://en.wikipedia.org/wiki/Inversion_of_control" target="_blank">Inversion of Control</a> (IoC) in 2004. Since then, it became popular in Java lightweight frameworks where adding late binding was seen as a critical step for upping productivity.</p>
<p>The core value of DI is basically represented in these 2 points:</p>
<ol>
<li>Testability. DI makes testing easy by enabling loosely coupled components that are easily replaced with mock objects.</li>
<li>Dependency control. When you deploy a DI framework instead of using the Factory Method pattern, dependency can be managed outside of components.</li>
</ol>
<p>The first point is rather obvious. To understand the second point, I recommend you to browse the <a href="http://code.google.com/p/google-guice/" target="_blank">Google Giuce</a> lightweight Java DI framework for its video presentation and documents. It illustrates the necessity of such a framework for Java in a straightforward way. Particularly, Giuce appears to be a neat implementation of DI where you don&#8217;t need to manage XML configuration files unlike other frameworks. Just like inner DSL, dependency is handled in type-safe Java code even though it ditches type-safe factories scattered in code.</p>
<p>But, as Ruby and other dynamic languages gets more attention, the relative mind share of DI seems to get smaller. In Ruby, you can swap methods of instances dynamically at the side of a test class. The dynamic nature of Ruby can enable whole other tricks dependent on it such as ActiveRecord.</p>
<p>So what about DI? Is it just a glorified abstract factory? Unfortunately, there still have to be environments where DI makes things a lot easier. Not just Java, but other static language, such as C++. Since my programming history is MS-Windows-centric, my interest toward DI is its applicability for Windows app development. DI is a lot discussed in the context of Java/.NET enterprise development, but its necessity would be even higher in C++ development on Windows as long as other requirements such as performance permit.</p>
<p><span id="more-397"></span></p>
<p>If you are a Windows programmer, IoC can&#8217;t be a novel concept since without it no Windows GUI application can be built. Plugging in your implementation code into some framework is not an alien concept for us. As for DI, its merit of testability is a big plus for a project that includes many C++ components and consumes mind-bogglingly long time to rebuild.</p>
<p>But DI discussion seems thin around here. Why? It seems existing implementations in Java often rely on reflection which is not available in C++. For example, Giuce uses <code>@inject</code> annotation to tell injection points. It may be just for its AOP features, but lacking reflection makes it a lot harder to implement. Using exotic macros and templates can change the situation, but I guess not much. Another issue is, as I mentioned already, it&#8217;s a form of late binding hence performance hit is expected. If you design it not to get hit hard, it will not be loosely coupled any more. At this point, I almost gave up the idea of DI for Windows C++.</p>
<p>Instead, my interest shifted to finding the next best thing available which can help us to test binary components without hassle. So I searched &#8211; and found a solution. It&#8217;s called <a href="http://msdn.microsoft.com/en-us/library/ms973913.aspx" target="_blank">registration-free COM</a> or Reg-Free COM.</p>
<p>OK don&#8217;t stone me :) It&#8217;s a very nice feature or a hidden gem in Windows. It&#8217;s only available on Windows XP and later, but it won&#8217;t be a problem. The basic idea behind <a href="http://en.wikipedia.org/wiki/Component_Object_Model" target="_blank">COM (Component Object Model)</a> is a binary interface for reusable components. A part of its concept was later adopted by <a href="http://en.wikipedia.org/wiki/XPCOM" target="_blank">XPCOM</a> for Mozilla Firefox.</p>
<p>One issue that nags developers and users regarding the use of COM components is it requires Registry entry to resolve an interface query. GUIDs of COM components have to be registered with regsvr32.exe in the HKEY_CLASSES_ROOT (HKCR) Registry key. It makes deployment of COM components really cumbersome even though COM itself is a really reasonable technology. Uninstalling them can be a PITA too.</p>
<p>Enter Reg-Free COM, now Registry entry is not necessary to use a COM component as long as XML manifests are provided to load correct components. In normal COM, the ClassFactory and related platform facility searches Registry entry when a specific CLSID or IID is requested in CoCreateInstance or QueryInterface, whereas in Reg-Free COM dependency resolution is done at application startup by parsing manifests. There are 2 kinds of manifests: application manifest and assembly manifest. The former describes on what components an application depends. The latter describes assembly&#8217;s identity such as a dll file name and CLSID.</p>
<p>A typical application manifest is as follows (lifted from the sample at MSDN)</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;assembly xmlns=&quot;urn:schemas-microsoft-com:asm.v1&quot; manifestVersion=&quot;1.0&quot;&gt;
&lt;assemblyIdentity
            type = &quot;win32&quot;
            name = &quot;client&quot;
            version = &quot;1.0.0.0&quot; /&gt;
&lt;dependency&gt;
            &lt;dependentAssembly&gt;
                        &lt;assemblyIdentity
                                    type=&quot;win32&quot;
                                    name=&quot;SideBySide.X&quot;
                                    version=&quot;1.0.0.0&quot; /&gt;
            &lt;/dependentAssembly&gt;
&lt;/dependency&gt;
&lt;/assembly&gt;
</pre>
<p>It shows it depends on an assembly with the name &#8220;SideBySide.X&#8221;. The dll loader tries to find a file with the name &#8220;SideBySide.X.manifest&#8221; when reading this application manifest. In SideBySide.X.manifest, its correspondent dll is described.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;assembly xmlns=&quot;urn:schemas-microsoft-com:asm.v1&quot; manifestVersion=&quot;1.0&quot;&gt;

&lt;assemblyIdentity
	type=&quot;win32&quot;
	name=&quot;SideBySide.X&quot;
	version=&quot;1.0.0.0&quot; /&gt;

&lt;file name = &quot;SideBySide.dll&quot;&gt;

&lt;comClass
    clsid=&quot;{4B72FC46-C543-4101-80DB-7777848D1357}&quot;
    threadingModel = &quot;Apartment&quot; /&gt;

&lt;typelib tlbid=&quot;{E6A9CD40-8559-4E17-A0D9-C68B038B4FA0}&quot;
       version=&quot;1.0&quot; helpdir=&quot;&quot;/&gt;

&lt;/file&gt;

&lt;comInterfaceExternalProxyStub
    name=&quot;ISideBySideClass&quot;
    iid=&quot;{CBA85B94-9C11-43aa-84F6-30B90145FD3E}&quot;
    proxyStubClsid32=&quot;{00020424-0000-0000-C000-000000000046}&quot;
    baseInterface=&quot;{00000000-0000-0000-C000-000000000046}&quot;
    tlbid = &quot;{E6A9CD40-8559-4E17-A0D9-C68B038B4FA0}&quot; /&gt;

&lt;/assembly&gt;
</pre>
<p>A <code>comInterfaceExternalProxyStub</code> node is necessary when a component is called in a different kind of a thread apartment from that of the component.</p>
<p<a href="http://en.wikipedia.org/wiki/Dependency_injection" target="_blank">Dependency Injection</a> (DI) is one of the recent buzz phrases within the design pattern community after Martin Fowler picked it up with another related concept <a href="http://en.wikipedia.org/wiki/Inversion_of_control" target="_blank">Inversion of Control</a> (IoC) in 2004. Since then, it became popular in Java lightweight frameworks where adding late binding was seen as a critical step for upping productivity.</p>
<p>The core value of DI is basically represented in these 2 points:</p>
<ol>
<li>Testability. DI makes testing easy by enabling loosely coupled components that are easily replaced with mock objects.</li>
<li>Dependency control. When you deploy a DI framework instead of using the Factory Method pattern, dependency can be managed outside of components.</li>
</ol>
<p>The first point is rather obvious. To understand the second point, I recommend you to browse the <a href="http://code.google.com/p/google-guice/" target="_blank">Google Giuce</a> lightweight Java DI framework for its video presentation and documents. It illustrates the necessity of such a framework for Java in a straightforward way. Particularly, Giuce appears to be a neat implementation of DI where you don&#8217;t need to manage XML configuration files unlike other frameworks. Just like inner DSL, dependency is handled in type-safe Java code even though it ditches type-safe factories scattered in code.</p>
<p>But, as Ruby and other dynamic languages gets more attention, the relative mind share of DI seems to get smaller. In Ruby, you can swap methods of instances dynamically at the side of a test class. The dynamic nature of Ruby can enable whole other tricks dependent on it such as ActiveRecord.</p>
<p>So what about DI? Is it just a glorified abstract factory? Unfortunately, there still have to be environments where DI makes things a lot easier. Not just Java, but other static language, such as C++. Since my programming history is MS-Windows-centric, my interest toward DI is its applicability for Windows app development. DI is a lot discussed in the context of Java/.NET enterprise development, but its necessity would be even higher in C++ development on Windows as long as other requirements such as performance permit.</p>
<p><!--more--></p>
<p>If you are a Windows programmer, IoC can&#8217;t be a novel concept since without it no Windows GUI application can be built. Plugging in your implementation code into some framework is not an alien concept for us. As for DI, its merit of testability is a big plus for a project that includes many C++ components and consumes mind-bogglingly long time to rebuild.</p>
<p>But DI discussion seems thin around here. Why? It seems existing implementations in Java often rely on reflection which is not available in C++. For example, Giuce uses <code>@inject</code> annotation to tell injection points. It may be just for its AOP features, but lacking reflection makes it a lot harder to implement. Using exotic macros and templates can change the situation, but I guess not much. Another issue is, as I mentioned already, it&#8217;s a form of late binding hence performance hit is expected. If you design it not to get hit hard, it will not be loosely coupled any more. At this point, I almost gave up the idea of DI for Windows C++.</p>
<p>Instead, my interest shifted to finding the next best thing available which can help us to test binary components without hassle. So I searched &#8211; and found a solution. It&#8217;s called <a href="http://msdn.microsoft.com/en-us/library/ms973913.aspx" target="_blank">registration-free COM</a> or Reg-Free COM.</p>
<p>OK don&#8217;t stone me :) It&#8217;s a very nice feature or a hidden gem in Windows. It&#8217;s only available on Windows XP and later, but it won&#8217;t be a problem. The basic idea behind <a href="http://en.wikipedia.org/wiki/Component_Object_Model" target="_blank">COM (Component Object Model)</a> is a binary interface for reusable components. A part of its concept was later adopted by <a href="http://en.wikipedia.org/wiki/XPCOM" target="_blank">XPCOM</a> for Mozilla Firefox.</p>
<p>One issue that nags developers and users regarding the use of COM components is it requires Registry entry to resolve an interface query. GUIDs of COM components have to be registered with regsvr32.exe in the HKEY_CLASSES_ROOT (HKCR) Registry key. It makes deployment of COM components really cumbersome even though COM itself is a really reasonable technology. Uninstalling them can be a PITA too.</p>
<p>Enter Reg-Free COM, now Registry entry is not necessary to use a COM component as long as XML manifests are provided to load correct components. In normal COM, the ClassFactory and related platform facility searches Registry entry when a specific CLSID or IID is requested in CoCreateInstance or QueryInterface, whereas in Reg-Free COM dependency resolution is done at application startup by parsing manifests. There are 2 kinds of manifests: application manifest and assembly manifest. The former describes on what components an application depends. The latter describes assembly&#8217;s identity such as a dll file name and CLSID.</p>
<p>A typical application manifest is as follows (lifted from the sample at MSDN)</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;assembly xmlns=&quot;urn:schemas-microsoft-com:asm.v1&quot; manifestVersion=&quot;1.0&quot;&gt;
&lt;assemblyIdentity
            type = &quot;win32&quot;
            name = &quot;client&quot;
            version = &quot;1.0.0.0&quot; /&gt;
&lt;dependency&gt;
            &lt;dependentAssembly&gt;
                        &lt;assemblyIdentity
                                    type=&quot;win32&quot;
                                    name=&quot;SideBySide.X&quot;
                                    version=&quot;1.0.0.0&quot; /&gt;
            &lt;/dependentAssembly&gt;
&lt;/dependency&gt;
&lt;/assembly&gt;
</pre>
<p>It shows it depends on an assembly with the name &#8220;SideBySide.X&#8221;. The dll loader tries to find a file with the name &#8220;SideBySide.X.manifest&#8221; when reading this application manifest. In SideBySide.X.manifest, its correspondent dll is described.</p>
<pr>
<p>Back on the topic of DI, the most important point is you can modify dependency by editing these manifests. You can change an application manifest to refer to another dependent manifest. It&#8217;s possible to change the file name in an assembly manifest to load a different dll that has a different implementation of a coclass with the same CLSID. As long as IID matches you can swap it with a mock object.</p>
<p>Of course there are drawbacks. If you feel making COM objects tedious, it&#8217;s not for you. But I&#8217;d take unit testing without rebuild any day. Also, since it resolves dependency at startup, it can slow down the process a bit if there are too many Reg-Free COM objects. After startup the overhead should not be larger than regular COM usage.</p>
<p>One thing I&#8217;d like to emphasize in this article is reinventing the wheel costs you a lot. Instead, first consider using what&#8217;s available to your liking before jumping the gun to write your own version. Most likely, someone already came up with a decent idea deliberately or indeliberately.</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2009/09/01/cpp-dependency-injection-or-the-next-best-thing-on-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Red Pill or Blue Pill</title>
		<link>http://zzz.zggg.com/2009/08/19/red-pill-or-blue-pill/</link>
		<comments>http://zzz.zggg.com/2009/08/19/red-pill-or-blue-pill/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 15:25:53 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[sup]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=677</guid>
		<description><![CDATA[先月7月頭に、GoogleのChrome OSが発表された。Linuxカーネル + 軽量ウィンドウマネージャ + Google Chrome Webブラウザという構成を取るといわれるこのOSは、いわゆるシンクライアントを [...]]]></description>
			<content:encoded><![CDATA[<p>先月7月頭に、Googleの<a title="Chrome OS" href="http://googlejapan.blogspot.com/2009/07/google-chrome-os.html" target="_blank">Chrome OS</a>が発表された。Linuxカーネル + 軽量ウィンドウマネージャ + Google Chrome Webブラウザという構成を取るといわれるこのOSは、いわゆるシンクライアントを最低限のハードウェアリソースで実現するための環境となると推測される。ただし、従来の企業向け用途の単なるシンクライアントではなく、ビデオ再生や3Dなど、ハードウェアリソースを要求するリッチメディアがWeb上で当たり前のようにやりとりされている現在や近未来のパーソナルコンピューティング環境をも視野に入れていることは間違いないだろう。</p>
<p>これが、かつてOracleが提唱した<a href="http://ja.wikipedia.org/wiki/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF" target="_blank">ネットワークコンピュータ</a>を越えていくものとなるかどうかは、実際のプロダクトの出来を見なければ、占うにはまだ早すぎるといわざるをえない。それでも、Google Chromeに続きChrome OSによって、Googleが考えるところの理想のクライアント環境を実現しようとする動きは、きわめて自然であるし、一貫性があるといえる。しかし、この一貫性は、単にGoogle内部で完結しているものではなく、歴史的な流れの中のある一点で、たまたまGoogleという企業が、マイルストーンとして一般に認知される発表を行うことを可能とするリソースや動機を有していた、という見方もできよう。</p>
<p>この仮想的な歴史をめぐる可能世界で、Chrome OSの前駆者として、またもう一つの可能性として念頭にあるのは、Microsoftの活動だ。今年の2月に発表された<a href="http://research.microsoft.com/apps/pubs/default.aspx?id=79655" target="_blank">Gazelle</a>は、プリンシパルベースのセキュリティという概念を主軸に置いて、Google Chromeより徹底したセキュリティアーキテクチャのWebブラウザを、OSをも巻き込んだ形で実装してしまおうという試みである。このアプローチは、Google Chrome実装の経緯と、興味深い鏡像関係を成している。Google Chromeの実装者らは、Windows上でセキュリティサンドボックスを実現するために、Windows XP SP2の実装に<a href="http://www.hanselman.com/blog/TheWeeklySourceCode33MicrosoftOpenSourceInsideGoogleChrome.aspx" target="_blank">深く依存せざるを得なかった</a>。市場を独占するOSのAPIや実装を管理できるというリソースを持ち合わせるMicrosoftにとっては、そのあたりの苦労は、技術的なものではなく、単に手続き的なものでしかない。そして、Gazelleが理論として存在したとしても、それが実際の製品に生かされるかどうかは、別の次元の話である。</p>
<p>Gazelleという試みと別の次元で並行して走る現実世界でのMicrosoftの問題は、法的な懸念である。1997年のInternet Explorer 4で、MicrosoftはOSのシェルとWebブラウザの統合を図った。その余波が、WebブラウザなどのコンポーネントをOSに同梱する際に紛糾するというヨーロッパでの今日的状況にまで及んでいる。この、法的な懸念をかわしつつ、MicrosoftがGazelleを実現しようとするならば、必要な機能のほとんどはOS側に盛り込んで、それを自社のWebブラウザからだけではなく他社からも利用できるようにすることになるだろう。Webブラウザというアプリケーションに固有の部分は、<a href="http://ja.wikipedia.org/wiki/%E5%A4%9A%E5%B1%A4%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3" target="_blank">3層アーキテクチャ</a>でいえば、データの表示を司るいわゆるプレゼンテーション層や、Webブラウザ固有の操作に限定されたビジネスロジック層に限ったものとなり、データのやり取りを管理するデータ層は、OSが引き取ることになる。</p>
<p>ここで、Webブラウザの話に戻ると、Google Chromeの構成は、すでにそのような階層を前提としている。データのやり取りや管理を行うカーネルと、データの表示を行うレンダラーの分離は、Gazelle的なOSにおけるOSとアプリケーションの関係にそのままあてはまる。であれば、GoogleもまたOSに向かうのは当然の流れだろう。その意味で、Google Chromeとは、Windows等のOSの中に、Googleの植民地としての仮想OSを構築するという試みであったといえる。そして、仮想OSをOSに変えるには、ハードウェアとの仲立ちを行ってくれる層(たとえばLinuxカーネル)があればよい。</p>
<p>Webブラウザを仮想OSとしてとらえ、各々の機能を別プロセスに分けサンドボックス化してセキュリティを担保するという構成自体は、Google Chromeが初めてではない。2008年3月に発表されている<a href="http://www.iti.illinois.edu/news/press-releases/iti-researchers-create-secure-web-browser" target="_blank">Opus Palladianum</a>は、まさにそのような実験だった。そこでの課題は、パフォーマンスである。データの流れに対して要所要所で監査が行われるため、そのためのレイテンシ増大が問題となっていた。これに対し、Google Chromeの場合は、機能分割の粒度を下げたり、各々の部品の最適化を進めることで、現実解を導いている。</p>
<p>いずれにせよ、ネットワークリソースのサンドボックス化、仮想マシン化、そしてクラウド化というトレンドは、最早後戻りのないポイントにまで進展してきている。このリアリティ(<a href="http://en.wikipedia.org/wiki/Redpill" target="_blank">Red Pill</a>)を受け入れ、積極的に生かすことができるか、もしくは幸福な幻想(Blue Pill)のもとに留まるか &#8211; 今後数年で、さまざまな選択と、その結果を目にすることになるのは間違いない。</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2009/08/19/red-pill-or-blue-pill/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Whisky-Tango-Foxtrot</title>
		<link>http://zzz.zggg.com/2009/04/15/whisky-tango-foxtrot/</link>
		<comments>http://zzz.zggg.com/2009/04/15/whisky-tango-foxtrot/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 22:59:39 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[sup]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=137</guid>
		<description><![CDATA[更新を再開しようかと思ったのだが、まだネタがないので仕方なくblog風に先日撮った写真(芝公園にて、2009年4月3日)で茶を濁す。 昨年も書いているように、サイト自体をCMSかblogツールにいい加減移行したいと本当は [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://zzz.zggg.com/?attachment_id=627"><img class="alignright size-full wp-image-627" title="20090403" src="http://zzz.zggg.com/wordpress/wp-content/uploads/20090403.png" alt="芝公園にて、2009年4月3日" width="396" height="528" /></a></p>
<p>更新を再開しようかと思ったのだが、まだネタがないので仕方なくblog風に先日撮った写真(芝公園にて、2009年4月3日)で茶を濁す。</p>
<p>昨年も書いているように、サイト自体をCMSかblogツールにいい加減移行したいと本当は思っていて、そのくせ時間がないので踏み切れないでいる。</p>
<p>VS2008はやっと自分のPCにインストールしたところで、昨年書いた課題に取りかかる以前の段階で1年以上足踏みしてしまっている。その間に生活環境が変化したため、以前描いていた計画も、実装に取りかかる遙か以前の段階で既に再検討を余儀なくされている。具体的には、DICEに関して、ある部分のみC++/CLIを用いて.NET化することを考えていた。それというのも、ネイティブコードもそろそろ潮時かと考えて、C++を利用する部分を徐々に縮小させることを意図していたからであった。現在もその方針自体は誤りではなかったと考えているが、今それを為すべきか、そのための時間があるかということを熟慮すると、同じ時間を使うにしても他にやらなければならないことがあるのではないかというのが今回至った結論である。</p>
<p>また、去年計画・調査だけ行って結局頓挫したものとして、どのみち日の目を見ないだろうから忘れないうちに書いてしまうと、RTMPをDICEに実装することを考えていた。それというのも、抽象サーバーフレームワークであるDICEのプロトコル実装の試金石として商業的に意味のありそうなプロトコルを是非実装しておきたかったのと、Flashとの親和性を高めておきたかったという事情がある。サーバー用のソフトウェアスタック(と.NETで作った簡易クライアント)しかコントロールできない私にとって、Flash       +  JavaScriptはクライアントアプリ作成のためのRAD環境たり得た。ところが状況は変わり、C++の非常に有望なクライアント用ソフトウェアスタックが自由なライセンスの元で利用できることになり、今はそれをどう活かすかについて思案している。勘の良い諸兄ならそれが何かもうお分かりだろう。</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2009/04/15/whisky-tango-foxtrot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WindowsにおけるC++へのPHP組み込み環境の構築</title>
		<link>http://zzz.zggg.com/2008/02/11/windows-cpp-php-embedding/</link>
		<comments>http://zzz.zggg.com/2008/02/11/windows-cpp-php-embedding/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 23:33:40 +0000</pubDate>
		<dc:creator>RyuK</dc:creator>
				<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://zzz.zggg.com/?p=157</guid>
		<description><![CDATA[前回の記事では、C/C++コードへのPerlとRubyの組み込みを扱った。DICEへの組み込みの評価を兼ねていて、当時はPerlを使うことになった。一方で、DICEのWebサーバとしての側面をもっと強調せねばという課題が [...]]]></description>
			<content:encoded><![CDATA[<p><a href="../../perl_ruby_multithreading_embedding.html" target="_blank">前回の記事</a>では、C/C++コードへのPerlとRubyの組み込みを扱った。<a href="http://zzz.zggg.com/dice/" target="_blank">DICE</a>への組み込みの評価を兼ねていて、当時はPerlを使うことになった。一方で、DICEのWebサーバとしての側面をもっと強調せねばという課題が最近わりと念頭にあり、Webサーバを名乗るからには現在のWeb向けスクリプト言語No1としてのPHPをサポートしていないというのはいかにも心苦しい。PHPはApacheと関連付けて語られることも多い以上、Apacheの代替を目指しているわけではないDICEでサポートする意味も薄いと判断し敬遠してきたという経緯もあったものの、あまりにもPHPの勢いがありすぎるので仕方なくサポートに向けて舵を切ったというわけだ。特に海外では、VBulletinやWordPressといった代表的Webアプリケーションが利用できてようやくそれなりのWebサーバとしてユーザの検討の俎上に載せられることもあるだろう。<br />
<span id="more-157"></span><br />
PHPの魅力は、言語仕様ではなくバックエンドにある。特に、実行時間を限定できるオプションは有り難い。中をあまり見ていないので実装の詳細は知らないが、実行スレッド以外にスレッドを起動するか、あるいは元々のディスパッチャがディスパッチしたタスクを定期的にチェックするなりして監視していると思われる。WindowsだとTerminateThreadというAPIでスレッドを止めることが出来るけれども、これはリソースリークを起こす不安定なAPIとして知られている。特に、OSのスレッドプールを使っている場合は、スレッドを勝手に止めるとどんな予期しない悪影響が起こるかわかったものではない。PHP側で非ネイティブスレッドの実行を途中停止しているとすれば、PHPを組み込んで使うクライアントコード側としては手間が省けて大いに助かるというわけである。</p>
<p>本記事の環境はVS2005(VC8)である。PHPはPHP 5.25を用いた。PHP組み込みに関する公式の資料は<a href="http://www.php.net/manual/en/internals2.php" target="_blank">PHPマニュアル第7章</a>に存在する。46節の&#8221;<a href="http://www.php.net/manual/en/internals2.ze1.zendapi.php" target="_blank">Zend   API: Hacking the Core of PHP</a>&#8220;に変数の操作に関して記述がある。ところが、現時点のPHPマニュアルには、組み込みの際の初期化についてすら解説がない。PHPソースコードを展開した際に<code>php-5.2.5\sapi\embed</code>フォルダに見つかる<code>php_embed.h</code>ならびに<code>php_embed.c</code>を参照すると、初期化/終了マクロがあり、初期化の際に<code>sapi_startup</code>関数を呼んでいるのが分かる。これは<code>main\SAPI.h</code>ならびに<code>SAPI.c</code>に定義されており、引数となる構造体<code>_sapi_module_struct</code>にコールバックを登録してPHPのSAPI(Server   API)を初期化している。そのコールバックの中でも、<code>php_embed_ub_write</code>がprintなどの出力を受ける関数で、<code>php_embed.c</code>内では<code>php_embed_ub_write</code>を経由して<code>php_embed_single_write</code>に至り、標準出力へ出力されている。つまりそこをオーバライドしてやればユーザ側でスクリプトの出力を受け取れるのであり、基本的にはRuby組み込みで使われる方法と同一だが、PHPはSAPIフレームワークの中でインターフェイスをユーザ側に提供している点が異なる。</p>
<p>ユーザコードの概要が掴めたところで、次にPHP組み込みに必要な環境を作らなければならない。先に書いておくが、ここにまず問題がある。PHPのソースコードを<a href="http://www.php.net/downloads.php" target="_blank">ダウンロード</a>してローカルに展開した後に、マニュアルの<a href="http://jp.php.net/manual/ja/install.windows.building.php" target="_blank">Windows上でのビルド方法</a>に従ってビルドを行う。<code>win32build.zip</code>と   <code>bindlib_w32.zip</code>もビルドに必要なGNUツールなどを含んでいるので所定の場所へ展開しておく必要がある。ビルドには、Visual C++ツールのコマンドプロンプトを使用する。今回は組み込みを行うので、WSHを経由して<code>configure.js</code>を呼び出しmakeの設定を行う際に、<code>--enable-embed</code>を引数に加えることになる。</p>
<p>ところが、そのままビルドを始めると、エラーが出てストップしてしまう。エラーコードを見ると、libxmlに問題が起こっているらしい。そこで libxml2をダウンロードしてパスを通すも、やはりビルドが通らない。今度はどうやらiconvが必要なようで、最新版libiconvをダウンロー ドしてみると、なんと以前は入っていたVC++サポートがどういうわけか削除されていた。mingwでビルドせよとあるので試してみたがどうも上手くいかない。しかも、ダウンロード元がGNUだったことを思い出し、これはライセンス的にまずいのではないかと後から気付いた。iconvに由来するコードが PHPのスタティックライブラリに含まれているとすれば、PHP組み込みを行った時点でLGPLに汚染され、ユーザプログラムの配布に支障が出てしまう。 そこで、仕方なく<code>--without-libxml</code>をconfigure.jsのオプションに加え、XMLサポートを諦めた。調べてみると、iconv自体はPHP   5からPHP本体に組み込まれており、<code>php-5.2.5\ext\iconv</code>を見る限りクリーンルーム実装がなされている。このあたりlibxmlもどうにかできないものかと思うがここでは深く追及しない。</p>
<p>libxml/iconvの問題以外にもビルドプロセスには問題があり、ZLIBの関数も使用できないので<code>--disable-zlib</code>で無効にする。これでようやく<code>php-5.2.5\Release_TS</code>ないし<code>php-5.2.5\Debug_TS</code>に、アプリケーションにリンクするスタティックライブラリ(<code>php5embed.lib</code>)と実行時に必要なdllファイル(<code>php5ts.dll</code>)が出来上がる。次にVC++の設定として、メニューの「ツール   | オプション」からVC++のディレクトリにlibファイルの場所を追加し、さらにプロジェクト設定内のincludeファイルのフォルダに<code>php-5.2.5\</code>、<code>php-5.2.5\sapi\embed</code>、<code>php-5.2.5\Zend</code>、<code>php-5.2.5\TSRM</code>を加える。さらに、<code>PHP_WIN32</code>、<code>ZEND_WIN32</code>各シンボルの定義が必要となる。また、実際には、VC8からtime_tが64ビットになっているため<code>_USE_32BIT_TIME_T</code>も定義しなければクライアントコードのビルドは成功しない。以上でどうにか環境が整ったので、以下のコードがPHP組み込みのサンプルとしてビルド、実行できる。</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;stdio.h&gt;
#include &lt;tchar.h&gt;

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;cstdio&gt;

#include &lt;php.h&gt;
#include &lt;php_embed.h&gt;

using namespace std;

static int php_ub_write(const char* str, unsigned int str_length TSRMLS_DC)
{
	string s(str, str_length);

	cout &lt;&lt; s;

	return str_length;
}

static void php_log_message(char* message)
{
	cerr &lt;&lt; &quot;php_log_message: &quot; &lt;&lt; message  &lt;&lt; endl;
}

static void php_sapi_error(int type, const char* fmt, ...)
{
	va_list va;
	va_start(va, fmt);
	printf(&quot;php_sapi_error: &quot;);
	vprintf(fmt, va);
	va_end(va);
}

int _tmain(int argc, _TCHAR* argv[])
{
	php_embed_module.ub_write = php_ub_write;
	php_embed_module.log_message = php_log_message;
	php_embed_module.sapi_error = php_sapi_error;

	char* argv2[] = {&quot;&quot;};

	PHP_EMBED_START_BLOCK(0, argv2);

	zval* v = NULL;

	MAKE_STD_ZVAL(v);
	ZVAL_STRING(v, &quot;Hello&quot;, 1);
	ZEND_SET_SYMBOL(&amp;amp;EG(symbol_table), &quot;hello&quot;, v);

	zend_eval_string(&quot;print \&quot;$hello \&quot;;$hello = \&quot;World\&quot;;&quot;, NULL, &quot;&quot; TSRMLS_CC);

	if (v-&gt;type == IS_STRING)
	{
		cout &lt;&lt; string(v-&gt;value.str.val, v-&gt;value.str.len) &lt;&lt; endl;
	}

	PHP_EMBED_END_BLOCK();

    return 0;
}
</pre>
<p>PHP関係のヘッダは他の標準ヘッダの後に置かなければエラーが出るようだ。コードの内容は、上述のように出力関数をオーバライドし、さらに<code>$hello</code>という名称の変数を作成して操作し最終的にHello   Worldを表示するというたわいのないものである。<code>PHP_EMBED_START_BLOCK</code>、<code>PHP_EMBED_END_BLOCK</code>が初期化、終了のマクロで、内部で<code>zend_first_try</code>/<code>zend_catch</code>のブロックを作っているので変数のスコープに注意しなければならない。前回のPerl組み込みの場合だとPerlでの例外をラップする仕組みを自前で作る必要があったのに対し、PHPの方はZendが面倒を見てくれる点は有り難い。</p>
<p>とはいえ、このようにしてビルドした物だとPHP  5の特徴的機能であるところのXMLがおそらく使用できない事はかなりの損失である。そこで、次に考えられる方法として、PHPの配布バイナリ内のライブラリを利用するという道がある。PHPの配布バイナリには、(一体どうやってビルドしたのかは謎だが)<code>php5embed.lib</code>と<code>php5ts.dll</code>が含まれているのである。Dependency   Walkerで<code>php5ts.dll</code>を覗いてみてもCライブラリがスタティックリンクされているので一見使い勝手が良いように見える。ところが、落とし穴があり、デバッグ版だとVC++のdllが異なってくるので、これを使った場合正常にデバッグが出来なくなってしまう。そこで、開発の際には自分でビルドしたlibファイルを使い、リリース版は配布バイナリの方を利用することになる。</p>
<p>しかし、拍子抜けではあるが、最終的にDICEでは上述のようなストレートな組み込み方法は採らなかった。というのも、不透明なライセンスの問題に加え、上述のやり方ではPHPスクリプトやASP(Active   Server  Pages)の最も有用な機能である、コードブロックのHTML埋め込みが出来ないのである(出来る方法があるのかも知れないがそれは本稿の範囲を超える)。これではこちらで配布するWebサーバに組み込んで利用するという本来の目的にそぐわない。そこで、結局DICEの方にISAPIエクステンションのサポートを入れ、ISAPIを経由してPHPをロードする形に落ち着いた。PHPはSAPIという組み込みインタフェイスを用意しており、PHPの配布バイナリにはISAPIエクステンションのdllが含まれている。この組み込み方法であればライセンス問題は完全にクリーンであり、PHP設定ファイルの読み込みなどの付随的処理もPHP側で全て自動的に行ってくれる。PHPはかなり素直なISAPIアクセスしか行わないので、別にwebサーバへの組み込み用途ではなくても、Windows上で ライセンスが気になる場合等はPHPそのものの組み込みの代わりにISAPIを経由してコントロールするのも一つの有力な選択肢ではないかと思う。他方で、配布を目的とせずサーバ側でのみ利用する場合はライセンスに関する問題はもちろん発生しないため、最初に取り上げた組み込み手順もそれはそれで有用となる局面もあるだろう。</p>
]]></content:encoded>
			<wfw:commentRss>http://zzz.zggg.com/2008/02/11/windows-cpp-php-embedding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

