1 /* Spa
2  *
3  * Copyright © 2019 Wim Taymans
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 (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <sys/eventfd.h>
33 #include <sys/signalfd.h>
34 
35 #include <evl/evl.h>
36 #include <evl/timer.h>
37 
38 #include <spa/support/log.h>
39 #include <spa/support/system.h>
40 #include <spa/support/plugin.h>
41 #include <spa/utils/type.h>
42 #include <spa/utils/result.h>
43 #include <spa/utils/string.h>
44 
45 #define NAME "evl-system"
46 
47 #define MAX_POLL	512
48 
49 struct poll_entry {
50 	int pfd;
51 	int fd;
52 	uint32_t events;
53 	void *data;
54 };
55 
56 struct impl {
57 	struct spa_handle handle;
58 	struct spa_system system;
59 
60         struct spa_log *log;
61 
62 	struct poll_entry entries[MAX_POLL];
63 	uint32_t n_entries;
64 
65 	uint32_t n_xbuf;
66 	int attached;
67 	int pid;
68 };
69 
impl_read(void * object,int fd,void * buf,size_t count)70 static ssize_t impl_read(void *object, int fd, void *buf, size_t count)
71 {
72 	return oob_read(fd, buf, count);
73 }
74 
impl_write(void * object,int fd,const void * buf,size_t count)75 static ssize_t impl_write(void *object, int fd, const void *buf, size_t count)
76 {
77 	return oob_write(fd, buf, count);
78 }
79 
impl_ioctl(void * object,int fd,unsigned long request,...)80 static int impl_ioctl(void *object, int fd, unsigned long request, ...)
81 {
82 	int res;
83 	va_list ap;
84 	long arg;
85 
86 	va_start(ap, request);
87 	arg = va_arg(ap, long);
88 	res = oob_ioctl(fd, request, arg);
89 	va_end(ap);
90 
91 	return res;
92 }
93 
impl_close(void * object,int fd)94 static int impl_close(void *object, int fd)
95 {
96 	return close(fd);
97 }
98 
clock_id_to_evl(int clockid)99 static inline int clock_id_to_evl(int clockid)
100 {
101 	switch(clockid) {
102 	case CLOCK_MONOTONIC:
103 		return EVL_CLOCK_MONOTONIC;
104 	case CLOCK_REALTIME:
105 		return EVL_CLOCK_REALTIME;
106 	default:
107 		return -clockid;
108 	}
109 }
110 
111 /* clock */
impl_clock_gettime(void * object,int clockid,struct timespec * value)112 static int impl_clock_gettime(void *object,
113 			int clockid, struct timespec *value)
114 {
115 	return evl_read_clock(clock_id_to_evl(clockid), value);
116 }
117 
impl_clock_getres(void * object,int clockid,struct timespec * res)118 static int impl_clock_getres(void *object,
119 			int clockid, struct timespec *res)
120 {
121 	return evl_get_clock_resolution(clock_id_to_evl(clockid), res);
122 }
123 
124 /* poll */
impl_pollfd_create(void * object,int flags)125 static int impl_pollfd_create(void *object, int flags)
126 {
127 	int retval;
128 	retval = evl_new_poll();
129 	return retval;
130 }
131 
find_entry(struct impl * impl,int pfd,int fd)132 static inline struct poll_entry *find_entry(struct impl *impl, int pfd, int fd)
133 {
134 	uint32_t i;
135 	for (i = 0; i < impl->n_entries; i++) {
136 		struct poll_entry *e = &impl->entries[i];
137 		if (e->pfd == pfd && e->fd == fd)
138 			return e;
139 	}
140 	return NULL;
141 }
142 
impl_pollfd_add(void * object,int pfd,int fd,uint32_t events,void * data)143 static int impl_pollfd_add(void *object, int pfd, int fd, uint32_t events, void *data)
144 {
145 	struct impl *impl = object;
146 	struct poll_entry *e;
147 
148 	if (impl->n_entries == MAX_POLL)
149 		return -ENOSPC;
150 
151 	e = &impl->entries[impl->n_entries++];
152 	e->pfd = pfd;
153 	e->fd = fd;
154 	e->events = events;
155 	e->data = data;
156 	return evl_add_pollfd(pfd, fd, e->events);
157 }
158 
impl_pollfd_mod(void * object,int pfd,int fd,uint32_t events,void * data)159 static int impl_pollfd_mod(void *object, int pfd, int fd, uint32_t events, void *data)
160 {
161 	struct impl *impl = object;
162 	struct poll_entry *e;
163 
164 	e = find_entry(impl, pfd, fd);
165 	if (e == NULL)
166 		return -ENOENT;
167 
168 	e->events = events;
169 	e->data = data;
170 	return evl_mod_pollfd(pfd, fd, e->events);
171 }
172 
impl_pollfd_del(void * object,int pfd,int fd)173 static int impl_pollfd_del(void *object, int pfd, int fd)
174 {
175 	struct impl *impl = object;
176 	struct poll_entry *e;
177 
178 	e = find_entry(impl, pfd, fd);
179 	if (e == NULL)
180 		return -ENOENT;
181 
182 	e->pfd = -1;
183 	e->fd = -1;
184 	return evl_del_pollfd(pfd, fd);
185 }
186 
impl_pollfd_wait(void * object,int pfd,struct spa_poll_event * ev,int n_ev,int timeout)187 static int impl_pollfd_wait(void *object, int pfd,
188 		struct spa_poll_event *ev, int n_ev, int timeout)
189 {
190 	struct impl *impl = object;
191 	struct evl_poll_event pollset[n_ev];
192 	struct timespec tv;
193 	int i, j, res;
194 
195 	if (impl->attached == 0) {
196 		res = evl_attach_self("evl-thread-%d-%p", impl->pid, impl);
197 		if (res < 0)
198 			return res;
199 		impl->attached = res;
200 	}
201 
202 	if (timeout == -1) {
203 		tv.tv_sec = 0;
204 		tv.tv_nsec = 0;
205 	} else {
206 		tv.tv_sec = timeout / SPA_MSEC_PER_SEC;
207 		tv.tv_nsec = (timeout % SPA_MSEC_PER_SEC) * SPA_NSEC_PER_MSEC;
208 	}
209 	res = evl_timedpoll(pfd, pollset, n_ev, &tv);
210 	if (SPA_UNLIKELY(res < 0))
211 		return res;
212 
213         for (i = 0, j = 0; i < res; i++) {
214 		struct poll_entry *e;
215 
216 		e = find_entry(impl, pfd, pollset[i].fd);
217 		if (e == NULL)
218 			continue;
219 
220 		ev[j].events = pollset[i].events;
221 		ev[j].data = e->data;
222 		j++;
223 	}
224 	return j;
225 }
226 
227 /* timers */
impl_timerfd_create(void * object,int clockid,int flags)228 static int impl_timerfd_create(void *object, int clockid, int flags)
229 {
230 	int cid;
231 
232 	switch (clockid) {
233 	case CLOCK_MONOTONIC:
234 		cid = EVL_CLOCK_MONOTONIC;
235 		break;
236 	default:
237 		return -ENOTSUP;
238 	}
239 	return evl_new_timer(cid);
240 }
241 
impl_timerfd_settime(void * object,int fd,int flags,const struct itimerspec * new_value,struct itimerspec * old_value)242 static int impl_timerfd_settime(void *object,
243 			int fd, int flags,
244 			const struct itimerspec *new_value,
245 			struct itimerspec *old_value)
246 {
247 	struct itimerspec val = *new_value;
248 
249 	if (!(flags & SPA_FD_TIMER_ABSTIME)) {
250 		struct timespec now;
251 
252 		evl_read_clock(EVL_CLOCK_MONOTONIC, &now);
253 		val.it_value.tv_sec += now.tv_sec;
254 		val.it_value.tv_nsec += now.tv_nsec;
255 		if (val.it_value.tv_nsec >= 1000000000) {
256 			val.it_value.tv_sec++;
257 			val.it_value.tv_nsec -= 1000000000;
258 		}
259 	}
260 	return evl_set_timer(fd, &val, old_value);
261 }
262 
impl_timerfd_gettime(void * object,int fd,struct itimerspec * curr_value)263 static int impl_timerfd_gettime(void *object,
264 			int fd, struct itimerspec *curr_value)
265 {
266 	return evl_get_timer(fd, curr_value);
267 
268 }
impl_timerfd_read(void * object,int fd,uint64_t * expirations)269 static int impl_timerfd_read(void *object, int fd, uint64_t *expirations)
270 {
271 	uint32_t ticks;
272 	if (oob_read(fd, &ticks, sizeof(ticks)) != sizeof(ticks))
273 		return -errno;
274 	*expirations = ticks;
275 	return 0;
276 }
277 
278 /* events */
impl_eventfd_create(void * object,int flags)279 static int impl_eventfd_create(void *object, int flags)
280 {
281 	struct impl *impl = object;
282 	int res;
283 
284 	res = evl_new_xbuf(1024, 1024, "xbuf-%d-%p-%d", impl->pid, impl, impl->n_xbuf);
285 	if (res < 0)
286 		return res;
287 
288 	impl->n_xbuf++;
289 
290 	if (flags & SPA_FD_NONBLOCK)
291 		fcntl(res, F_SETFL, fcntl(res, F_GETFL) | O_NONBLOCK);
292 
293 	return res;
294 }
295 
impl_eventfd_write(void * object,int fd,uint64_t count)296 static int impl_eventfd_write(void *object, int fd, uint64_t count)
297 {
298 	if (write(fd, &count, sizeof(uint64_t)) != sizeof(uint64_t))
299 		return -errno;
300 	return 0;
301 }
302 
impl_eventfd_read(void * object,int fd,uint64_t * count)303 static int impl_eventfd_read(void *object, int fd, uint64_t *count)
304 {
305 	if (oob_read(fd, count, sizeof(uint64_t)) != sizeof(uint64_t))
306 		return -errno;
307 	return 0;
308 }
309 
310 /* signals */
impl_signalfd_create(void * object,int signal,int flags)311 static int impl_signalfd_create(void *object, int signal, int flags)
312 {
313 	sigset_t mask;
314 	int res, fl = 0;
315 
316 	if (flags & SPA_FD_CLOEXEC)
317 		fl |= SFD_CLOEXEC;
318 	if (flags & SPA_FD_NONBLOCK)
319 		fl |= SFD_NONBLOCK;
320 
321 	sigemptyset(&mask);
322 	sigaddset(&mask, signal);
323 	res = signalfd(-1, &mask, fl);
324 	sigprocmask(SIG_BLOCK, &mask, NULL);
325 
326 	return res;
327 }
328 
impl_signalfd_read(void * object,int fd,int * signal)329 static int impl_signalfd_read(void *object, int fd, int *signal)
330 {
331 	struct signalfd_siginfo signal_info;
332 	int len;
333 
334 	len = read(fd, &signal_info, sizeof signal_info);
335 	if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info)
336 		return -errno;
337 
338 	*signal = signal_info.ssi_signo;
339 
340 	return 0;
341 }
342 
343 static const struct spa_system_methods impl_system = {
344 	SPA_VERSION_SYSTEM_METHODS,
345 	.read = impl_read,
346 	.write = impl_write,
347 	.ioctl = impl_ioctl,
348 	.close = impl_close,
349 	.clock_gettime = impl_clock_gettime,
350 	.clock_getres = impl_clock_getres,
351 	.pollfd_create = impl_pollfd_create,
352 	.pollfd_add = impl_pollfd_add,
353 	.pollfd_mod = impl_pollfd_mod,
354 	.pollfd_del = impl_pollfd_del,
355 	.pollfd_wait = impl_pollfd_wait,
356 	.timerfd_create = impl_timerfd_create,
357 	.timerfd_settime = impl_timerfd_settime,
358 	.timerfd_gettime = impl_timerfd_gettime,
359 	.timerfd_read = impl_timerfd_read,
360 	.eventfd_create = impl_eventfd_create,
361 	.eventfd_write = impl_eventfd_write,
362 	.eventfd_read = impl_eventfd_read,
363 	.signalfd_create = impl_signalfd_create,
364 	.signalfd_read = impl_signalfd_read,
365 };
366 
impl_get_interface(struct spa_handle * handle,const char * type,void ** interface)367 static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
368 {
369 	struct impl *impl;
370 
371 	spa_return_val_if_fail(handle != NULL, -EINVAL);
372 	spa_return_val_if_fail(interface != NULL, -EINVAL);
373 
374 	impl = (struct impl *) handle;
375 
376 	if (spa_streq(type, SPA_TYPE_INTERFACE_System))
377 		*interface = &impl->system;
378 	else
379 		return -ENOENT;
380 
381 	return 0;
382 }
383 
impl_clear(struct spa_handle * handle)384 static int impl_clear(struct spa_handle *handle)
385 {
386 	spa_return_val_if_fail(handle != NULL, -EINVAL);
387 	return 0;
388 }
389 
390 static size_t
impl_get_size(const struct spa_handle_factory * factory,const struct spa_dict * params)391 impl_get_size(const struct spa_handle_factory *factory,
392 	      const struct spa_dict *params)
393 {
394 	return sizeof(struct impl);
395 }
396 
397 static int
impl_init(const struct spa_handle_factory * factory,struct spa_handle * handle,const struct spa_dict * info,const struct spa_support * support,uint32_t n_support)398 impl_init(const struct spa_handle_factory *factory,
399 	  struct spa_handle *handle,
400 	  const struct spa_dict *info,
401 	  const struct spa_support *support,
402 	  uint32_t n_support)
403 {
404 	struct impl *impl;
405 	int res;
406 
407 	spa_return_val_if_fail(factory != NULL, -EINVAL);
408 	spa_return_val_if_fail(handle != NULL, -EINVAL);
409 
410 	handle->get_interface = impl_get_interface;
411 	handle->clear = impl_clear;
412 
413 	impl = (struct impl *) handle;
414 	impl->system.iface = SPA_INTERFACE_INIT(
415 			SPA_TYPE_INTERFACE_System,
416 			SPA_VERSION_SYSTEM,
417 			&impl_system, impl);
418 
419 	impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
420 
421 	impl->pid = getpid();
422 
423 	if ((res = evl_attach_self("evl-system-%d-%p", impl->pid, impl)) < 0) {
424 		spa_log_error(impl->log, NAME " %p: init failed: %s", impl, spa_strerror(res));
425 		return res;
426 	}
427 
428 	spa_log_debug(impl->log, NAME " %p: initialized", impl);
429 
430 	return 0;
431 }
432 
433 static const struct spa_interface_info impl_interfaces[] = {
434 	{SPA_TYPE_INTERFACE_System,},
435 };
436 
437 static int
impl_enum_interface_info(const struct spa_handle_factory * factory,const struct spa_interface_info ** info,uint32_t * index)438 impl_enum_interface_info(const struct spa_handle_factory *factory,
439 			 const struct spa_interface_info **info,
440 			 uint32_t *index)
441 {
442 	spa_return_val_if_fail(factory != NULL, -EINVAL);
443 	spa_return_val_if_fail(info != NULL, -EINVAL);
444 	spa_return_val_if_fail(index != NULL, -EINVAL);
445 
446 	if (*index >= SPA_N_ELEMENTS(impl_interfaces))
447 		return 0;
448 
449 	*info = &impl_interfaces[(*index)++];
450 	return 1;
451 }
452 
453 const struct spa_handle_factory spa_support_evl_system_factory = {
454 	SPA_VERSION_HANDLE_FACTORY,
455 	SPA_NAME_SUPPORT_SYSTEM,
456 	NULL,
457 	impl_get_size,
458 	impl_init,
459 	impl_enum_interface_info
460 };
461