aboutsummaryrefslogtreecommitdiff
path: root/files/ja/mozilla/projects/spidermonkey/internals/thread_safety/index.html
blob: 90bfb3fb106d4dd3bfae65f635eaeafc665fe3ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
---
title: Thread Safety
slug: Mozilla/Projects/SpiderMonkey/Internals/Thread_Safety
tags:
  - JavaScript
  - SpiderMonkey
---
<p>This page describes implementation details of the <a href="/ja/SpiderMonkey" title="ja/SpiderMonkey">SpiderMonkey</a> JavaScript engine. It is mainly of interest to people working on SpiderMonkey itself, but this information is also helpful for anyone embedding SpiderMonkey in a multithreaded environment. See also <code><a href="/ja/JS_THREADSAFE" title="ja/JS_THREADSAFE">JS_THREADSAFE</a></code>.</p>
<p>{{ 英語版章題("General background") }}</p>
<h4 id="General_background" name="General_background">General background</h4>
<p>SpiderMonkeyは、最上位の構造体として<code><a href="/ja/JS_NewRuntime" title="ja/JS_NewRuntime">JSRuntime</a></code>を利用します。これらの構造体は、メモリの管理とグローバルなデータ構造を扱います。 通常の場合プログラムは、多くのスレッドを利用する場合でも、1つだけ<code>JSRuntime</code>を使います。<code>JSRuntime</code>は、JSオブジェクトが動作する 世界といってもよいでしょう。オブジェクトは、他の<code>JSRuntime</code>に移って動作することはできません。 <span class="comment">SpiderMonkey has a top-level struct, &lt;code&gt;<a href="/ja/JS_NewRuntime" title="ja/JS_NewRuntime">&lt;/code&gt;, that handles, among other things, memory management and "global" data structures. A program typically has only one &lt;code&gt;JSRuntime&lt;/code&gt;, even if it has many threads. The &lt;code&gt;JSRuntime&lt;/code&gt; is the universe in which JS objects live; they can't travel to other &lt;code&gt;JSRuntime&lt;/code&gt;s.</a></span></p>
<p>全てのJSコードとほとんどのJSAPIの呼び出しは、<code><a href="/ja/JS_NewContext" title="ja/JS_NewContext">JSContext</a></code>の中で動作します。<code>JSContext</code>は、 <code>JSRuntime</code>の子供のようなもので、例えば、例外の処理などは、<code>JSContext</code>ごとに実行されます。 各<code>JSContext</code>は、同時に複数スレッドからアクセスしてはなりません。 <span class="comment">All JS code and most JSAPI calls run within a &lt;code&gt;<a href="/ja/JS_NewContext" title="ja/JS_NewContext">JSContext</a>&lt;/code&gt;. The &lt;code&gt;JSContext&lt;/code&gt; is a child of the &lt;code&gt;JSRuntime&lt;/code&gt;; exception handling, for example, is per-&lt;code&gt;JSContext&lt;/code&gt;. Each &lt;code&gt;JSContext&lt;/code&gt; must be used by only one thread at a time.</span></p>
<p>オブジェクトは、同じ<code>JSRuntime</code>内の<code>JSContext</code>間で共有できます。コンテキストとオブジェクトの間には、固定的な関係はありません。 <span class="comment">Objects may be shared among &lt;code&gt;JSContext&lt;/code&gt;s within a &lt;code&gt;JSRuntime&lt;/code&gt;. There's no fixed association between an object and a context.</span></p>
<p>SpiderMonkeyにおけるスレッドセーフ機能は、<code>-DJS_THREADSAFE</code>をつけてコンパイルすることで有効になります。<code><a href="/ja/JS_THREADSAFE" title="ja/JS_THREADSAFE">JS_THREADSAFE</a></code>を有効にしたビルドでは、次のような操作について特別な処理が行われます。 <span class="comment">Thread-safety in SpiderMonkey is turned on by compiling with &lt;code&gt;-DJS_THREADSAFE&lt;/code&gt;. In a &lt;code&gt;<a href="/ja/JS_THREADSAFE" title="ja/JS_THREADSAFE">JS_THREADSAFE</a>&lt;/code&gt; build, these operations are handled specially:</span></p>
<ul> <li><code>JSRuntime</code>のデータ構造にアクセスする場合</li> <li>ガーベジコレクションを行う場合</li> <li>オブジェクトのプロパティにアクセスする場合</li>
</ul>
<p><span class="comment">* access to &lt;code&gt;JSRuntime&lt;/code&gt; data structures * garbage collection * access to properties of objects</span></p>
<p><code>JSRuntime</code>のデータ構造へのアクセスは、mutexによってシリアライズされます。 GCとプロパティに関する処理については、もう少し詳しく説明します。 <span class="comment">Accesses to &lt;code&gt;JSRuntime&lt;/code&gt; data structures are serialized with a few mutexes. The treatment of GC and properties requires more explanation.</span></p>
<p>{{ 英語版章題("Making GC thread-safe") }}</p>
<h4 id="Making_GC_thread-safe" name="Making_GC_thread-safe">Making GC thread-safe</h4>
<p><code>JS_THREADSAFE</code>を用いるときは、APIを若干変更します。プログラム中でJSAPIを呼び出すときは、次に示す"request"で くくらなくてはなりません。 <span class="comment">With &lt;code&gt;JS_THREADSAFE&lt;/code&gt;, the API changes slightly. The program must group JSAPI calls into "requests":</span></p>
<pre class="eval">   <a href="/ja/JS_SetContextThread" title="ja/JS_SetContextThread">JS_SetContextThread</a>(cx);
   <a href="/ja/JS_BeginRequest" title="ja/JS_BeginRequest">JS_BeginRequest</a>(cx);
   /* ... do stuff ... */
   <a href="/ja/JS_EndRequest" title="ja/JS_EndRequest">JS_EndRequest</a>(cx);
   <a href="/ja/JS_ClearContextThread" title="ja/JS_ClearContextThread">JS_ClearContextThread</a>(cx);
</pre>
<p>複数のスレッドがrequest内で同じ<code>JSRuntime</code>を同時にアクセスできるため、この操作がボトルネックになることはありません。詳細は<a href="/ja/JS_BeginRequest" title="ja/JS_BeginRequest">JS_BeginRequest</a>を参照してください。 <span class="comment">It isn't a bottleneck; multiple threads are allowed to be in requests on the same &lt;code&gt;JSRuntime&lt;/code&gt; at once. See <a href="/ja/JS_BeginRequest" title="ja/JS_BeginRequest">JS_BeginRequest</a>.</span></p>
<p>requestの最も顕著な効果は、いつでも複数のスレッドがrequestのくくりを実行することができるか、1つのスレッドだけがGCを実行していて他のスレッドが停止させられている 用にすることです。JS_GC()を呼び出しても、他のスレッドが停止させられるまでは、処理がブロックされます。つまり、他のスレッドがJSAPIを呼び出していないか (呼び出していないときには、特に注意する必要がないので)、JSAPIを実行中であってもGCが終了するのを待っているブロックしている状態になるまで、 GCの実行は停止させられます。 <span class="comment">The most obvious effect of a request is: at any given moment there can either be multiple threads in active requests, or one thread doing GC and all requests suspended. A call to JS_GC() will block until the latter becomes possible. In other words, GC waits until each other thread is either outside JSAPI (in which case we don't care what it's doing) or else in JSAPI, but blocked, waiting for GC to finish.</span></p>
<p>requestのくくりの中にいないときには、スレッドは、GCに影響を与えるような処理を行ってはいけません。 当たり前のことですが、requestのくくりの中では、GCが抑止されてしまうので、ブロックしたり、時間のかかる処理を行ってはいけません。 <span class="comment">Threads must not do anything that would affect GC while outside a request. And obviously you shouldn't block or otherwise dilly-dally while in a request; it prohibits GC. 最適化のために、スレッドには、スレッドごとの大きさごとに分けられた、割り当て可能なGC用のメモリの集合に関するフリーリストを持っています。 このリストにより、ほとんどの場合ロックせずにメモリを割り当てることができます。スレッドがロックを必要とするのは、スレッドの対応するフリーリストが 空だった場合だけです。このようなことが怒った場合に、ロックして広域のGC割り当てを行い、&lt;code&gt;JSRuntime&lt;/code&gt;から、フリーリストに領域を補充します。 &lt;!--As an optimization, each thread has its own size-classified freelists containing chunks of GC-managed memory ready to be allocated. This allows allocation to avoid locking most of the time (a significant speed win). A thread needs to lock on allocation only when the relevant per-thread freelist is empty. When this happens, the thread also refills that freelist from the &lt;code&gt;JSRuntime&lt;/code&gt;-wide GC allocator while it's in the lock.</span></p>
<p>{{ 英語版章題("Making property accesses thread-safe") }}</p>
<h4 id="Making_property_accesses_thread-safe" name="Making_property_accesses_thread-safe">Making property accesses thread-safe</h4>
<p>JSAPIのユーザにとっては、プロパティへのアクセスは全てシリアライズされているように見えます。これから記述する方法は、SpiderMonkeyの内部に関するもので ユーザにとっては見えない、最適化についてです。 <span class="comment">To the JSAPI user, all property accesses appear to be serialized. The scheme described below is an optimization, internal to SpiderMonkey and invisible to the user.</span></p>
<p>SpiderMonkeyの実装では、mutableなオブジェクトは必要に応じて暗黙のうちにロックされます。ロックの手順は、うまく最適化されていて、単なるmutexではありません。 <span class="comment">SpiderMonkey implicitly locks mutable objects as needed. The locking protocol is cleverly optimized. It's not a simple mutex.</span></p>
<p>それぞれの、mutableなオブジェクトは、<code>JSContext</code>が"占有"している(つまり、コンテキストがロックをしなくてもプロパティにアクセスできる) か、<code>JSRuntime</code>内の<code>JSContext</code>で、"共有"しているかのいずれかです。(繰り返しになりますが、JSAPIのユーザにとっては、全てのオブジェクトは 共有されており、この"所有関係"は、ユーザには見えないように最適化されています。) <span class="comment">Each mutable object is either "owned" by a &lt;code&gt;JSContext&lt;/code&gt;, meaning that context may access its properties without locking; or "shared" across all &lt;code&gt;JSContext&lt;/code&gt;s in the &lt;code&gt;JSRuntime&lt;/code&gt;. (Again, to the end user, all objects are shared--this "ownership" is a transparent optimization.)</span></p>
<p>初期状態では、オブジェクトの所有者は、オブジェクトを作った<code>JSContext&lt;/code.です。他の&lt;code&gt;JSContext</code>がオブジェクトにアクセスしようとするまでは、 ロックは全く必要ではありません。他のコンテキストがアクセスしようとした時点で、<code>JSRuntime</code>の広域ロックを取得します。ただ、この時点においても プロパティへの通常のアクセスは、1つのオブジェクト(つまり、プロパティを持っているオブジェクトのこと)のmutable部分に触る必要があるだけです。 従って、デッドロックは問題になりません。* また、スレッドがロックする必要がある場合でも、オブジェクトを所有しているコンテキストが requestのくくりを実行していないのであれば、コストのかかる他のスレッドとのランデブ**を避けることができます。 <span class="comment">Initially an object is owned by the &lt;code&gt;JSContext&lt;/code&gt; in which it was created. Locking is never needed until some other &lt;code&gt;JSContext&lt;/code&gt; tries to access the object. At that point, we acquire a &lt;code&gt;JSRuntime&lt;/code&gt;-wide lock. But even then, each ordinary property access only needs to touch mutable parts of one object (the one that has the property), so deadlock isn't an issue.* And even though the calling thread must lock, it can still avoid a costly rendezvous** with another thread, if the context that owns the object is not currently in a request.</span></p>
<p>I found it helpful to read the code for <code><a href="http://lxr.mozilla.org/seamonkey/ident?i=OBJ_GET_SLOT" class="external">OBJ_GET_SLOT</a></code>, defined in <a href="http://hg.mozilla.org/mozilla-central/?file/tip/js/src/jsobj.h" class="external">jsobj.h</a>, and track down the various things it calls.</p>
<pre class="eval">   /* Thread-safe functions and wrapper macros for accessing slots in obj. */
   #define OBJ_GET_SLOT(cx,obj,slot)                                     \
       (OBJ_CHECK_SLOT(obj, slot),                                       \
        (OBJ_IS_NATIVE(obj) &amp;&amp; OBJ_SCOPE(obj)-&gt;ownercx == cx)            \
        ? LOCKED_OBJ_GET_SLOT(obj, slot)                                 \
        : js_GetSlotThreadSafe(cx, obj, slot))
</pre>
<p>Here <code>OBJ_CHECK_SLOT()</code> is just an assertion. <code>LOCKED_OBJ_GET_SLOT()</code> is the fast path; it amounts to an array access. <code>OBJ_SCOPE(obj)-&gt;ownercx</code> is the object's owning context, or <code>NULL</code> if the object is "shared". (An <code>OBJ_SCOPE</code> is just a handy place to stick this field; it is often shared across multiple objects, so all this locking is somewhat higher than object-level.)</p>
<p>This may appear unsafe, at least in SMP environments where writing a word isn't guaranteed to make the new value immediately visible to other CPUs. Requests save the day again: entering or leaving a request always briefly acquires a lock, which forces a read-write barrier. This barrier is necessary and sufficient to make several of these optimizations safe.</p>
<p>In short, any <code>JSContext</code> may touch any object, yet not only is locking usually optimized away, the threads don't even have to execute atomic instructions or barrier instructions in the most common path.</p>
<hr>
<p>* deadlock isn't an issue: That is, SpiderMonkey doesn't need any special code to detect and avoid potential deadlock when getting or setting an ordinary property, because it can't happen--you're only locking one object at a time. Assigning to <code>__proto__</code> is an example of a special case: SpiderMonkey checks for prototype chain cycles, which means locking the whole chain. So in that case, and maybe others, SpiderMonkey does extra work to avoid deadlock.</p>
<p>** can still avoid a costly rendezvous: That is, it can avoid "asking" that thread to surrender the object and then waiting for the thread to respond. It just takes the object. See <a href="http://lxr.mozilla.org/seamonkey/ident?i=ClaimScope" class="external">ClaimScope</a> in jslock.c.</p>
<p>{{ 英語版章題("Patent") }}</p>
<h4 id="Patent" name="Patent">Patent</h4>
<p>The SpiderMonkey request model is patented: <a href="http://www.wipo.int/pctdb/en/wo.jsp?wo=2003042845" class=" external" rel="freelink">http://www.wipo.int/pctdb/en/wo.jsp?wo=2003042845</a></p>
<p>The Mozilla Public License in the SpiderMonkey source code grants a worldwide royalty-free license to this invention.</p>

<p>{{ languages( { "en": "en/SpiderMonkey_Internals/Thread_Safety" } ) }} </p>