Blob Blame History Raw
// Copyright(c) 2018-2020, Intel Corporation
//
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of  source code  must retain the  above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name  of Intel Corporation  nor the names of its contributors
//   may be used to  endorse or promote  products derived  from this  software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H

#include <signal.h>
#include "fpgad.h"
#include "monitor_thread.h"
#include "event_dispatcher_thread.h"
#include "events_api_thread.h"

#ifdef LOG
#undef LOG
#endif
#define LOG(format, ...) \
log_printf("main: " format, ##__VA_ARGS__)

struct fpgad_config global_config;

void sig_handler(int sig, siginfo_t *info, void *unused)
{
	UNUSED_PARAM(info);
	UNUSED_PARAM(unused);
	switch (sig) {
	case SIGINT:
		// Process interrupted.
		LOG("Got SIGINT. Exiting.\n");
		global_config.running = false;
		break;
	case SIGTERM:
		// Process terminated.
		LOG("Got SIGTERM. Exiting.\n");
		global_config.running = false;
		break;
	}
}

int main(int argc, char *argv[])
{
	int res;
	FILE *fp;

	memset(&global_config, 0, sizeof(global_config));

	global_config.poll_interval_usec = 100 * 1000;
	global_config.running = true;
	global_config.api_socket = "/tmp/fpga_event_socket";
	global_config.num_null_gbs = 0;

	log_set(stdout);

	res = cmd_parse_args(&global_config, argc, argv);
	if (res != 0) {
		if (res == -2)
			res = 0;
		else
			LOG("error parsing command line.\n");
		goto out_destroy;
	}

	if (cmd_canonicalize_paths(&global_config)) {
		LOG("error with paths.\n");
		goto out_destroy;
	}

	if (global_config.daemon) {

		res = daemonize(sig_handler,
				global_config.filemode,
				global_config.directory);
		if (res != 0) {
			LOG("daemonize failed: %s\n", strerror(res));
			goto out_destroy;
		}


	} else {
		struct sigaction sa;

		memset(&sa, 0, sizeof(sa));
		sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
		sa.sa_sigaction = sig_handler;

		res = sigaction(SIGINT, &sa, NULL);
		if (res < 0) {
			LOG("failed to register SIGINT handler.\n");
			goto out_destroy;
		}

		res = sigaction(SIGTERM, &sa, NULL);
		if (res < 0) {
			LOG("failed to register SIGTERM handler.\n");
			goto out_destroy;
		}
	}

	if (log_open(global_config.logfile) < 0) {
		LOG("failed to open log file\n");
		res = 1;
		goto out_destroy;
	}

	fp = fopen(global_config.pidfile, "w");
	if (NULL == fp) {
		LOG("failed to open pid file\n");
		res = 1;
		goto out_destroy;
	}
	fprintf(fp, "%d\n", getpid());
	fclose(fp);

	res = mon_enumerate(&global_config);
	if (res) {
		LOG("OPAE device enumeration failed\n");
		goto out_destroy;
	}

	res = pthread_create(&global_config.event_dispatcher_thr,
			     NULL,
			     event_dispatcher_thread,
			     &event_dispatcher_config);
	if (res) {
		LOG("failed to create event_dispatcher_thread\n");
		global_config.running = false;
		goto out_destroy;
	}

	while (!evt_dispatcher_is_ready())
		usleep(1);

	res = pthread_create(&global_config.monitor_thr,
			     NULL,
			     monitor_thread,
			     &monitor_config);
	if (res) {
		LOG("failed to create monitor_thread\n");
		global_config.running = false;
		goto out_stop_event_dispatcher;
	}

	res = pthread_create(&global_config.events_api_thr,
			     NULL,
			     events_api_thread,
			     &events_api_config);
	if (res) {
		LOG("failed to create events_api_thread\n");
		global_config.running = false;
		goto out_stop_monitor;
	}

	if (pthread_join(global_config.events_api_thr, NULL)) {
		LOG("failed to join events_api_thread\n");
	}
out_stop_monitor:
	if (pthread_join(global_config.monitor_thr, NULL)) {
		LOG("failed to join monitor_thread\n");
	}
out_stop_event_dispatcher:
	if (pthread_join(global_config.event_dispatcher_thr, NULL)) {
		LOG("failed to join event_dispatcher_thread\n");
	}
out_destroy:
	mon_destroy(&global_config);
	cmd_destroy(&global_config);
	log_close();
	return res;
}