Loading liblog/include/log/log.h +5 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,11 @@ clockid_t android_log_clockid(void); /* * Release any logger resources (a new log write will immediately re-acquire) * * May be used to clean up File descriptors after a Fork, the resources are * all O_CLOEXEC so wil self clean on exec(). * This is specifically meant to be used by Zygote to close open file descriptors after fork() * and before specialization. O_CLOEXEC is used on file descriptors, so they will be closed upon * exec() in normal use cases. * * Note that this is not safe to call from a multi-threaded program. */ void __android_log_close(void); Loading liblog/logd_writer.cpp +28 −41 Original line number Diff line number Diff line Loading @@ -32,58 +32,53 @@ #include <time.h> #include <unistd.h> #include <shared_mutex> #include <private/android_filesystem_config.h> #include <private/android_logger.h> #include "logger.h" #include "rwlock.h" #include "uio.h" static int logd_socket; static RwLock logd_socket_lock; static void OpenSocketLocked() { logd_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); if (logd_socket <= 0) { return; } static atomic_int logd_socket; // Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this // function is used to reconnect to logd without requiring a new socket. static void LogdConnect() { sockaddr_un un = {}; un.sun_family = AF_UNIX; strcpy(un.sun_path, "/dev/socket/logdw"); if (TEMP_FAILURE_RETRY( connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))) < 0) { close(logd_socket); logd_socket = 0; } TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))); } static void OpenSocket() { auto lock = std::unique_lock{logd_socket_lock}; if (logd_socket > 0) { // Someone raced us and opened the socket already. // logd_socket should only be opened once. If we see that logd_socket is uninitialized, we create a // new socket and attempt to exchange it into the atomic logd_socket. If the compare/exchange was // successful, then that will be the socket used for the duration of the program, otherwise a // different thread has already opened and written the socket to the atomic, so close the new socket // and return. static void GetSocket() { if (logd_socket != 0) { return; } OpenSocketLocked(); int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); if (new_socket <= 0) { return; } static void ResetSocket(int old_socket) { auto lock = std::unique_lock{logd_socket_lock}; if (old_socket != logd_socket) { // Someone raced us and reset the socket already. int uninitialized_value = 0; if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) { close(new_socket); return; } close(logd_socket); logd_socket = 0; OpenSocketLocked(); LogdConnect(); } // This is the one exception to the above. Zygote uses this to clean up open FD's after fork() and // before specialization. It is single threaded at this point and therefore this function is // explicitly not thread safe. It sets logd_socket to 0, so future logs will be safely initialized // whenever they happen. void LogdClose() { auto lock = std::unique_lock{logd_socket_lock}; if (logd_socket > 0) { close(logd_socket); } Loading @@ -99,12 +94,7 @@ int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) static atomic_int dropped; static atomic_int droppedSecurity; auto lock = std::shared_lock{logd_socket_lock}; if (logd_socket <= 0) { lock.unlock(); OpenSocket(); lock.lock(); } GetSocket(); if (logd_socket <= 0) { return -EBADF; Loading Loading @@ -183,10 +173,7 @@ int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) // the connection, so we reset it and try again. ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i)); if (ret < 0 && errno != EAGAIN) { int old_socket = logd_socket; lock.unlock(); ResetSocket(old_socket); lock.lock(); LogdConnect(); ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i)); } Loading liblog/pmsg_writer.cpp +18 −18 Original line number Diff line number Diff line Loading @@ -23,30 +23,36 @@ #include <sys/types.h> #include <time.h> #include <shared_mutex> #include <log/log_properties.h> #include <private/android_logger.h> #include "logger.h" #include "rwlock.h" #include "uio.h" static int pmsg_fd; static RwLock pmsg_fd_lock; static atomic_int pmsg_fd; static void PmsgOpen() { auto lock = std::unique_lock{pmsg_fd_lock}; if (pmsg_fd > 0) { // Someone raced us and opened the socket already. // pmsg_fd should only beopened once. If we see that pmsg_fd is uninitialized, we open "/dev/pmsg0" // then attempt to compare/exchange it into pmsg_fd. If the compare/exchange was successful, then // that will be the fd used for the duration of the program, otherwise a different thread has // already opened and written the fd to the atomic, so close the new fd and return. static void GetPmsgFd() { if (pmsg_fd != 0) { return; } int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); if (new_fd <= 0) { return; } pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); int uninitialized_value = 0; if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) { close(new_fd); return; } } void PmsgClose() { auto lock = std::unique_lock{pmsg_fd_lock}; if (pmsg_fd > 0) { close(pmsg_fd); } Loading Loading @@ -77,13 +83,7 @@ int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) } } auto lock = std::shared_lock{pmsg_fd_lock}; if (pmsg_fd <= 0) { lock.unlock(); PmsgOpen(); lock.lock(); } GetPmsgFd(); if (pmsg_fd <= 0) { return -EBADF; Loading liblog/rwlock.hdeleted 100644 → 0 +0 −39 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #pragma once #include <pthread.h> // As of the end of Dec 2019, std::shared_mutex is *not* simply a pthread_rwlock, but rather a // combination of std::mutex and std::condition variable, which is obviously less efficient. This // immitates what std::shared_mutex should be doing and is compatible with std::shared_lock and // std::unique_lock. class RwLock { public: RwLock() {} ~RwLock() {} void lock() { pthread_rwlock_wrlock(&rwlock_); } void unlock() { pthread_rwlock_unlock(&rwlock_); } void lock_shared() { pthread_rwlock_rdlock(&rwlock_); } void unlock_shared() { pthread_rwlock_unlock(&rwlock_); } private: pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER; }; liblog/tests/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -63,8 +63,8 @@ cc_defaults { "log_system_test.cpp", "log_time_test.cpp", "log_wrap_test.cpp", "logd_writer_test.cpp", "logprint_test.cpp", "rwlock_test.cpp", ], shared_libs: [ "libcutils", Loading Loading @@ -108,7 +108,6 @@ cc_test_host { "liblog_host_test.cpp", "liblog_default_tag.cpp", "liblog_global_state.cpp", "rwlock_test.cpp", ], isolated: true, } Loading
liblog/include/log/log.h +5 −2 Original line number Diff line number Diff line Loading @@ -143,8 +143,11 @@ clockid_t android_log_clockid(void); /* * Release any logger resources (a new log write will immediately re-acquire) * * May be used to clean up File descriptors after a Fork, the resources are * all O_CLOEXEC so wil self clean on exec(). * This is specifically meant to be used by Zygote to close open file descriptors after fork() * and before specialization. O_CLOEXEC is used on file descriptors, so they will be closed upon * exec() in normal use cases. * * Note that this is not safe to call from a multi-threaded program. */ void __android_log_close(void); Loading
liblog/logd_writer.cpp +28 −41 Original line number Diff line number Diff line Loading @@ -32,58 +32,53 @@ #include <time.h> #include <unistd.h> #include <shared_mutex> #include <private/android_filesystem_config.h> #include <private/android_logger.h> #include "logger.h" #include "rwlock.h" #include "uio.h" static int logd_socket; static RwLock logd_socket_lock; static void OpenSocketLocked() { logd_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); if (logd_socket <= 0) { return; } static atomic_int logd_socket; // Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this // function is used to reconnect to logd without requiring a new socket. static void LogdConnect() { sockaddr_un un = {}; un.sun_family = AF_UNIX; strcpy(un.sun_path, "/dev/socket/logdw"); if (TEMP_FAILURE_RETRY( connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))) < 0) { close(logd_socket); logd_socket = 0; } TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un))); } static void OpenSocket() { auto lock = std::unique_lock{logd_socket_lock}; if (logd_socket > 0) { // Someone raced us and opened the socket already. // logd_socket should only be opened once. If we see that logd_socket is uninitialized, we create a // new socket and attempt to exchange it into the atomic logd_socket. If the compare/exchange was // successful, then that will be the socket used for the duration of the program, otherwise a // different thread has already opened and written the socket to the atomic, so close the new socket // and return. static void GetSocket() { if (logd_socket != 0) { return; } OpenSocketLocked(); int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)); if (new_socket <= 0) { return; } static void ResetSocket(int old_socket) { auto lock = std::unique_lock{logd_socket_lock}; if (old_socket != logd_socket) { // Someone raced us and reset the socket already. int uninitialized_value = 0; if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) { close(new_socket); return; } close(logd_socket); logd_socket = 0; OpenSocketLocked(); LogdConnect(); } // This is the one exception to the above. Zygote uses this to clean up open FD's after fork() and // before specialization. It is single threaded at this point and therefore this function is // explicitly not thread safe. It sets logd_socket to 0, so future logs will be safely initialized // whenever they happen. void LogdClose() { auto lock = std::unique_lock{logd_socket_lock}; if (logd_socket > 0) { close(logd_socket); } Loading @@ -99,12 +94,7 @@ int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) static atomic_int dropped; static atomic_int droppedSecurity; auto lock = std::shared_lock{logd_socket_lock}; if (logd_socket <= 0) { lock.unlock(); OpenSocket(); lock.lock(); } GetSocket(); if (logd_socket <= 0) { return -EBADF; Loading Loading @@ -183,10 +173,7 @@ int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) // the connection, so we reset it and try again. ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i)); if (ret < 0 && errno != EAGAIN) { int old_socket = logd_socket; lock.unlock(); ResetSocket(old_socket); lock.lock(); LogdConnect(); ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i)); } Loading
liblog/pmsg_writer.cpp +18 −18 Original line number Diff line number Diff line Loading @@ -23,30 +23,36 @@ #include <sys/types.h> #include <time.h> #include <shared_mutex> #include <log/log_properties.h> #include <private/android_logger.h> #include "logger.h" #include "rwlock.h" #include "uio.h" static int pmsg_fd; static RwLock pmsg_fd_lock; static atomic_int pmsg_fd; static void PmsgOpen() { auto lock = std::unique_lock{pmsg_fd_lock}; if (pmsg_fd > 0) { // Someone raced us and opened the socket already. // pmsg_fd should only beopened once. If we see that pmsg_fd is uninitialized, we open "/dev/pmsg0" // then attempt to compare/exchange it into pmsg_fd. If the compare/exchange was successful, then // that will be the fd used for the duration of the program, otherwise a different thread has // already opened and written the fd to the atomic, so close the new fd and return. static void GetPmsgFd() { if (pmsg_fd != 0) { return; } int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); if (new_fd <= 0) { return; } pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC)); int uninitialized_value = 0; if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) { close(new_fd); return; } } void PmsgClose() { auto lock = std::unique_lock{pmsg_fd_lock}; if (pmsg_fd > 0) { close(pmsg_fd); } Loading Loading @@ -77,13 +83,7 @@ int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) } } auto lock = std::shared_lock{pmsg_fd_lock}; if (pmsg_fd <= 0) { lock.unlock(); PmsgOpen(); lock.lock(); } GetPmsgFd(); if (pmsg_fd <= 0) { return -EBADF; Loading
liblog/rwlock.hdeleted 100644 → 0 +0 −39 Original line number Diff line number Diff line /* * Copyright (C) 2019 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. */ #pragma once #include <pthread.h> // As of the end of Dec 2019, std::shared_mutex is *not* simply a pthread_rwlock, but rather a // combination of std::mutex and std::condition variable, which is obviously less efficient. This // immitates what std::shared_mutex should be doing and is compatible with std::shared_lock and // std::unique_lock. class RwLock { public: RwLock() {} ~RwLock() {} void lock() { pthread_rwlock_wrlock(&rwlock_); } void unlock() { pthread_rwlock_unlock(&rwlock_); } void lock_shared() { pthread_rwlock_rdlock(&rwlock_); } void unlock_shared() { pthread_rwlock_unlock(&rwlock_); } private: pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER; };
liblog/tests/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -63,8 +63,8 @@ cc_defaults { "log_system_test.cpp", "log_time_test.cpp", "log_wrap_test.cpp", "logd_writer_test.cpp", "logprint_test.cpp", "rwlock_test.cpp", ], shared_libs: [ "libcutils", Loading Loading @@ -108,7 +108,6 @@ cc_test_host { "liblog_host_test.cpp", "liblog_default_tag.cpp", "liblog_global_state.cpp", "rwlock_test.cpp", ], isolated: true, }