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()30 pid_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)47 void* 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