1 /******************************************************************************
2 *
3 * Copyright 2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /*******************************************************************************
20 *
21 * Filename: bt_utils.cc
22 *
23 * Description: Miscellaneous helper functions
24 *
25 *
26 ******************************************************************************/
27
28 #define LOG_TAG "bt_utils"
29
30 #include "bt_utils.h"
31
32 #include <errno.h>
33 #include <pthread.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/resource.h>
37 #include <unistd.h>
38 #include <mutex>
39
40 #define A2DP_RT_PRIORITY 1
41 #ifndef OS_GENERIC
42 #include <processgroup/sched_policy.h>
43 #endif
44
45 #include "bt_types.h"
46 #include "btcore/include/module.h"
47 #include "osi/include/compat.h"
48 #include "osi/include/log.h"
49 #include "osi/include/properties.h"
50
51 /*******************************************************************************
52 * Type definitions for callback functions
53 ******************************************************************************/
54 static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
55 static bool g_DoSchedulingGroup[TASK_HIGH_MAX];
56 static std::mutex gIdxLock;
57 static int g_TaskIdx;
58 static int g_TaskIDs[TASK_HIGH_MAX];
59 #define INVALID_TASK_ID (-1)
60
init(void)61 static future_t* init(void) {
62 int i;
63
64 for (i = 0; i < TASK_HIGH_MAX; i++) {
65 g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
66 g_DoSchedulingGroup[i] = true;
67 g_TaskIDs[i] = INVALID_TASK_ID;
68 }
69
70 return NULL;
71 }
72
clean_up(void)73 static future_t* clean_up(void) {
74 return NULL;
75 }
76
77 EXPORT_SYMBOL extern const module_t bt_utils_module = {.name = BT_UTILS_MODULE,
78 .init = init,
79 .start_up = NULL,
80 .shut_down = NULL,
81 .clean_up = clean_up,
82 .dependencies = {NULL}};
83
84 /*****************************************************************************
85 *
86 * Function check_do_scheduling_group
87 *
88 * Description check if it is ok to change schedule group
89 *
90 * Returns void
91 *
92 ******************************************************************************/
check_do_scheduling_group(void)93 static void check_do_scheduling_group(void) {
94 char buf[PROPERTY_VALUE_MAX];
95 int len = osi_property_get("debug.sys.noschedgroups", buf, "");
96 if (len > 0) {
97 int temp;
98 if (sscanf(buf, "%d", &temp) == 1) {
99 g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
100 }
101 }
102 }
103
104 /*****************************************************************************
105 *
106 * Function raise_priority_a2dp
107 *
108 * Description Raise task priority for A2DP streaming
109 *
110 * Returns void
111 *
112 ******************************************************************************/
raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task)113 void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
114 int rc = 0;
115 int tid = gettid();
116
117 {
118 std::lock_guard<std::mutex> lock(gIdxLock);
119 g_TaskIdx = high_task;
120
121 // TODO(armansito): Remove this conditional check once we find a solution
122 // for system/core on non-Android platforms.
123 #if defined(OS_GENERIC)
124 rc = -1;
125 #else // !defined(OS_GENERIC)
126 pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx],
127 check_do_scheduling_group);
128 if (g_DoSchedulingGroup[g_TaskIdx]) {
129 // set_sched_policy does not support tid == 0
130 rc = set_sched_policy(tid, SP_AUDIO_SYS);
131 }
132 #endif // defined(OS_GENERIC)
133
134 g_TaskIDs[high_task] = tid;
135 }
136
137 if (rc) {
138 LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid,
139 errno);
140 }
141
142 // make A2DP threads use RT scheduling policy since they are part of the
143 // audio pipeline
144 {
145 struct sched_param rt_params;
146 rt_params.sched_priority = A2DP_RT_PRIORITY;
147
148 const int rc = sched_setscheduler(tid, SCHED_FIFO, &rt_params);
149 if (rc != 0) {
150 LOG_ERROR(LOG_TAG,
151 "%s unable to set SCHED_FIFO priority %d for tid %d, error %s",
152 __func__, A2DP_RT_PRIORITY, tid, strerror(errno));
153 }
154 }
155 }
156