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 get_thread_id()30pid_t get_thread_id() { 31 #if defined(OS_MACOSX) 32 return pthread_mach_thread_np(pthread_self()); 33 #elif defined(OS_LINUX) 34 #include <sys/syscall.h> /* For SYS_xxx definitions */ 35 #include <unistd.h> 36 return syscall(__NR_gettid); 37 #elif defined(__ANDROID__) 38 #include <sys/types.h> 39 #include <unistd.h> 40 return gettid(); 41 #else 42 return 0; 43 #endif 44 } 45 46 // message loop run_message_loop(void * arg)47void* run_message_loop(void* arg) { 48 bluetooth::log::assert_that(arg != nullptr, 49 "Must pass in a thread start argument"); 50 thread_t* thread = nullptr; 51 { 52 // Decouple thread portion from |start_arg| wrapper 53 thread_start_arg_t* start_arg = static_cast<thread_start_arg_t*>(arg); 54 thread = start_arg->thread; 55 thread->set_state(thread_t::State::RUNNING); 56 start_arg->start_sem.notify(); 57 } // Cannot touch any offsets from |start_arg| anymore 58 59 // thread->tid_ = syscall(__NR_gettid); 60 thread->tid_ = get_thread_id(); 61 bluetooth::log::debug("Thread message loop is operational name:{} tid:{}", 62 thread->name_, thread->tid_); 63 64 while (thread->is_running()) { 65 thread->work_queue_semaphore.wait(); 66 work_item work_item; 67 size_t num_work_items = 0UL; 68 { 69 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 70 num_work_items = thread->work_queue.size(); 71 } 72 73 while (num_work_items > 0) { 74 num_work_items--; 75 { 76 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 77 work_item = thread->work_queue.front(); 78 thread->work_queue.pop(); 79 } 80 // Execute work item 81 work_item.first(work_item.second); 82 osi_free(work_item.second); 83 } 84 } 85 86 // Flush the rest of the work items 87 work_item work_item; 88 size_t num_work_items = 0UL; 89 { 90 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 91 num_work_items = thread->work_queue.size(); 92 } 93 while (num_work_items > 0) { 94 num_work_items--; 95 { 96 std::lock_guard<std::mutex> lock(thread->work_queue_semaphore.mutex_); 97 work_item = thread->work_queue.front(); 98 thread->work_queue.pop(); 99 } 100 // Execute work item 101 work_item.first(work_item.second); 102 osi_free(work_item.second); 103 } 104 thread->set_state(thread_t::State::STOPPED); 105 106 // Release the finish_semaphore for any waiters 107 thread->notify_finished(); 108 return NULL; 109 } 110