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()33 pid_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)50 void* 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