Add debug output for errors when setting MMCSS thread characteristics
[ardour.git] / libs / backends / portaudio / mmcss.cc
1 /*
2  * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include "mmcss.h"
20
21 #include "pbd/compose.h"
22
23 #include "debug.h"
24
25 typedef HANDLE (WINAPI* AvSetMmThreadCharacteristicsA_t)(LPCSTR TaskName,
26                                                          LPDWORD TaskIndex);
27
28 typedef BOOL (WINAPI* AvRevertMmThreadCharacteristics_t)(HANDLE AvrtHandle);
29
30 typedef BOOL (WINAPI* AvSetMmThreadPriority_t)(
31     HANDLE AvrtHandle, mmcss::AVRT_PRIORITY Priority);
32
33 static HMODULE avrt_dll = NULL;
34
35 static AvSetMmThreadCharacteristicsA_t AvSetMmThreadCharacteristicsA = NULL;
36 static AvRevertMmThreadCharacteristics_t AvRevertMmThreadCharacteristics = NULL;
37 static AvSetMmThreadPriority_t AvSetMmThreadPriority = NULL;
38
39
40 namespace mmcss {
41
42 bool
43 initialize ()
44 {
45         if (avrt_dll != NULL) return true;
46
47         avrt_dll = LoadLibraryA ("avrt.dll");
48
49         if (avrt_dll == NULL) {
50                 DEBUG_THREADS ("Unable to load avrt.dll\n");
51                 return false;
52         }
53         bool unload_dll = false;
54
55         AvSetMmThreadCharacteristicsA =
56             (AvSetMmThreadCharacteristicsA_t)GetProcAddress (
57                 avrt_dll, "AvSetMmThreadCharacteristicsA");
58
59         if (AvSetMmThreadCharacteristicsA == NULL) {
60                 DEBUG_THREADS ("Unable to resolve AvSetMmThreadCharacteristicsA\n");
61                 unload_dll = true;
62         }
63
64         AvRevertMmThreadCharacteristics =
65             (AvRevertMmThreadCharacteristics_t)GetProcAddress (
66                 avrt_dll, "AvRevertMmThreadCharacteristics");
67
68         if (AvRevertMmThreadCharacteristics == NULL) {
69                 DEBUG_THREADS ("Unable to resolve AvRevertMmThreadCharacteristics\n");
70                 unload_dll = true;
71         }
72
73         AvSetMmThreadPriority = (AvSetMmThreadPriority_t)GetProcAddress (
74             avrt_dll, "AvSetMmThreadPriority");
75
76         if (AvSetMmThreadPriority == NULL) {
77                 DEBUG_THREADS ("Unable to resolve AvSetMmThreadPriority\n");
78                 unload_dll = true;
79         }
80
81         if (unload_dll) {
82                 DEBUG_THREADS (
83                     "MMCSS Unable to resolve necessary symbols, unloading avrt.dll\n");
84                 deinitialize ();
85         }
86
87         return true;
88 }
89
90 bool
91 deinitialize ()
92 {
93         if (avrt_dll == NULL) return true;
94
95         if (FreeLibrary (avrt_dll) == 0) {
96                 DEBUG_THREADS ("Unable to unload avrt.dll\n");
97                 return false;
98         }
99
100         avrt_dll = NULL;
101
102         AvSetMmThreadCharacteristicsA = NULL;
103         AvRevertMmThreadCharacteristics = NULL;
104         AvSetMmThreadPriority = NULL;
105
106         return true;
107 }
108
109 bool
110 set_thread_characteristics (const std::string& task_name, HANDLE* task_handle)
111 {
112         if (AvSetMmThreadCharacteristicsA == NULL) return false;
113
114         DWORD task_index_dummy = 0;
115
116         *task_handle = AvSetMmThreadCharacteristicsA(task_name.c_str(), &task_index_dummy);
117
118         if (*task_handle == 0) {
119                 DEBUG_THREADS (string_compose ("Failed to set Thread Characteristics to %1\n",
120                                                task_name));
121                 DWORD error = GetLastError();
122
123                 switch (error) {
124                 case ERROR_INVALID_TASK_INDEX:
125                         DEBUG_THREADS("MMCSS: Invalid Task Index\n");
126                         break;
127                 case ERROR_INVALID_TASK_NAME:
128                         DEBUG_THREADS("MMCSS: Invalid Task Name\n");
129                         break;
130                 case ERROR_PRIVILEGE_NOT_HELD:
131                         DEBUG_THREADS("MMCSS: Privilege not held\n");
132                         break;
133                 default:
134                         DEBUG_THREADS("MMCSS: Unknown error setting thread characteristics\n");
135                         break;
136                 }
137                 return false;
138         }
139
140         DEBUG_THREADS (
141             string_compose ("Set thread characteristics to %1\n", task_name));
142
143         return true;
144 }
145
146 bool
147 revert_thread_characteristics (HANDLE task_handle)
148 {
149         if (AvRevertMmThreadCharacteristics == NULL) return false;
150
151         if (AvRevertMmThreadCharacteristics (task_handle) == 0) {
152                 DEBUG_THREADS ("Failed to set revert thread characteristics\n");
153                 return false;
154         }
155
156         DEBUG_THREADS ("Reverted thread characteristics\n");
157
158         return true;
159 }
160
161 bool
162 set_thread_priority (HANDLE task_handle, AVRT_PRIORITY priority)
163 {
164         if (AvSetMmThreadPriority == NULL) return false;
165
166         if (AvSetMmThreadPriority (task_handle, priority) == 0) {
167                 DEBUG_THREADS (
168                     string_compose ("Failed to set thread priority %1\n", priority));
169                 return false;
170         }
171
172         DEBUG_THREADS (string_compose ("Set thread priority to %1\n", priority));
173
174         return true;
175 }
176
177 } // namespace mmcss