1 /**************************************************************************
2 *
3 * Copyright (C) 2019 Chromium.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "virgl_util.h"
30
31 #include <errno.h>
32 #ifdef HAVE_EVENTFD_H
33 #include <sys/eventfd.h>
34 #endif
35 #include <unistd.h>
36
37 #include "os/os_misc.h"
38 #include "util/u_pointer.h"
39
40 #include <assert.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #if ENABLE_TRACING == TRACE_WITH_PERFETTO
49 #include <vperfetto-min.h>
50 #endif
51
52 #if ENABLE_TRACING == TRACE_WITH_STDERR
53 #include <stdio.h>
54 #endif
55
hash_func_u32(void * key)56 unsigned hash_func_u32(void *key)
57 {
58 intptr_t ip = pointer_to_intptr(key);
59 return (unsigned)(ip & 0xffffffff);
60 }
61
compare_func(void * key1,void * key2)62 int compare_func(void *key1, void *key2)
63 {
64 if (key1 < key2)
65 return -1;
66 if (key1 > key2)
67 return 1;
68 else
69 return 0;
70 }
71
has_eventfd(void)72 bool has_eventfd(void)
73 {
74 #ifdef HAVE_EVENTFD_H
75 return true;
76 #else
77 return false;
78 #endif
79 }
80
create_eventfd(unsigned int initval)81 int create_eventfd(unsigned int initval)
82 {
83 #ifdef HAVE_EVENTFD_H
84 return eventfd(initval, EFD_CLOEXEC | EFD_NONBLOCK);
85 #else
86 (void)initval;
87 return -1;
88 #endif
89 }
90
write_eventfd(int fd,uint64_t val)91 int write_eventfd(int fd, uint64_t val)
92 {
93 const char *buf = (const char *)&val;
94 size_t count = sizeof(val);
95 ssize_t ret = 0;
96
97 while (count) {
98 ret = write(fd, buf, count);
99 if (ret < 0) {
100 if (errno == EINTR)
101 continue;
102 break;
103 }
104 count -= ret;
105 buf += ret;
106 }
107
108 return count ? -1 : 0;
109 }
110
flush_eventfd(int fd)111 void flush_eventfd(int fd)
112 {
113 ssize_t len;
114 uint64_t value;
115 do {
116 len = read(fd, &value, sizeof(value));
117 } while ((len == -1 && errno == EINTR) || len == sizeof(value));
118 }
119
120 static
virgl_default_logger(const char * fmt,va_list va)121 void virgl_default_logger(const char *fmt, va_list va)
122 {
123 static FILE* fp = NULL;
124 if (NULL == fp) {
125 const char* log = getenv("VIRGL_LOG_FILE");
126 if (log) {
127 char *log_prefix = strdup(log);
128 char *log_suffix = strstr(log_prefix, "%PID%");
129 if (log_suffix) {
130 *log_suffix = 0;
131 log_suffix += 5;
132 int len = strlen(log) + 32;
133 char *name = malloc(len);
134 snprintf(name, len, "%s%d%s", log_prefix, getpid(), log_suffix);
135 fp = fopen(name, "a");
136 free(name);
137 } else {
138 fp = fopen(log, "a");
139 }
140 free(log_prefix);
141 if (NULL == fp) {
142 fprintf(stderr, "Can't open %s\n", log);
143 fp = stderr;
144 }
145 } else {
146 fp = stderr;
147 }
148 }
149 vfprintf(fp, fmt, va);
150 fflush(fp);
151 }
152
153 static
virgl_null_logger(UNUSED const char * fmt,UNUSED va_list va)154 void virgl_null_logger(UNUSED const char *fmt, UNUSED va_list va)
155 {
156 }
157
158 static virgl_debug_callback_type virgl_logger = virgl_default_logger;
159
virgl_log_set_logger(virgl_debug_callback_type logger)160 virgl_debug_callback_type virgl_log_set_logger(virgl_debug_callback_type logger)
161 {
162 virgl_debug_callback_type old = virgl_logger;
163
164 /* virgl_null_logger is internal */
165 if (old == virgl_null_logger)
166 old = NULL;
167 if (!logger)
168 logger = virgl_null_logger;
169
170 virgl_logger = logger;
171 return old;
172 }
173
virgl_logv(const char * fmt,va_list va)174 void virgl_logv(const char *fmt, va_list va)
175 {
176 assert(virgl_logger);
177 virgl_logger(fmt, va);
178 }
179
180 #if ENABLE_TRACING == TRACE_WITH_PERCETTO
PERCETTO_CATEGORY_DEFINE(VIRGL_PERCETTO_CATEGORIES)181 PERCETTO_CATEGORY_DEFINE(VIRGL_PERCETTO_CATEGORIES)
182
183 void trace_init(void)
184 {
185 PERCETTO_INIT(PERCETTO_CLOCK_DONT_CARE);
186 }
187 #endif
188
189 #if ENABLE_TRACING == TRACE_WITH_PERFETTO
trace_init(void)190 void trace_init(void)
191 {
192 struct vperfetto_min_config config = {
193 .init_flags = VPERFETTO_INIT_FLAG_USE_SYSTEM_BACKEND,
194 .filename = NULL,
195 .shmem_size_hint_kb = 32 * 1024,
196 };
197
198 vperfetto_min_startTracing(&config);
199 }
200
trace_begin(const char * scope)201 const char *trace_begin(const char *scope)
202 {
203 vperfetto_min_beginTrackEvent_VMM(scope);
204 return scope;
205 }
206
trace_end(const char ** dummy)207 void trace_end(const char **dummy)
208 {
209 (void)dummy;
210 vperfetto_min_endTrackEvent_VMM();
211 }
212 #endif
213
214 #if ENABLE_TRACING == TRACE_WITH_STDERR
215 static int nesting_depth = 0;
trace_init(void)216 void trace_init(void)
217 {
218 }
219
trace_begin(const char * scope)220 const char *trace_begin(const char *scope)
221 {
222 for (int i = 0; i < nesting_depth; ++i)
223 fprintf(stderr, " ");
224
225 fprintf(stderr, "ENTER:%s\n", scope);
226 nesting_depth++;
227
228 return scope;
229 }
230
trace_end(const char ** func_name)231 void trace_end(const char **func_name)
232 {
233 --nesting_depth;
234 for (int i = 0; i < nesting_depth; ++i)
235 fprintf(stderr, " ");
236 fprintf(stderr, "LEAVE %s\n", *func_name);
237 }
238 #endif
239