| <html devsite> |
| <head> |
| <title>Threading Models</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| |
| <p>Methods marked as <code>oneway</code> do not block. For methods not marked as |
| <code>oneway</code>, a client's method call will block until the server has |
| completed execution or called a synchronous callback (whichever comes first). |
| Server method implementations may call at most one synchronous callback; extra |
| callback calls are discarded and logged as errors. If a method is supposed to |
| return values via callback and does not call its callback, this is logged as an |
| error and reported as a transport error to the client.</p> |
| |
| <h2 id=passthrough>Threads in passthrough mode</h2> |
| <p>In passthrough mode, most calls are synchronous. However, to preserve the |
| intended behavior that <code>oneway</code> calls do not block the client, a |
| thread is created for each process. For details, see the |
| <a href="/devices/architecture/hidl/index.html#passthrough">HIDL overview</a>. |
| </p> |
| |
| <h2 id=binderized>Threads in binderized HALs</h2> |
| <p>To serve incoming RPC calls (including asynchronous callbacks from HALs to |
| HAL users) and death notifications, a threadpool is associated with each process |
| that uses HIDL. If a single process implements multiple HIDL interfaces and/or |
| death notification handlers, its threadpool is shared between all of them. When |
| a process receives an incoming method call from a client, it picks a free thread |
| from the threadpool and executes the call on that thread. If no free thread is |
| available, it blocks until one is available.</p> |
| |
| <p>If the server has only one thread, then calls into the server are completed |
| in order. A server with more than one thread may complete calls out of order |
| even if the client has only one thread. However, for a given interface object, |
| <code>oneway</code> calls are guaranteed to be ordered (see |
| <a href="#model">Server threading model</a>). For a multi-threaded server that |
| hosts multiple interfaces, <code>oneway</code> calls to different interfaces |
| may be processed concurrently with each other or other blocking calls.</p> |
| |
| <p>Multiple nested calls will be sent on the same hwbinder thread. For instance, |
| if a process (A) makes a synchronous call from a hwbinder thread into process (B), |
| and then process (B) makes a synchronous call back into process (A), the call will |
| be executed on the original hwbinder thread in (A) which is blocked on the original |
| call. This optimization makes it possible to have a single threaded server able to |
| handle nested calls, but it does not extend to cases where the calls travel through |
| another sequence of IPC calls. For instance, if process (B) had made a |
| binder/vndbinder call which called into a process (C) and then process (C) calls |
| back into (A), it cannot be served on the original thread in (A).</p> |
| |
| <h2 id=model>Server threading model</h2> |
| <p>Except for passthrough mode, server implementations of HIDL interfaces live |
| in a different process than the client and need one or more threads waiting for |
| incoming method calls. These threads are the server's threadpool; the server may |
| decide how many threads it wants running in its threadpool, and can use a |
| threadpool size of one to serialize all calls on its interfaces. If the server |
| has more than one thread in the threadpool, it can receive concurrent incoming |
| calls on any of its interfaces (in C++, this means that shared data must be |
| carefully locked).</p> |
| |
| <p>Oneway calls into the same interface are serialized. If a multi-threaded |
| client calls <code>method1</code> and <code>method2</code> on interface |
| <code>IFoo</code>, and <code>method3</code> on interface <code>IBar</code>, |
| <code>method1</code> and <code>method2</code> will always be serialized, but |
| <code>method3</code> may run in parallel with <code>method1</code> and |
| <code>method2</code>.</p> |
| |
| <p>A single client thread of execution can cause concurrent execution on a |
| server with multiple threads in two ways:</p> |
| |
| <ul> |
| <li><code>oneway</code> calls do not block. If a <code>oneway</code> call is |
| executed and then a non-<code>oneway</code> is called, the server may execute |
| the <code>oneway</code> call and the non-<code>oneway</code> call |
| simultaneously.</li> |
| <li>Server methods that pass data back with synchronous callbacks can unblock |
| the client as soon as the callback is called from the server.</li> |
| </ul> |
| |
| <p>For the second way, any code in the server function that executes after the |
| callback is called may execute concurrently, with the server handling subsequent |
| calls from the client. This includes code in the server function and automatic |
| destructors that execute at the end of the function. If the server has more than |
| one thread in its threadpool, concurrency issues arise even if calls are coming |
| in from only one single client thread. (If any HAL served by a process needs |
| multiple threads, all HALs will have multiple threads because the threadpool is |
| shared per-process.)</p> |
| |
| <p>As soon as the server calls the provided callback, the transport can call the |
| implemented callback on the client and unblock the client. The client proceeds |
| in parallel with whatever the server implementation does after it calls the |
| callback (which may include running destructors). Code in the server function |
| after the callback is no longer blocking the client (as long as the server |
| threadpool has enough threads to handle incoming calls), but may be executed |
| concurrently with future calls from the client (unless the server threadpool has |
| only one thread).</p> |
| |
| <p>In addition to synchronous callbacks, <code>oneway</code> calls from a |
| single-threaded client may be handled concurrently by a server with multiple |
| threads in its threadpool, but only if those <code>oneway</code> calls are |
| executed on different interfaces. <code>oneway</code> calls on the same |
| interface are always serialized.</p> |
| |
| <p class=note><strong>Note:</strong> We strongly encourage server functions to |
| return as soon as they have called the callback function.</p> |
| |
| <p>For example (in C++):</p> |
| |
| <pre class="prettyprint"> |
| Return<void> someMethod(someMethod_cb _cb) { |
| // Do some processing, then call callback with return data |
| hidl_vec<uint32_t> vec = ... |
| _cb(vec); |
| // At this point, the client's callback will be called, |
| // and the client will resume execution. |
| ... |
| return Void(); // is basically a no-op |
| }; |
| </pre> |
| |
| <h2 id=client>Client threading model</h2> |
| <p>The threading model on the client differs between non-blocking calls |
| (functions that are marked with the <code>oneway</code> keyword) and blocking |
| calls (functions that do not have the <code>oneway</code> keyword specified).</p> |
| |
| <h3 id=block>Blocking calls</h3> |
| <p>For blocking calls, the client blocks until one of the following happens:</p> |
| |
| <ul> |
| <li>Transport error occurs; the <code>Return</code> object contains an error |
| state that can be retrieved with <code>Return::isOk()</code>.</li> |
| <li>Server implementation calls the callback (if there was one).</li> |
| <li>Server implementation returns a value (if there was no callback parameter). |
| </li> |
| </ul> |
| |
| <p>In case of success, the callback function the client passes as an argument is |
| always called by the server before the function itself returns. The callback is |
| executed on the same thread that the function call is made on, so implementers |
| must be careful with holding locks during function calls (and avoid them |
| altogether when possible). A function without a <code>generates</code> statement |
| or a <code>oneway</code> keyword is still blocking; the client blocks until the |
| server returns a <code>Return<void></code> object.</p> |
| |
| <h3 id=oneway>Oneway calls</h3> |
| <p>When a function is marked <code>oneway</code>, the client returns immediately |
| and does not wait for the server to complete its function call invocation. At the |
| surface (and in aggregate), this means the function call takes half the |
| time because it is executing half the code, but when writing implementations that |
| are performance sensitive, this has some scheduling implications. Normally, |
| using a oneway call causes the caller to continue to be scheduled whereas |
| using a normal synchronous call causes the scheduler to immediately transfer |
| from the caller to the callee process. This is a performance optimization in |
| binder. For services where the oneway call must be executed in the target process |
| with a high priority, the scheduling policy of the receiving service can be |
| changed. In C++, using <code>libhidltransport</code>'s method |
| <code>setMinSchedulerPolicy</code> with the scheduler priorities and policies |
| defined in <code>sched.h</code> ensures that all calls into the service run at |
| least at the set scheduling policy and priority.</p> |
| |
| </body> |
| </html> |