1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "test/fake/fake_looper.h" 18 19 #include <bluetooth/log.h> 20 #include <gtest/gtest.h> 21 #include <stddef.h> 22 #include <stdlib.h> 23 24 #include <mutex> 25 #include <queue> 26 27 #include "osi/include/allocator.h" 28 #include "test/fake/fake_thread.h" 29 30 // TODO(b/369381361) Enfore -Wmissing-prototypes 31 #pragma GCC diagnostic ignored "-Wmissing-prototypes" 32 get_thread_id()33pid_t get_thread_id() { 34 #if defined(OS_MACOSX) 35 return pthread_mach_thread_np(pthread_self()); 36 #elif defined(OS_LINUX) 37 #include <sys/syscall.h> /* For SYS_xxx definitions */ 38 #include <unistd.h> 39 return syscall(__NR_gettid); 40 #elif defined(__ANDROID__) 41 #include <sys/types.h> 42 #include <unistd.h> 43 return gettid(); 44 #else 45 return 0; 46 #endif 47 } 48 49 // message loop run_message_loop(void * arg)50void* run_message_loop(void* arg) { 51 bluetooth::log::assert_that(arg != nullptr, "Must pass in a thread start argument"); 52 thread_t* thread = nullptr; 53 { 54 // Decouple thread portion from |start_arg| wrapper 55 thread_start_arg_t* start_arg = static_cast<thread_start_arg_t*>(arg); 56 thread = start_arg->thread; 57 thread->set_state(thread_t::State::RUNNING); 58 start_arg->start_sem.notify(); 59 } // Cannot touch any offsets from |start_arg| anymore 60 61 // thread->tid_ = syscall(__NR_gettid); 62 thread->tid_ = get_thread_id(); 63 bluetooth::log::debug("Thread message loop is operational name:{} tid:{}", thread->name_, 64 thread->tid_); 65 66 while (thread->is_running()) { 67 thread->work_queue_semaphore.wait(); 68 work_item work_item; 69 size_t num_work_items = 0UL; 70 { 71 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 72 num_work_items = thread->work_queue.size(); 73 } 74 75 while (num_work_items > 0) { 76 num_work_items--; 77 { 78 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 79 work_item = thread->work_queue.front(); 80 thread->work_queue.pop(); 81 } 82 // Execute work item 83 work_item.first(work_item.second); 84 osi_free(work_item.second); 85 } 86 } 87 88 // Flush the rest of the work items 89 work_item work_item; 90 size_t num_work_items = 0UL; 91 { 92 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 93 num_work_items = thread->work_queue.size(); 94 } 95 while (num_work_items > 0) { 96 num_work_items--; 97 { 98 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 99 work_item = thread->work_queue.front(); 100 thread->work_queue.pop(); 101 } 102 // Execute work item 103 work_item.first(work_item.second); 104 osi_free(work_item.second); 105 } 106 thread->set_state(thread_t::State::STOPPED); 107 108 // Release the finish_semaphore for any waiters 109 thread->notify_finished(); 110 return NULL; 111 } 112