system/corennnnn
リビジョン | 11440395e379f35069e8e39a6e3ccfa7a7bfc72f (tree) |
---|---|
日時 | 2016-08-17 07:52:46 |
作者 | Josh Gao <jmgao@goog...> |
コミッター | gitbuildkicker |
adb: switch the socket list mutex to a recursive_mutex.
sockets.cpp was branching on whether a socket close function was
local_socket_close in order to avoid a potential deadlock if the socket
list lock was held while closing a peer socket.
Bug: http://b/28347842
Change-Id: I5e56f17fa54275284787f0f1dc150d1960256ab3
(functionally a cherrypick of 903b749f + 9b587dec, with windows disabled)
@@ -200,7 +200,10 @@ endif | ||
200 | 200 | # will violate ODR |
201 | 201 | LOCAL_SHARED_LIBRARIES := |
202 | 202 | |
203 | +# Don't build the host adb on Windows (this branch should only be used for security updates.) | |
204 | +ifneq ($(HOST_OS),windows) | |
203 | 205 | include $(BUILD_HOST_EXECUTABLE) |
206 | +endif | |
204 | 207 | |
205 | 208 | $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE)) |
206 | 209 |
@@ -6,7 +6,6 @@ | ||
6 | 6 | #ifndef ADB_MUTEX |
7 | 7 | #error ADB_MUTEX not defined when including this file |
8 | 8 | #endif |
9 | -ADB_MUTEX(socket_list_lock) | |
10 | 9 | ADB_MUTEX(transport_lock) |
11 | 10 | #if ADB_HOST |
12 | 11 | ADB_MUTEX(local_transports_lock) |
@@ -25,18 +25,27 @@ | ||
25 | 25 | #include <string.h> |
26 | 26 | #include <unistd.h> |
27 | 27 | |
28 | +#include <algorithm> | |
29 | +#include <mutex> | |
30 | +#include <string> | |
31 | +#include <vector> | |
32 | + | |
28 | 33 | #if !ADB_HOST |
29 | 34 | #include "cutils/properties.h" |
30 | 35 | #endif |
31 | 36 | |
32 | 37 | #include "adb.h" |
33 | 38 | #include "adb_io.h" |
39 | +#include "sysdeps/mutex.h" | |
34 | 40 | #include "transport.h" |
35 | 41 | |
36 | -ADB_MUTEX_DEFINE( socket_list_lock ); | |
42 | +#if !defined(__BIONIC__) | |
43 | +using std::recursive_mutex; | |
44 | +#endif | |
37 | 45 | |
38 | -static void local_socket_close_locked(asocket *s); | |
46 | +static void local_socket_close(asocket* s); | |
39 | 47 | |
48 | +static recursive_mutex& local_socket_list_lock = *new recursive_mutex(); | |
40 | 49 | static unsigned local_socket_next_id = 1; |
41 | 50 | |
42 | 51 | static asocket local_socket_list = { |
@@ -61,7 +70,7 @@ asocket *find_local_socket(unsigned local_id, unsigned peer_id) | ||
61 | 70 | asocket *s; |
62 | 71 | asocket *result = NULL; |
63 | 72 | |
64 | - adb_mutex_lock(&socket_list_lock); | |
73 | + std::lock_guard<recursive_mutex> lock(local_socket_list_lock); | |
65 | 74 | for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { |
66 | 75 | if (s->id != local_id) |
67 | 76 | continue; |
@@ -70,7 +79,6 @@ asocket *find_local_socket(unsigned local_id, unsigned peer_id) | ||
70 | 79 | } |
71 | 80 | break; |
72 | 81 | } |
73 | - adb_mutex_unlock(&socket_list_lock); | |
74 | 82 | |
75 | 83 | return result; |
76 | 84 | } |
@@ -84,20 +92,17 @@ insert_local_socket(asocket* s, asocket* list) | ||
84 | 92 | s->next->prev = s; |
85 | 93 | } |
86 | 94 | |
87 | - | |
88 | -void install_local_socket(asocket *s) | |
89 | -{ | |
90 | - adb_mutex_lock(&socket_list_lock); | |
95 | +void install_local_socket(asocket* s) { | |
96 | + std::lock_guard<recursive_mutex> lock(local_socket_list_lock); | |
91 | 97 | |
92 | 98 | s->id = local_socket_next_id++; |
93 | 99 | |
94 | 100 | // Socket ids should never be 0. |
95 | - if (local_socket_next_id == 0) | |
96 | - local_socket_next_id = 1; | |
101 | + if (local_socket_next_id == 0) { | |
102 | + fatal("local socket id overflow"); | |
103 | + } | |
97 | 104 | |
98 | 105 | insert_local_socket(s, &local_socket_list); |
99 | - | |
100 | - adb_mutex_unlock(&socket_list_lock); | |
101 | 106 | } |
102 | 107 | |
103 | 108 | void remove_socket(asocket *s) |
@@ -116,19 +121,17 @@ void remove_socket(asocket *s) | ||
116 | 121 | void close_all_sockets(atransport *t) |
117 | 122 | { |
118 | 123 | asocket *s; |
119 | - | |
120 | - /* this is a little gross, but since s->close() *will* modify | |
121 | - ** the list out from under you, your options are limited. | |
122 | - */ | |
123 | - adb_mutex_lock(&socket_list_lock); | |
124 | + /* this is a little gross, but since s->close() *will* modify | |
125 | + ** the list out from under you, your options are limited. | |
126 | + */ | |
127 | + std::lock_guard<recursive_mutex> lock(local_socket_list_lock); | |
124 | 128 | restart: |
125 | - for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ | |
126 | - if(s->transport == t || (s->peer && s->peer->transport == t)) { | |
127 | - local_socket_close_locked(s); | |
129 | + for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { | |
130 | + if (s->transport == t || (s->peer && s->peer->transport == t)) { | |
131 | + local_socket_close(s); | |
128 | 132 | goto restart; |
129 | 133 | } |
130 | 134 | } |
131 | - adb_mutex_unlock(&socket_list_lock); | |
132 | 135 | } |
133 | 136 | |
134 | 137 | static int local_socket_enqueue(asocket *s, apacket *p) |
@@ -191,13 +194,6 @@ static void local_socket_ready(asocket *s) | ||
191 | 194 | fdevent_add(&s->fde, FDE_READ); |
192 | 195 | } |
193 | 196 | |
194 | -static void local_socket_close(asocket *s) | |
195 | -{ | |
196 | - adb_mutex_lock(&socket_list_lock); | |
197 | - local_socket_close_locked(s); | |
198 | - adb_mutex_unlock(&socket_list_lock); | |
199 | -} | |
200 | - | |
201 | 197 | // be sure to hold the socket list lock when calling this |
202 | 198 | static void local_socket_destroy(asocket *s) |
203 | 199 | { |
@@ -226,27 +222,21 @@ static void local_socket_destroy(asocket *s) | ||
226 | 222 | } |
227 | 223 | } |
228 | 224 | |
229 | - | |
230 | -static void local_socket_close_locked(asocket *s) | |
231 | -{ | |
232 | - D("entered local_socket_close_locked. LS(%d) fd=%d\n", s->id, s->fd); | |
233 | - if(s->peer) { | |
234 | - D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", | |
235 | - s->id, s->peer->id, s->peer->fd); | |
225 | +static void local_socket_close(asocket* s) { | |
226 | + D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd); | |
227 | + std::lock_guard<recursive_mutex> lock(local_socket_list_lock); | |
228 | + if (s->peer) { | |
229 | + D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); | |
236 | 230 | /* Note: it's important to call shutdown before disconnecting from |
237 | 231 | * the peer, this ensures that remote sockets can still get the id |
238 | 232 | * of the local socket they're connected to, to send a CLOSE() |
239 | 233 | * protocol event. */ |
240 | - if (s->peer->shutdown) | |
241 | - s->peer->shutdown(s->peer); | |
242 | - s->peer->peer = 0; | |
243 | - // tweak to avoid deadlock | |
244 | - if (s->peer->close == local_socket_close) { | |
245 | - local_socket_close_locked(s->peer); | |
246 | - } else { | |
247 | - s->peer->close(s->peer); | |
234 | + if (s->peer->shutdown) { | |
235 | + s->peer->shutdown(s->peer); | |
248 | 236 | } |
249 | - s->peer = 0; | |
237 | + s->peer->peer = nullptr; | |
238 | + s->peer->close(s->peer); | |
239 | + s->peer = nullptr; | |
250 | 240 | } |
251 | 241 | |
252 | 242 | /* If we are already closing, or if there are no |
@@ -0,0 +1,143 @@ | ||
1 | +#pragma once | |
2 | + | |
3 | +/* | |
4 | + * Copyright (C) 2016 The Android Open Source Project | |
5 | + * | |
6 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | + * you may not use this file except in compliance with the License. | |
8 | + * You may obtain a copy of the License at | |
9 | + * | |
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | + * | |
12 | + * Unless required by applicable law or agreed to in writing, software | |
13 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | + * See the License for the specific language governing permissions and | |
16 | + * limitations under the License. | |
17 | + */ | |
18 | + | |
19 | +#if defined(_WIN32) | |
20 | + | |
21 | +#include <windows.h> | |
22 | + | |
23 | +#include <android-base/macros.h> | |
24 | + | |
25 | +#include "adb.h" | |
26 | + | |
27 | +// The prebuilt version of mingw we use doesn't support mutex or recursive_mutex. | |
28 | +// Therefore, implement our own using the Windows primitives. | |
29 | +// Put them directly into the std namespace, so that when they're actually available, the build | |
30 | +// breaks until they're removed. | |
31 | + | |
32 | +#include <mutex> | |
33 | +namespace std { | |
34 | + | |
35 | +// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class. | |
36 | +class recursive_mutex { | |
37 | + public: | |
38 | + recursive_mutex() { | |
39 | + InitializeCriticalSection(&mutex_); | |
40 | + } | |
41 | + | |
42 | + ~recursive_mutex() { | |
43 | + DeleteCriticalSection(&mutex_); | |
44 | + } | |
45 | + | |
46 | + void lock() { | |
47 | + EnterCriticalSection(&mutex_); | |
48 | + } | |
49 | + | |
50 | + bool try_lock() { | |
51 | + return TryEnterCriticalSection(&mutex_); | |
52 | + } | |
53 | + | |
54 | + void unlock() { | |
55 | + LeaveCriticalSection(&mutex_); | |
56 | + } | |
57 | + | |
58 | + private: | |
59 | + CRITICAL_SECTION mutex_; | |
60 | + | |
61 | + DISALLOW_COPY_AND_ASSIGN(recursive_mutex); | |
62 | +}; | |
63 | + | |
64 | +class mutex { | |
65 | + public: | |
66 | + mutex() { | |
67 | + } | |
68 | + | |
69 | + ~mutex() { | |
70 | + } | |
71 | + | |
72 | + void lock() { | |
73 | + mutex_.lock(); | |
74 | + if (++lock_count_ != 1) { | |
75 | + fatal("non-recursive mutex locked reentrantly"); | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + void unlock() { | |
80 | + if (--lock_count_ != 0) { | |
81 | + fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_); | |
82 | + } | |
83 | + mutex_.unlock(); | |
84 | + } | |
85 | + | |
86 | + bool try_lock() { | |
87 | + if (!mutex_.try_lock()) { | |
88 | + return false; | |
89 | + } | |
90 | + | |
91 | + if (lock_count_ != 0) { | |
92 | + mutex_.unlock(); | |
93 | + return false; | |
94 | + } | |
95 | + | |
96 | + ++lock_count_; | |
97 | + return true; | |
98 | + } | |
99 | + | |
100 | + private: | |
101 | + recursive_mutex mutex_; | |
102 | + size_t lock_count_ = 0; | |
103 | +}; | |
104 | + | |
105 | +} | |
106 | + | |
107 | +#elif defined(__BIONIC__) | |
108 | + | |
109 | +// On M, the recovery image uses parts of adb that depends on recursive_mutex, and uses libstdc++, | |
110 | +// which lacks it. | |
111 | + | |
112 | +#include <pthread.h> | |
113 | +#include <mutex> | |
114 | + | |
115 | +#include <base/macros.h> | |
116 | + | |
117 | +class recursive_mutex { | |
118 | + public: | |
119 | + recursive_mutex() { | |
120 | + } | |
121 | + | |
122 | + ~recursive_mutex() { | |
123 | + } | |
124 | + | |
125 | + void lock() { | |
126 | + pthread_mutex_lock(&mutex_); | |
127 | + } | |
128 | + | |
129 | + bool try_lock() { | |
130 | + return pthread_mutex_trylock(&mutex_); | |
131 | + } | |
132 | + | |
133 | + void unlock() { | |
134 | + pthread_mutex_unlock(&mutex_); | |
135 | + } | |
136 | + | |
137 | + private: | |
138 | + pthread_mutex_t mutex_ = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; | |
139 | + | |
140 | + DISALLOW_COPY_AND_ASSIGN(recursive_mutex); | |
141 | +}; | |
142 | + | |
143 | +#endif |