Blame tools/fpgad/events_api_thread.c

Packit Service 3975d1
// Copyright(c) 2018-2020, Intel Corporation
Packit Service 3975d1
//
Packit Service 3975d1
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit Service 3975d1
// modification, are permitted provided that the following conditions are met:
Packit Service 3975d1
//
Packit Service 3975d1
// * Redistributions of  source code  must retain the  above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer.
Packit Service 3975d1
// * Redistributions in binary form must reproduce the above copyright notice,
Packit Service 3975d1
//   this list of conditions and the following disclaimer in the documentation
Packit Service 3975d1
//   and/or other materials provided with the distribution.
Packit Service 3975d1
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit Service 3975d1
//   may be used to  endorse or promote  products derived  from this  software
Packit Service 3975d1
//   without specific prior written permission.
Packit Service 3975d1
//
Packit Service 3975d1
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit Service 3975d1
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit Service 3975d1
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 3975d1
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit Service 3975d1
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit Service 3975d1
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit Service 3975d1
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit Service 3975d1
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit Service 3975d1
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit Service 3975d1
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit Service 3975d1
// POSSIBILITY OF SUCH DAMAGE.
Packit Service 3975d1
Packit Service 3975d1
#ifdef HAVE_CONFIG_H
Packit Service 3975d1
#include <config.h>
Packit Service 3975d1
#endif // HAVE_CONFIG_H
Packit Service 3975d1
Packit Service 3975d1
#ifndef _GNU_SOURCE
Packit Service 3975d1
#define _GNU_SOURCE
Packit Service 3975d1
#endif
Packit Service 3975d1
#ifndef __USE_GNU
Packit Service 3975d1
#define __USE_GNU
Packit Service 3975d1
#endif
Packit Service 3975d1
Packit Service 3975d1
#include <sys/socket.h>
Packit Service 3975d1
#include <sys/un.h>
Packit Service 3975d1
#include <poll.h>
Packit Service 3975d1
#include <inttypes.h>
Packit Service 3975d1
#include "events_api_thread.h"
Packit Service 3975d1
#include "api/opae_events_api.h"
Packit Service 3975d1
Packit Service 3975d1
#ifdef LOG
Packit Service 3975d1
#undef LOG
Packit Service 3975d1
#endif
Packit Service 3975d1
#define LOG(format, ...) \
Packit Service 3975d1
log_printf("events_api_thread: " format, ##__VA_ARGS__)
Packit Service 3975d1
Packit Service 3975d1
events_api_thread_config events_api_config = {
Packit Service 3975d1
	.global = &global_config,
Packit Service 3975d1
	.sched_policy = SCHED_RR,
Packit Service 3975d1
	.sched_priority = 10,
Packit Service 3975d1
};
Packit Service 3975d1
Packit Service 3975d1
#define MAX_CLIENT_CONNECTIONS 1023
Packit Service 3975d1
#define SRV_SOCKET             0
Packit Service 3975d1
#define FIRST_CLIENT_SOCKET    1
Packit Service 3975d1
Packit Service 3975d1
/* array keeping track of all connection file descriptors (plus server socket) */
Packit Service 3975d1
STATIC struct pollfd pollfds[MAX_CLIENT_CONNECTIONS+1];
Packit Service 3975d1
STATIC nfds_t num_fds = 1;
Packit Service 3975d1
Packit Service 3975d1
STATIC void remove_client(int conn_socket)
Packit Service 3975d1
{
Packit Service 3975d1
	nfds_t i, j;
Packit Service 3975d1
	nfds_t removed = 0;
Packit Service 3975d1
Packit Service 3975d1
	opae_api_unregister_all_events_for(conn_socket);
Packit Service 3975d1
	LOG("closing connection conn_socket=%d.\n", conn_socket);
Packit Service 3975d1
	close(conn_socket);
Packit Service 3975d1
Packit Service 3975d1
	for (i = j = FIRST_CLIENT_SOCKET ; i < num_fds ; ++i) {
Packit Service 3975d1
		if (conn_socket != pollfds[i].fd) {
Packit Service 3975d1
			if (j != i)
Packit Service 3975d1
				pollfds[j] = pollfds[i];
Packit Service 3975d1
			++j;
Packit Service 3975d1
		} else {
Packit Service 3975d1
			++removed;
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	num_fds -= removed;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC int handle_message(int conn_socket)
Packit Service 3975d1
{
Packit Service 3975d1
	struct msghdr mh;
Packit Service 3975d1
	struct cmsghdr *cmh;
Packit Service 3975d1
	struct iovec iov[1];
Packit Service 3975d1
	struct event_request req;
Packit Service 3975d1
	char buf[CMSG_SPACE(sizeof(int))];
Packit Service 3975d1
	ssize_t n;
Packit Service 3975d1
	int *fd_ptr;
Packit Service 3975d1
Packit Service 3975d1
	/* set up ancillary data message header */
Packit Service 3975d1
	iov[0].iov_base = &req;
Packit Service 3975d1
	iov[0].iov_len = sizeof(req);
Packit Service 3975d1
	memset(buf, 0, sizeof(buf));
Packit Service 3975d1
	mh.msg_name = NULL;
Packit Service 3975d1
	mh.msg_namelen = 0;
Packit Service 3975d1
	mh.msg_iov = iov;
Packit Service 3975d1
	mh.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
Packit Service 3975d1
	mh.msg_control = buf;
Packit Service 3975d1
	mh.msg_controllen = CMSG_LEN(sizeof(int));
Packit Service 3975d1
	mh.msg_flags = 0;
Packit Service 3975d1
	cmh = CMSG_FIRSTHDR(&mh);
Packit Service 3975d1
	cmh->cmsg_len = CMSG_LEN(sizeof(int));
Packit Service 3975d1
	cmh->cmsg_level = SOL_SOCKET;
Packit Service 3975d1
	cmh->cmsg_type = SCM_RIGHTS;
Packit Service 3975d1
Packit Service 3975d1
	n = recvmsg(conn_socket, &mh, 0);
Packit Service 3975d1
	if (n < 0) {
Packit Service 3975d1
		LOG("recvmsg() failed: %s\n", strerror(errno));
Packit Service 3975d1
		return (int)n;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	if (!n) { // socket closed by peer
Packit Service 3975d1
		remove_client(conn_socket);
Packit Service 3975d1
		return (int)n;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	switch (req.type) {
Packit Service 3975d1
Packit Service 3975d1
	case REGISTER_EVENT:
Packit Service 3975d1
		fd_ptr = (int *)CMSG_DATA(cmh);
Packit Service 3975d1
Packit Service 3975d1
		if (opae_api_register_event(conn_socket, *fd_ptr,
Packit Service 3975d1
				    req.event, req.object_id)) {
Packit Service 3975d1
			LOG("failed to register event\n");
Packit Service 3975d1
			return -1;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		LOG("registered event sock=%d:fd=%d"
Packit Service 3975d1
		     "(event=%d object_id=0x%" PRIx64  ")\n",
Packit Service 3975d1
			conn_socket, *fd_ptr, req.event, req.object_id);
Packit Service 3975d1
Packit Service 3975d1
		break;
Packit Service 3975d1
Packit Service 3975d1
	case UNREGISTER_EVENT:
Packit Service 3975d1
Packit Service 3975d1
		if (opae_api_unregister_event(conn_socket,
Packit Service 3975d1
					      req.event,
Packit Service 3975d1
					      req.object_id)) {
Packit Service 3975d1
			LOG("failed to unregister event\n");
Packit Service 3975d1
			return -1;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		LOG("unregistered event sock=%d:"
Packit Service 3975d1
		     "(event=%d object_id=0x%" PRIx64  ")\n",
Packit Service 3975d1
			conn_socket, req.event, req.object_id);
Packit Service 3975d1
Packit Service 3975d1
		break;
Packit Service 3975d1
Packit Service 3975d1
	default:
Packit Service 3975d1
		LOG("unknown request type %d\n", req.type);
Packit Service 3975d1
		return -1;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	return 0;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC volatile bool evt_api_is_ready = false;
Packit Service 3975d1
Packit Service 3975d1
bool events_api_is_ready(void)
Packit Service 3975d1
{
Packit Service 3975d1
	return evt_api_is_ready;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
void *events_api_thread(void *thread_context)
Packit Service 3975d1
{
Packit Service 3975d1
	events_api_thread_config *c =
Packit Service 3975d1
		(events_api_thread_config *)thread_context;
Packit Service 3975d1
	struct sched_param sched_param;
Packit Service 3975d1
	int policy = 0;
Packit Service 3975d1
	int res;
Packit Service 3975d1
Packit Service 3975d1
	nfds_t i;
Packit Service 3975d1
	struct sockaddr_un addr;
Packit Service 3975d1
	int server_socket;
Packit Service 3975d1
	int conn_socket;
Packit Service 3975d1
	size_t len;
Packit Service 3975d1
Packit Service 3975d1
	LOG("starting\n");
Packit Service 3975d1
Packit Service 3975d1
	res = pthread_getschedparam(pthread_self(), &policy, &sched_param);
Packit Service 3975d1
	if (res) {
Packit Service 3975d1
		LOG("error getting scheduler params: %s\n", strerror(res));
Packit Service 3975d1
	} else {
Packit Service 3975d1
		policy = c->sched_policy;
Packit Service 3975d1
		sched_param.sched_priority = c->sched_priority;
Packit Service 3975d1
Packit Service 3975d1
		res = pthread_setschedparam(pthread_self(),
Packit Service 3975d1
					    policy,
Packit Service 3975d1
					    &sched_param);
Packit Service 3975d1
		if (res) {
Packit Service 3975d1
			LOG("error setting scheduler params"
Packit Service 3975d1
			    " (got root?): %s\n", strerror(res));
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	unlink(c->global->api_socket);
Packit Service 3975d1
Packit Service 3975d1
	server_socket = socket(AF_UNIX, SOCK_STREAM, 0);
Packit Service 3975d1
	if (server_socket < 0) {
Packit Service 3975d1
		LOG("failed to create server socket.\n");
Packit Service 3975d1
		goto out_exit;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("created server socket.\n");
Packit Service 3975d1
Packit Service 3975d1
	addr.sun_family = AF_UNIX;
Packit Service 3975d1
Packit Service 3975d1
	len = strnlen(c->global->api_socket, sizeof(addr.sun_path) - 1);
Packit Service 3975d1
	memcpy(addr.sun_path, c->global->api_socket, len);
Packit Service 3975d1
	addr.sun_path[len] = '\0';
Packit Service 3975d1
Packit Service 3975d1
	if (bind(server_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
Packit Service 3975d1
		LOG("failed to bind server socket.\n");
Packit Service 3975d1
		goto out_close_server;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("server socket bind success.\n");
Packit Service 3975d1
Packit Service 3975d1
	if (listen(server_socket, 20) < 0) {
Packit Service 3975d1
		LOG("failed to listen on socket.\n");
Packit Service 3975d1
		goto out_close_server;
Packit Service 3975d1
	}
Packit Service 3975d1
	LOG("listening for connections.\n");
Packit Service 3975d1
Packit Service 3975d1
	evt_api_is_ready = true;
Packit Service 3975d1
Packit Service 3975d1
	pollfds[SRV_SOCKET].fd = server_socket;
Packit Service 3975d1
	pollfds[SRV_SOCKET].events = POLLIN | POLLPRI;
Packit Service 3975d1
	num_fds = 1;
Packit Service 3975d1
Packit Service 3975d1
	while (c->global->running) {
Packit Service 3975d1
Packit Service 3975d1
		res = poll(pollfds, num_fds, 100);
Packit Service 3975d1
		if (res < 0) {
Packit Service 3975d1
			LOG("poll error\n");
Packit Service 3975d1
			continue;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (0 == res) // timeout
Packit Service 3975d1
			continue;
Packit Service 3975d1
Packit Service 3975d1
		if ((nfds_t)res > num_fds) { // weird
Packit Service 3975d1
			LOG("something bad happened during poll!\n");
Packit Service 3975d1
			continue;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		// handle requests on existing sockets
Packit Service 3975d1
		for (i = FIRST_CLIENT_SOCKET ; i < num_fds ; ++i) {
Packit Service 3975d1
			if (pollfds[i].revents) {
Packit Service 3975d1
				handle_message(pollfds[i].fd);
Packit Service 3975d1
			}
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		// handle new connection requests
Packit Service 3975d1
		if (pollfds[SRV_SOCKET].revents) {
Packit Service 3975d1
Packit Service 3975d1
			if (num_fds == MAX_CLIENT_CONNECTIONS+1) {
Packit Service 3975d1
				LOG("exceeded max connections!\n");
Packit Service 3975d1
				continue;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			conn_socket = accept(server_socket, NULL, NULL);
Packit Service 3975d1
Packit Service 3975d1
			if (conn_socket < 0) {
Packit Service 3975d1
				LOG("failed to accept new connection!\n");
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("accepting connection %d.\n", conn_socket);
Packit Service 3975d1
Packit Service 3975d1
				pollfds[num_fds].fd = conn_socket;
Packit Service 3975d1
				pollfds[num_fds].events = POLLIN | POLLPRI;
Packit Service 3975d1
				++num_fds;
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	opae_api_unregister_all_events();
Packit Service 3975d1
Packit Service 3975d1
	// close any active client sockets
Packit Service 3975d1
	for (i = FIRST_CLIENT_SOCKET ; i < num_fds ; ++i) {
Packit Service 3975d1
		close(pollfds[i].fd);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
out_close_server:
Packit Service 3975d1
	evt_api_is_ready = false;
Packit Service 3975d1
	close(server_socket);
Packit Service 3975d1
out_exit:
Packit Service 3975d1
	LOG("exiting\n");
Packit Service 3975d1
	return NULL;
Packit Service 3975d1
}