Loading adb/mutex_list.h +0 −1 Original line number Diff line number Diff line Loading @@ -8,7 +8,6 @@ #endif ADB_MUTEX(basename_lock) ADB_MUTEX(dirname_lock) ADB_MUTEX(socket_list_lock) ADB_MUTEX(transport_lock) #if ADB_HOST ADB_MUTEX(local_transports_lock) Loading adb/sockets.cpp +239 −268 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <unistd.h> #include <algorithm> #include <mutex> #include <string> #include <vector> Loading @@ -35,17 +36,16 @@ #include "adb.h" #include "adb_io.h" #include "sysdeps/mutex.h" #include "transport.h" ADB_MUTEX_DEFINE( socket_list_lock ); static void local_socket_close_locked(asocket *s); static void local_socket_close(asocket* s); static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex(); static unsigned local_socket_next_id = 1; static asocket local_socket_list = { .next = &local_socket_list, .prev = &local_socket_list, .next = &local_socket_list, .prev = &local_socket_list, }; /* the the list of currently closing local sockets. Loading @@ -53,62 +53,53 @@ static asocket local_socket_list = { ** write to their fd. */ static asocket local_socket_closing_list = { .next = &local_socket_closing_list, .prev = &local_socket_closing_list, .next = &local_socket_closing_list, .prev = &local_socket_closing_list, }; // Parse the global list of sockets to find one with id |local_id|. // If |peer_id| is not 0, also check that it is connected to a peer // with id |peer_id|. Returns an asocket handle on success, NULL on failure. asocket *find_local_socket(unsigned local_id, unsigned peer_id) { asocket* find_local_socket(unsigned local_id, unsigned peer_id) { asocket* s; asocket* result = NULL; adb_mutex_lock(&socket_list_lock); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { if (s->id != local_id) if (s->id != local_id) { continue; } if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) { result = s; } break; } adb_mutex_unlock(&socket_list_lock); return result; } static void insert_local_socket(asocket* s, asocket* list) { static void insert_local_socket(asocket* s, asocket* list) { s->next = list; s->prev = s->next->prev; s->prev->next = s; s->next->prev = s; } void install_local_socket(asocket *s) { adb_mutex_lock(&socket_list_lock); void install_local_socket(asocket* s) { std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); s->id = local_socket_next_id++; // Socket ids should never be 0. if (local_socket_next_id == 0) local_socket_next_id = 1; if (local_socket_next_id == 0) { fatal("local socket id overflow"); } insert_local_socket(s, &local_socket_list); adb_mutex_unlock(&socket_list_lock); } void remove_socket(asocket *s) { void remove_socket(asocket* s) { // socket_list_lock should already be held if (s->prev && s->next) { if (s->prev && s->next) { s->prev->next = s->next; s->next->prev = s->prev; s->next = 0; Loading @@ -117,26 +108,23 @@ void remove_socket(asocket *s) } } void close_all_sockets(atransport *t) { void close_all_sockets(atransport* t) { asocket* s; /* this is a little gross, but since s->close() *will* modify ** the list out from under you, your options are limited. */ adb_mutex_lock(&socket_list_lock); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); restart: for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { if (s->transport == t || (s->peer && s->peer->transport == t)) { local_socket_close_locked(s); local_socket_close(s); goto restart; } } adb_mutex_unlock(&socket_list_lock); } static int local_socket_enqueue(asocket *s, apacket *p) { static int local_socket_enqueue(asocket* s, apacket* p) { D("LS(%d): enqueue %d", s->id, p->len); p->ptr = p->data; Loading Loading @@ -190,23 +178,14 @@ enqueue: return 1; /* not ready (backlog) */ } static void local_socket_ready(asocket *s) { static void local_socket_ready(asocket* s) { /* far side is ready for data, pay attention to readable events */ fdevent_add(&s->fde, FDE_READ); } static void local_socket_close(asocket *s) { adb_mutex_lock(&socket_list_lock); local_socket_close_locked(s); adb_mutex_unlock(&socket_list_lock); } // be sure to hold the socket list lock when calling this static void local_socket_destroy(asocket *s) { static void local_socket_destroy(asocket* s) { apacket *p, *n; int exit_on_close = s->exit_on_close; Loading @@ -232,27 +211,21 @@ static void local_socket_destroy(asocket *s) } } static void local_socket_close_locked(asocket *s) { D("entered local_socket_close_locked. LS(%d) fd=%d", s->id, s->fd); static void local_socket_close(asocket* s) { D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); if (s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); /* Note: it's important to call shutdown before disconnecting from * the peer, this ensures that remote sockets can still get the id * of the local socket they're connected to, to send a CLOSE() * protocol event. */ if (s->peer->shutdown) if (s->peer->shutdown) { s->peer->shutdown(s->peer); s->peer->peer = 0; // tweak to avoid deadlock if (s->peer->close == local_socket_close) { local_socket_close_locked(s->peer); } else { s->peer->close(s->peer); } s->peer = 0; s->peer->peer = nullptr; s->peer->close(s->peer); s->peer = nullptr; } /* If we are already closing, or if there are no Loading @@ -276,8 +249,7 @@ static void local_socket_close_locked(asocket *s) CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE); } static void local_socket_event_func(int fd, unsigned ev, void* _s) { static void local_socket_event_func(int fd, unsigned ev, void* _s) { asocket* s = reinterpret_cast<asocket*>(_s); D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev); Loading Loading @@ -334,7 +306,6 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) s->peer->ready(s->peer); } if (ev & FDE_READ) { apacket* p = get_apacket(); unsigned char* x = p->data; Loading @@ -345,8 +316,8 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) while (avail > 0) { r = adb_read(fd, x, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, r < 0 ? errno : 0, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, r < 0 ? errno : 0, avail); if (r == -1) { if (errno == EAGAIN) { break; Loading @@ -361,8 +332,8 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof, s->fde.force_eof); D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof, s->fde.force_eof); if ((avail == max_payload) || (s->peer == 0)) { put_apacket(p); } else { Loading Loading @@ -397,8 +368,7 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) } /* Don't allow a forced eof if data is still there */ if ((s->fde.force_eof && !r) || is_eof) { D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof); D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof); s->close(s); return; } Loading @@ -414,10 +384,11 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) } } asocket *create_local_socket(int fd) { asocket* create_local_socket(int fd) { asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); if (s == NULL) { fatal("cannot allocate socket"); } s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; Loading @@ -430,9 +401,7 @@ asocket *create_local_socket(int fd) return s; } asocket *create_local_service_socket(const char *name, const atransport* transport) { asocket* create_local_service_socket(const char* name, const atransport* transport) { #if !ADB_HOST if (!strcmp(name, "jdwp")) { return create_jdwp_service_socket(); Loading @@ -442,20 +411,23 @@ asocket *create_local_service_socket(const char *name, } #endif int fd = service_to_fd(name, transport); if(fd < 0) return 0; if (fd < 0) { return 0; } asocket* s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d", s->id, name, fd); #if !ADB_HOST char debug[PROPERTY_VALUE_MAX]; if (!strncmp(name, "root:", 5)) if (!strncmp(name, "root:", 5)) { property_get("ro.debuggable", debug, ""); } if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close", s->id); s->exit_on_close = 1; } Loading @@ -465,8 +437,7 @@ asocket *create_local_service_socket(const char *name, } #if ADB_HOST static asocket *create_host_service_socket(const char *name, const char* serial) { static asocket* create_host_service_socket(const char* name, const char* serial) { asocket* s; s = host_service_to_socket(name, serial); Loading @@ -480,10 +451,8 @@ static asocket *create_host_service_socket(const char *name, const char* serial) } #endif /* ADB_HOST */ static int remote_socket_enqueue(asocket *s, apacket *p) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); static int remote_socket_enqueue(asocket* s, apacket* p) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); p->msg.command = A_WRTE; p->msg.arg0 = s->peer->id; p->msg.arg1 = s->id; Loading @@ -492,10 +461,8 @@ static int remote_socket_enqueue(asocket *s, apacket *p) return 1; } static void remote_socket_ready(asocket *s) { D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); static void remote_socket_ready(asocket* s) { D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); apacket* p = get_apacket(); p->msg.command = A_OKAY; p->msg.arg0 = s->peer->id; Loading @@ -503,10 +470,9 @@ static void remote_socket_ready(asocket *s) send_packet(p, s->transport); } static void remote_socket_shutdown(asocket *s) { D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer?s->peer->fd:-1); static void remote_socket_shutdown(asocket* s) { D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer ? s->peer->fd : -1); apacket* p = get_apacket(); p->msg.command = A_CLSE; if (s->peer) { Loading @@ -516,16 +482,14 @@ static void remote_socket_shutdown(asocket *s) send_packet(p, s->transport); } static void remote_socket_close(asocket *s) { static void remote_socket_close(asocket* s) { if (s->peer) { s->peer->peer = 0; D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); s->peer->close(s->peer); } D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer?s->peer->fd:-1); D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer ? s->peer->fd : -1); D("RS(%d): closed", s->id); free(s); } Loading @@ -534,12 +498,15 @@ static void remote_socket_close(asocket *s) // |t|. Where |id| is the socket id of the corresponding service on the other // side of the transport (it is allocated by the remote side and _cannot_ be 0). // Returns a new non-NULL asocket handle. asocket *create_remote_socket(unsigned id, atransport *t) { if (id == 0) fatal("invalid remote socket id (0)"); asocket* create_remote_socket(unsigned id, atransport* t) { if (id == 0) { fatal("invalid remote socket id (0)"); } asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); if (s == NULL) { fatal("cannot allocate socket"); } s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; Loading @@ -551,8 +518,7 @@ asocket *create_remote_socket(unsigned id, atransport *t) return s; } void connect_to_remote(asocket *s, const char *destination) { void connect_to_remote(asocket* s, const char* destination) { D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd); apacket* p = get_apacket(); size_t len = strlen(destination) + 1; Loading @@ -569,11 +535,9 @@ void connect_to_remote(asocket *s, const char *destination) send_packet(p, s->transport); } /* this is used by magic sockets to rig local sockets to send the go-ahead message when they connect */ static void local_socket_ready_notify(asocket *s) { static void local_socket_ready_notify(asocket* s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; Loading @@ -584,8 +548,7 @@ static void local_socket_ready_notify(asocket *s) /* this is used by magic sockets to rig local sockets to send the failure message if they are closed before connected (to avoid closing them without a status message) */ static void local_socket_close_notify(asocket *s) { static void local_socket_close_notify(asocket* s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; Loading @@ -593,24 +556,37 @@ static void local_socket_close_notify(asocket *s) s->close(s); } static unsigned unhex(unsigned char *s, int len) { static unsigned unhex(unsigned char* s, int len) { unsigned n = 0, c; while (len-- > 0) { switch ((c = *s++)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c -= '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c - 'A' + 10; break; default: Loading Loading @@ -673,8 +649,7 @@ char* skip_host_serial(char* service) { #endif // ADB_HOST static int smart_socket_enqueue(asocket *s, apacket *p) { static int smart_socket_enqueue(asocket* s, apacket* p) { unsigned len; #if ADB_HOST char* service = nullptr; Loading @@ -694,8 +669,7 @@ static int smart_socket_enqueue(asocket *s, apacket *p) goto fail; } memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); s->pkt_first->len += p->len; put_apacket(p); Loading @@ -703,7 +677,9 @@ static int smart_socket_enqueue(asocket *s, apacket *p) } /* don't bother if we can't decode the length */ if(p->len < 4) return 0; if (p->len < 4) { return 0; } len = unhex(p->data, 4); if ((len < 1) || (len > MAX_PAYLOAD_V1)) { Loading Loading @@ -819,7 +795,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p) goto fail; } /* instrument our peer to pass the success or fail ** message back once it connects or closes, then ** detach from it, request the connection, and Loading @@ -846,13 +821,11 @@ fail: return -1; } static void smart_socket_ready(asocket *s) { static void smart_socket_ready(asocket* s) { D("SS(%d): ready", s->id); } static void smart_socket_close(asocket *s) { static void smart_socket_close(asocket* s) { D("SS(%d): closed", s->id); if (s->pkt_first) { put_apacket(s->pkt_first); Loading @@ -865,8 +838,7 @@ static void smart_socket_close(asocket *s) free(s); } static asocket *create_smart_socket(void) { static asocket* create_smart_socket(void) { D("Creating smart socket"); asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); Loading @@ -879,8 +851,7 @@ static asocket *create_smart_socket(void) return s; } void connect_to_smartsocket(asocket *s) { void connect_to_smartsocket(asocket* s) { D("Connecting to smart socket"); asocket* ss = create_smart_socket(); s->peer = ss; Loading adb/sysdeps/mutex.h 0 → 100644 +107 −0 Original line number Diff line number Diff line #pragma once /* * Copyright (C) 2016 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. */ #if defined(_WIN32) #include <windows.h> #include <android-base/macros.h> #include "adb.h" // The prebuilt version of mingw we use doesn't support mutex or recursive_mutex. // Therefore, implement our own using the Windows primitives. // Put them directly into the std namespace, so that when they're actually available, the build // breaks until they're removed. #include <mutex> namespace std { // CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class. class recursive_mutex { public: recursive_mutex() { InitializeCriticalSection(&mutex_); } ~recursive_mutex() { DeleteCriticalSection(&mutex_); } void lock() { EnterCriticalSection(&mutex_); } bool try_lock() { return TryEnterCriticalSection(&mutex_); } void unlock() { LeaveCriticalSection(&mutex_); } private: CRITICAL_SECTION mutex_; DISALLOW_COPY_AND_ASSIGN(recursive_mutex); }; class mutex { public: mutex() { } ~mutex() { } void lock() { mutex_.lock(); if (++lock_count_ != 1) { fatal("non-recursive mutex locked reentrantly"); } } void unlock() { if (--lock_count_ != 0) { fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_); } mutex_.unlock(); } bool try_lock() { if (!mutex_.try_lock()) { return false; } if (lock_count_ != 0) { mutex_.unlock(); return false; } ++lock_count_; return true; } private: recursive_mutex mutex_; size_t lock_count_ = 0; }; } #endif adb/sysdeps_test.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -244,3 +244,60 @@ TEST_F(sysdeps_poll, fd_count) { adb_close(fd); } } #include "sysdeps/mutex.h" TEST(sysdeps_mutex, mutex_smoke) { static std::atomic<bool> finished(false); static std::mutex &m = *new std::mutex(); m.lock(); ASSERT_FALSE(m.try_lock()); adb_thread_create([](void*) { ASSERT_FALSE(m.try_lock()); m.lock(); finished.store(true); adb_sleep_ms(200); m.unlock(); }, nullptr); ASSERT_FALSE(finished.load()); adb_sleep_ms(100); ASSERT_FALSE(finished.load()); m.unlock(); adb_sleep_ms(100); m.lock(); ASSERT_TRUE(finished.load()); m.unlock(); } // Our implementation on Windows aborts on double lock. #if defined(_WIN32) TEST(sysdeps_mutex, mutex_reentrant_lock) { std::mutex &m = *new std::mutex(); m.lock(); ASSERT_FALSE(m.try_lock()); EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly"); } #endif TEST(sysdeps_mutex, recursive_mutex_smoke) { static std::recursive_mutex &m = *new std::recursive_mutex(); m.lock(); ASSERT_TRUE(m.try_lock()); m.unlock(); adb_thread_create([](void*) { ASSERT_FALSE(m.try_lock()); m.lock(); adb_sleep_ms(500); m.unlock(); }, nullptr); adb_sleep_ms(100); m.unlock(); adb_sleep_ms(100); ASSERT_FALSE(m.try_lock()); m.lock(); m.unlock(); } Loading
adb/mutex_list.h +0 −1 Original line number Diff line number Diff line Loading @@ -8,7 +8,6 @@ #endif ADB_MUTEX(basename_lock) ADB_MUTEX(dirname_lock) ADB_MUTEX(socket_list_lock) ADB_MUTEX(transport_lock) #if ADB_HOST ADB_MUTEX(local_transports_lock) Loading
adb/sockets.cpp +239 −268 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <unistd.h> #include <algorithm> #include <mutex> #include <string> #include <vector> Loading @@ -35,17 +36,16 @@ #include "adb.h" #include "adb_io.h" #include "sysdeps/mutex.h" #include "transport.h" ADB_MUTEX_DEFINE( socket_list_lock ); static void local_socket_close_locked(asocket *s); static void local_socket_close(asocket* s); static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex(); static unsigned local_socket_next_id = 1; static asocket local_socket_list = { .next = &local_socket_list, .prev = &local_socket_list, .next = &local_socket_list, .prev = &local_socket_list, }; /* the the list of currently closing local sockets. Loading @@ -53,62 +53,53 @@ static asocket local_socket_list = { ** write to their fd. */ static asocket local_socket_closing_list = { .next = &local_socket_closing_list, .prev = &local_socket_closing_list, .next = &local_socket_closing_list, .prev = &local_socket_closing_list, }; // Parse the global list of sockets to find one with id |local_id|. // If |peer_id| is not 0, also check that it is connected to a peer // with id |peer_id|. Returns an asocket handle on success, NULL on failure. asocket *find_local_socket(unsigned local_id, unsigned peer_id) { asocket* find_local_socket(unsigned local_id, unsigned peer_id) { asocket* s; asocket* result = NULL; adb_mutex_lock(&socket_list_lock); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { if (s->id != local_id) if (s->id != local_id) { continue; } if (peer_id == 0 || (s->peer && s->peer->id == peer_id)) { result = s; } break; } adb_mutex_unlock(&socket_list_lock); return result; } static void insert_local_socket(asocket* s, asocket* list) { static void insert_local_socket(asocket* s, asocket* list) { s->next = list; s->prev = s->next->prev; s->prev->next = s; s->next->prev = s; } void install_local_socket(asocket *s) { adb_mutex_lock(&socket_list_lock); void install_local_socket(asocket* s) { std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); s->id = local_socket_next_id++; // Socket ids should never be 0. if (local_socket_next_id == 0) local_socket_next_id = 1; if (local_socket_next_id == 0) { fatal("local socket id overflow"); } insert_local_socket(s, &local_socket_list); adb_mutex_unlock(&socket_list_lock); } void remove_socket(asocket *s) { void remove_socket(asocket* s) { // socket_list_lock should already be held if (s->prev && s->next) { if (s->prev && s->next) { s->prev->next = s->next; s->next->prev = s->prev; s->next = 0; Loading @@ -117,26 +108,23 @@ void remove_socket(asocket *s) } } void close_all_sockets(atransport *t) { void close_all_sockets(atransport* t) { asocket* s; /* this is a little gross, but since s->close() *will* modify ** the list out from under you, your options are limited. */ adb_mutex_lock(&socket_list_lock); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); restart: for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { if (s->transport == t || (s->peer && s->peer->transport == t)) { local_socket_close_locked(s); local_socket_close(s); goto restart; } } adb_mutex_unlock(&socket_list_lock); } static int local_socket_enqueue(asocket *s, apacket *p) { static int local_socket_enqueue(asocket* s, apacket* p) { D("LS(%d): enqueue %d", s->id, p->len); p->ptr = p->data; Loading Loading @@ -190,23 +178,14 @@ enqueue: return 1; /* not ready (backlog) */ } static void local_socket_ready(asocket *s) { static void local_socket_ready(asocket* s) { /* far side is ready for data, pay attention to readable events */ fdevent_add(&s->fde, FDE_READ); } static void local_socket_close(asocket *s) { adb_mutex_lock(&socket_list_lock); local_socket_close_locked(s); adb_mutex_unlock(&socket_list_lock); } // be sure to hold the socket list lock when calling this static void local_socket_destroy(asocket *s) { static void local_socket_destroy(asocket* s) { apacket *p, *n; int exit_on_close = s->exit_on_close; Loading @@ -232,27 +211,21 @@ static void local_socket_destroy(asocket *s) } } static void local_socket_close_locked(asocket *s) { D("entered local_socket_close_locked. LS(%d) fd=%d", s->id, s->fd); static void local_socket_close(asocket* s) { D("entered local_socket_close. LS(%d) fd=%d", s->id, s->fd); std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock); if (s->peer) { D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); D("LS(%d): closing peer. peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); /* Note: it's important to call shutdown before disconnecting from * the peer, this ensures that remote sockets can still get the id * of the local socket they're connected to, to send a CLOSE() * protocol event. */ if (s->peer->shutdown) if (s->peer->shutdown) { s->peer->shutdown(s->peer); s->peer->peer = 0; // tweak to avoid deadlock if (s->peer->close == local_socket_close) { local_socket_close_locked(s->peer); } else { s->peer->close(s->peer); } s->peer = 0; s->peer->peer = nullptr; s->peer->close(s->peer); s->peer = nullptr; } /* If we are already closing, or if there are no Loading @@ -276,8 +249,7 @@ static void local_socket_close_locked(asocket *s) CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE); } static void local_socket_event_func(int fd, unsigned ev, void* _s) { static void local_socket_event_func(int fd, unsigned ev, void* _s) { asocket* s = reinterpret_cast<asocket*>(_s); D("LS(%d): event_func(fd=%d(==%d), ev=%04x)", s->id, s->fd, fd, ev); Loading Loading @@ -334,7 +306,6 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) s->peer->ready(s->peer); } if (ev & FDE_READ) { apacket* p = get_apacket(); unsigned char* x = p->data; Loading @@ -345,8 +316,8 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) while (avail > 0) { r = adb_read(fd, x, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, r < 0 ? errno : 0, avail); D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu", s->id, s->fd, r, r < 0 ? errno : 0, avail); if (r == -1) { if (errno == EAGAIN) { break; Loading @@ -361,8 +332,8 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) is_eof = 1; break; } D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof, s->fde.force_eof); D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof, s->fde.force_eof); if ((avail == max_payload) || (s->peer == 0)) { put_apacket(p); } else { Loading Loading @@ -397,8 +368,7 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) } /* Don't allow a forced eof if data is still there */ if ((s->fde.force_eof && !r) || is_eof) { D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof); D(" closing because is_eof=%d r=%d s->fde.force_eof=%d", is_eof, r, s->fde.force_eof); s->close(s); return; } Loading @@ -414,10 +384,11 @@ static void local_socket_event_func(int fd, unsigned ev, void* _s) } } asocket *create_local_socket(int fd) { asocket* create_local_socket(int fd) { asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); if (s == NULL) { fatal("cannot allocate socket"); } s->fd = fd; s->enqueue = local_socket_enqueue; s->ready = local_socket_ready; Loading @@ -430,9 +401,7 @@ asocket *create_local_socket(int fd) return s; } asocket *create_local_service_socket(const char *name, const atransport* transport) { asocket* create_local_service_socket(const char* name, const atransport* transport) { #if !ADB_HOST if (!strcmp(name, "jdwp")) { return create_jdwp_service_socket(); Loading @@ -442,20 +411,23 @@ asocket *create_local_service_socket(const char *name, } #endif int fd = service_to_fd(name, transport); if(fd < 0) return 0; if (fd < 0) { return 0; } asocket* s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d", s->id, name, fd); #if !ADB_HOST char debug[PROPERTY_VALUE_MAX]; if (!strncmp(name, "root:", 5)) if (!strncmp(name, "root:", 5)) { property_get("ro.debuggable", debug, ""); } if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close", s->id); s->exit_on_close = 1; } Loading @@ -465,8 +437,7 @@ asocket *create_local_service_socket(const char *name, } #if ADB_HOST static asocket *create_host_service_socket(const char *name, const char* serial) { static asocket* create_host_service_socket(const char* name, const char* serial) { asocket* s; s = host_service_to_socket(name, serial); Loading @@ -480,10 +451,8 @@ static asocket *create_host_service_socket(const char *name, const char* serial) } #endif /* ADB_HOST */ static int remote_socket_enqueue(asocket *s, apacket *p) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); static int remote_socket_enqueue(asocket* s, apacket* p) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); p->msg.command = A_WRTE; p->msg.arg0 = s->peer->id; p->msg.arg1 = s->id; Loading @@ -492,10 +461,8 @@ static int remote_socket_enqueue(asocket *s, apacket *p) return 1; } static void remote_socket_ready(asocket *s) { D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); static void remote_socket_ready(asocket* s) { D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); apacket* p = get_apacket(); p->msg.command = A_OKAY; p->msg.arg0 = s->peer->id; Loading @@ -503,10 +470,9 @@ static void remote_socket_ready(asocket *s) send_packet(p, s->transport); } static void remote_socket_shutdown(asocket *s) { D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer?s->peer->fd:-1); static void remote_socket_shutdown(asocket* s) { D("entered remote_socket_shutdown RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer ? s->peer->fd : -1); apacket* p = get_apacket(); p->msg.command = A_CLSE; if (s->peer) { Loading @@ -516,16 +482,14 @@ static void remote_socket_shutdown(asocket *s) send_packet(p, s->transport); } static void remote_socket_close(asocket *s) { static void remote_socket_close(asocket* s) { if (s->peer) { s->peer->peer = 0; D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd); s->peer->close(s->peer); } D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer?s->peer->fd:-1); D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd, s->peer ? s->peer->fd : -1); D("RS(%d): closed", s->id); free(s); } Loading @@ -534,12 +498,15 @@ static void remote_socket_close(asocket *s) // |t|. Where |id| is the socket id of the corresponding service on the other // side of the transport (it is allocated by the remote side and _cannot_ be 0). // Returns a new non-NULL asocket handle. asocket *create_remote_socket(unsigned id, atransport *t) { if (id == 0) fatal("invalid remote socket id (0)"); asocket* create_remote_socket(unsigned id, atransport* t) { if (id == 0) { fatal("invalid remote socket id (0)"); } asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); if (s == NULL) { fatal("cannot allocate socket"); } s->id = id; s->enqueue = remote_socket_enqueue; s->ready = remote_socket_ready; Loading @@ -551,8 +518,7 @@ asocket *create_remote_socket(unsigned id, atransport *t) return s; } void connect_to_remote(asocket *s, const char *destination) { void connect_to_remote(asocket* s, const char* destination) { D("Connect_to_remote call RS(%d) fd=%d", s->id, s->fd); apacket* p = get_apacket(); size_t len = strlen(destination) + 1; Loading @@ -569,11 +535,9 @@ void connect_to_remote(asocket *s, const char *destination) send_packet(p, s->transport); } /* this is used by magic sockets to rig local sockets to send the go-ahead message when they connect */ static void local_socket_ready_notify(asocket *s) { static void local_socket_ready_notify(asocket* s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; Loading @@ -584,8 +548,7 @@ static void local_socket_ready_notify(asocket *s) /* this is used by magic sockets to rig local sockets to send the failure message if they are closed before connected (to avoid closing them without a status message) */ static void local_socket_close_notify(asocket *s) { static void local_socket_close_notify(asocket* s) { s->ready = local_socket_ready; s->shutdown = NULL; s->close = local_socket_close; Loading @@ -593,24 +556,37 @@ static void local_socket_close_notify(asocket *s) s->close(s); } static unsigned unhex(unsigned char *s, int len) { static unsigned unhex(unsigned char* s, int len) { unsigned n = 0, c; while (len-- > 0) { switch ((c = *s++)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c -= '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = c - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = c - 'A' + 10; break; default: Loading Loading @@ -673,8 +649,7 @@ char* skip_host_serial(char* service) { #endif // ADB_HOST static int smart_socket_enqueue(asocket *s, apacket *p) { static int smart_socket_enqueue(asocket* s, apacket* p) { unsigned len; #if ADB_HOST char* service = nullptr; Loading @@ -694,8 +669,7 @@ static int smart_socket_enqueue(asocket *s, apacket *p) goto fail; } memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); s->pkt_first->len += p->len; put_apacket(p); Loading @@ -703,7 +677,9 @@ static int smart_socket_enqueue(asocket *s, apacket *p) } /* don't bother if we can't decode the length */ if(p->len < 4) return 0; if (p->len < 4) { return 0; } len = unhex(p->data, 4); if ((len < 1) || (len > MAX_PAYLOAD_V1)) { Loading Loading @@ -819,7 +795,6 @@ static int smart_socket_enqueue(asocket *s, apacket *p) goto fail; } /* instrument our peer to pass the success or fail ** message back once it connects or closes, then ** detach from it, request the connection, and Loading @@ -846,13 +821,11 @@ fail: return -1; } static void smart_socket_ready(asocket *s) { static void smart_socket_ready(asocket* s) { D("SS(%d): ready", s->id); } static void smart_socket_close(asocket *s) { static void smart_socket_close(asocket* s) { D("SS(%d): closed", s->id); if (s->pkt_first) { put_apacket(s->pkt_first); Loading @@ -865,8 +838,7 @@ static void smart_socket_close(asocket *s) free(s); } static asocket *create_smart_socket(void) { static asocket* create_smart_socket(void) { D("Creating smart socket"); asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket))); if (s == NULL) fatal("cannot allocate socket"); Loading @@ -879,8 +851,7 @@ static asocket *create_smart_socket(void) return s; } void connect_to_smartsocket(asocket *s) { void connect_to_smartsocket(asocket* s) { D("Connecting to smart socket"); asocket* ss = create_smart_socket(); s->peer = ss; Loading
adb/sysdeps/mutex.h 0 → 100644 +107 −0 Original line number Diff line number Diff line #pragma once /* * Copyright (C) 2016 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. */ #if defined(_WIN32) #include <windows.h> #include <android-base/macros.h> #include "adb.h" // The prebuilt version of mingw we use doesn't support mutex or recursive_mutex. // Therefore, implement our own using the Windows primitives. // Put them directly into the std namespace, so that when they're actually available, the build // breaks until they're removed. #include <mutex> namespace std { // CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class. class recursive_mutex { public: recursive_mutex() { InitializeCriticalSection(&mutex_); } ~recursive_mutex() { DeleteCriticalSection(&mutex_); } void lock() { EnterCriticalSection(&mutex_); } bool try_lock() { return TryEnterCriticalSection(&mutex_); } void unlock() { LeaveCriticalSection(&mutex_); } private: CRITICAL_SECTION mutex_; DISALLOW_COPY_AND_ASSIGN(recursive_mutex); }; class mutex { public: mutex() { } ~mutex() { } void lock() { mutex_.lock(); if (++lock_count_ != 1) { fatal("non-recursive mutex locked reentrantly"); } } void unlock() { if (--lock_count_ != 0) { fatal("non-recursive mutex unlock resulted in unexpected lock count: %d", lock_count_); } mutex_.unlock(); } bool try_lock() { if (!mutex_.try_lock()) { return false; } if (lock_count_ != 0) { mutex_.unlock(); return false; } ++lock_count_; return true; } private: recursive_mutex mutex_; size_t lock_count_ = 0; }; } #endif
adb/sysdeps_test.cpp +57 −0 Original line number Diff line number Diff line Loading @@ -244,3 +244,60 @@ TEST_F(sysdeps_poll, fd_count) { adb_close(fd); } } #include "sysdeps/mutex.h" TEST(sysdeps_mutex, mutex_smoke) { static std::atomic<bool> finished(false); static std::mutex &m = *new std::mutex(); m.lock(); ASSERT_FALSE(m.try_lock()); adb_thread_create([](void*) { ASSERT_FALSE(m.try_lock()); m.lock(); finished.store(true); adb_sleep_ms(200); m.unlock(); }, nullptr); ASSERT_FALSE(finished.load()); adb_sleep_ms(100); ASSERT_FALSE(finished.load()); m.unlock(); adb_sleep_ms(100); m.lock(); ASSERT_TRUE(finished.load()); m.unlock(); } // Our implementation on Windows aborts on double lock. #if defined(_WIN32) TEST(sysdeps_mutex, mutex_reentrant_lock) { std::mutex &m = *new std::mutex(); m.lock(); ASSERT_FALSE(m.try_lock()); EXPECT_DEATH(m.lock(), "non-recursive mutex locked reentrantly"); } #endif TEST(sysdeps_mutex, recursive_mutex_smoke) { static std::recursive_mutex &m = *new std::recursive_mutex(); m.lock(); ASSERT_TRUE(m.try_lock()); m.unlock(); adb_thread_create([](void*) { ASSERT_FALSE(m.try_lock()); m.lock(); adb_sleep_ms(500); m.unlock(); }, nullptr); adb_sleep_ms(100); m.unlock(); adb_sleep_ms(100); ASSERT_FALSE(m.try_lock()); m.lock(); m.unlock(); }