| Index: third_party/mojo/src/mojo/edk/system/channel_endpoint.cc
|
| diff --git a/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc b/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc
|
| index 0e071d8eef50a2187b773dee198a9886f0307fd2..72d9e280669297aa888b139fc12080f7dfc4edc1 100644
|
| --- a/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc
|
| +++ b/third_party/mojo/src/mojo/edk/system/channel_endpoint.cc
|
| @@ -93,45 +93,18 @@ void ChannelEndpoint::AttachAndRun(Channel* channel,
|
| }
|
|
|
| void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) {
|
| - scoped_refptr<ChannelEndpointClient> client;
|
| - unsigned client_port = 0;
|
| -
|
| - // This loop is to make |ReplaceClient()| work. We can't call the client's
|
| - // |OnReadMessage()| under our lock, so by the time we do that, |client| may
|
| - // no longer be our client.
|
| - //
|
| - // In that case, |client| must return false. We'll then yield, and retry with
|
| - // the new client. (Theoretically, the client could be replaced again.)
|
| - //
|
| - // This solution isn't terribly elegant, but it's the least costly way of
|
| - // handling/avoiding this (very unlikely) race. (Other solutions -- e.g.,
|
| - // adding a client message queue, which the client only fetches messages from
|
| - // -- impose significant cost in the common case.)
|
| - for (;;) {
|
| - {
|
| - base::AutoLock locker(lock_);
|
| - if (!channel_ || !client_) {
|
| - // This isn't a failure per se. (It just means that, e.g., the other end
|
| - // of the message point closed first.)
|
| - return;
|
| - }
|
| -
|
| - // If we get here in a second (third, etc.) iteration of the loop, it's
|
| - // because |ReplaceClient()| was called.
|
| - DCHECK(client_ != client || client_port_ != client_port);
|
| -
|
| - // Take a ref, and call |OnReadMessage()| outside the lock.
|
| - client = client_;
|
| - client_port = client_port_;
|
| - }
|
| + if (message->type() == MessageInTransit::kTypeEndpointClient) {
|
| + OnReadMessageForClient(message.Pass());
|
| + return;
|
| + }
|
|
|
| - if (client->OnReadMessage(client_port, message.get())) {
|
| - ignore_result(message.release());
|
| - break;
|
| - }
|
| + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint);
|
|
|
| - base::PlatformThread::YieldCurrentThread();
|
| - }
|
| + // TODO(vtl)
|
| + // Note that this won't crash on Release builds, which is important (since the
|
| + // other side may be malicious). Doing nothing is safe and will dispose of the
|
| + // message.
|
| + NOTREACHED();
|
| }
|
|
|
| void ChannelEndpoint::DetachFromChannel() {
|
| @@ -186,6 +159,51 @@ bool ChannelEndpoint::WriteMessageNoLock(scoped_ptr<MessageInTransit> message) {
|
| return channel_->WriteMessage(message.Pass());
|
| }
|
|
|
| +void ChannelEndpoint::OnReadMessageForClient(
|
| + scoped_ptr<MessageInTransit> message) {
|
| + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpointClient);
|
| +
|
| + scoped_refptr<ChannelEndpointClient> client;
|
| + unsigned client_port = 0;
|
| +
|
| + // This loop is to make |ReplaceClient()| work. We can't call the client's
|
| + // |OnReadMessage()| under our lock, so by the time we do that, |client| may
|
| + // no longer be our client.
|
| + //
|
| + // In that case, |client| must return false. We'll then yield, and retry with
|
| + // the new client. (Theoretically, the client could be replaced again.)
|
| + //
|
| + // This solution isn't terribly elegant, but it's the least costly way of
|
| + // handling/avoiding this (very unlikely) race. (Other solutions -- e.g.,
|
| + // adding a client message queue, which the client only fetches messages from
|
| + // -- impose significant cost in the common case.)
|
| + for (;;) {
|
| + {
|
| + base::AutoLock locker(lock_);
|
| + if (!channel_ || !client_) {
|
| + // This isn't a failure per se. (It just means that, e.g., the other end
|
| + // of the message point closed first.)
|
| + return;
|
| + }
|
| +
|
| + // If we get here in a second (third, etc.) iteration of the loop, it's
|
| + // because |ReplaceClient()| was called.
|
| + DCHECK(client_ != client || client_port_ != client_port);
|
| +
|
| + // Take a ref, and call |OnReadMessage()| outside the lock.
|
| + client = client_;
|
| + client_port = client_port_;
|
| + }
|
| +
|
| + if (client->OnReadMessage(client_port, message.get())) {
|
| + ignore_result(message.release());
|
| + break;
|
| + }
|
| +
|
| + base::PlatformThread::YieldCurrentThread();
|
| + }
|
| +}
|
| +
|
| void ChannelEndpoint::ResetChannelNoLock() {
|
| DCHECK(channel_);
|
| DCHECK(local_id_.is_valid());
|
|
|