Blame tools/fpgad/monitor_thread.c

Packit Service 3975d1
// Copyright(c) 2018-2019, 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
#include <dlfcn.h>
Packit Service 3975d1
#include "monitored_device.h"
Packit Service 3975d1
#include "monitor_thread.h"
Packit Service 3975d1
#include "event_dispatcher_thread.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("monitor_thread: " format, ##__VA_ARGS__)
Packit Service 3975d1
Packit Service 3975d1
monitor_thread_config monitor_config = {
Packit Service 3975d1
	.global = &global_config,
Packit Service 3975d1
	.sched_policy = SCHED_RR,
Packit Service 3975d1
	.sched_priority = 20,
Packit Service 3975d1
};
Packit Service 3975d1
Packit Service 3975d1
STATIC pthread_mutex_t mon_list_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
Packit Service 3975d1
STATIC fpgad_monitored_device *monitored_device_list;
Packit Service 3975d1
Packit Service 3975d1
STATIC void mon_queue_response(fpgad_detection_status status,
Packit Service 3975d1
			       fpgad_respond_event_t response,
Packit Service 3975d1
			       fpgad_monitored_device *d,
Packit Service 3975d1
			       void *response_context)
Packit Service 3975d1
{
Packit Service 3975d1
	if (status == FPGAD_STATUS_DETECTED_HIGH) {
Packit Service 3975d1
Packit Service 3975d1
		if (evt_queue_response_high(response,
Packit Service 3975d1
					    d,
Packit Service 3975d1
					    response_context)) {
Packit Service 3975d1
			pthread_yield();
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("high priority event queue is full. Dropping!\n");
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	} else if (status == FPGAD_STATUS_DETECTED) {
Packit Service 3975d1
Packit Service 3975d1
		if (evt_queue_response(response,
Packit Service 3975d1
				       d,
Packit Service 3975d1
				       response_context)) {
Packit Service 3975d1
			pthread_yield();
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("event queue is full. Dropping!\n");
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC void mon_monitor(fpgad_monitored_device *d)
Packit Service 3975d1
{
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
Packit Service 3975d1
	if (!d->detections)
Packit Service 3975d1
		return;
Packit Service 3975d1
Packit Service 3975d1
	for (i = 0 ; d->detections[i] ; ++i) {
Packit Service 3975d1
		fpgad_detection_status result;
Packit Service 3975d1
		fpgad_detect_event_t detect =
Packit Service 3975d1
			d->detections[i];
Packit Service 3975d1
		void *detect_context =
Packit Service 3975d1
			d->detection_contexts ?
Packit Service 3975d1
			d->detection_contexts[i] : NULL;
Packit Service 3975d1
Packit Service 3975d1
		result = detect(d, detect_context);
Packit Service 3975d1
Packit Service 3975d1
		if (result != FPGAD_STATUS_NOT_DETECTED && d->responses) {
Packit Service 3975d1
			fpgad_respond_event_t response =
Packit Service 3975d1
				d->responses[i];
Packit Service 3975d1
			void *response_context =
Packit Service 3975d1
				d->response_contexts ?
Packit Service 3975d1
				d->response_contexts[i] : NULL;
Packit Service 3975d1
Packit Service 3975d1
			if (response) {
Packit Service 3975d1
				mon_queue_response(result,
Packit Service 3975d1
						   response,
Packit Service 3975d1
						   d,
Packit Service 3975d1
						   response_context);
Packit Service 3975d1
			}
Packit Service 3975d1
		}
Packit Service 3975d1
	}
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
STATIC volatile bool mon_is_ready = false;
Packit Service 3975d1
Packit Service 3975d1
bool monitor_is_ready(void)
Packit Service 3975d1
{
Packit Service 3975d1
	return mon_is_ready;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
void *monitor_thread(void *thread_context)
Packit Service 3975d1
{
Packit Service 3975d1
	monitor_thread_config *c = (monitor_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
	int err;
Packit Service 3975d1
	fpgad_monitored_device *d;
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
	mon_is_ready = true;
Packit Service 3975d1
Packit Service 3975d1
	while (c->global->running) {
Packit Service 3975d1
		fpgad_mutex_lock(err, &mon_list_lock);
Packit Service 3975d1
Packit Service 3975d1
		for (d = monitored_device_list ; d ; d = d->next) {
Packit Service 3975d1
			mon_monitor(d);
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		fpgad_mutex_unlock(err, &mon_list_lock);
Packit Service 3975d1
Packit Service 3975d1
		usleep(c->global->poll_interval_usec);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	while (evt_dispatcher_is_ready()) {
Packit Service 3975d1
		// Wait for the event dispatcher to complete
Packit Service 3975d1
		// before we destroy the monitored devices.
Packit Service 3975d1
		usleep(c->global->poll_interval_usec);
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	mon_destroy(c->global);
Packit Service 3975d1
	mon_is_ready = false;
Packit Service 3975d1
Packit Service 3975d1
	LOG("exiting\n");
Packit Service 3975d1
	return NULL;
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
void mon_monitor_device(fpgad_monitored_device *d)
Packit Service 3975d1
{
Packit Service 3975d1
	int err;
Packit Service 3975d1
	fpgad_monitored_device *trav;
Packit Service 3975d1
Packit Service 3975d1
	fpgad_mutex_lock(err, &mon_list_lock);
Packit Service 3975d1
Packit Service 3975d1
	d->next = NULL;
Packit Service 3975d1
Packit Service 3975d1
	if (!monitored_device_list) {
Packit Service 3975d1
		monitored_device_list = d;
Packit Service 3975d1
		goto out_unlock;
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	for (trav = monitored_device_list ;
Packit Service 3975d1
		trav->next ;
Packit Service 3975d1
			trav = trav->next)
Packit Service 3975d1
		/* find the end of the list */ ;
Packit Service 3975d1
Packit Service 3975d1
	trav->next = d;
Packit Service 3975d1
Packit Service 3975d1
out_unlock:
Packit Service 3975d1
	fpgad_mutex_unlock(err, &mon_list_lock);
Packit Service 3975d1
}
Packit Service 3975d1
Packit Service 3975d1
void mon_destroy(struct fpgad_config *c)
Packit Service 3975d1
{
Packit Service 3975d1
	unsigned i;
Packit Service 3975d1
	int err;
Packit Service 3975d1
	fpgad_monitored_device *d;
Packit Service 3975d1
Packit Service 3975d1
	fpgad_mutex_lock(err, &mon_list_lock);
Packit Service 3975d1
Packit Service 3975d1
	for (d = monitored_device_list ; d ; ) {
Packit Service 3975d1
		fpgad_monitored_device *trash = d;
Packit Service 3975d1
		fpgad_plugin_destroy_t destroy;
Packit Service 3975d1
Packit Service 3975d1
		d = d->next;
Packit Service 3975d1
Packit Service 3975d1
		if (trash->type == FPGAD_PLUGIN_TYPE_THREAD) {
Packit Service 3975d1
Packit Service 3975d1
			if (trash->thread_stop_fn) {
Packit Service 3975d1
				trash->thread_stop_fn();
Packit Service 3975d1
			} else {
Packit Service 3975d1
				LOG("Thread plugin \"%s\" has"
Packit Service 3975d1
				    " no thread_stop_fn\n",
Packit Service 3975d1
				    trash->supported->library_path);
Packit Service 3975d1
				pthread_cancel(trash->thread);
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			pthread_join(trash->thread, NULL);
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		destroy = (fpgad_plugin_destroy_t)
Packit Service 3975d1
			dlsym(trash->supported->dl_handle,
Packit Service 3975d1
				FPGAD_PLUGIN_DESTROY);
Packit Service 3975d1
Packit Service 3975d1
		if (destroy) {
Packit Service 3975d1
			destroy(trash);
Packit Service 3975d1
		} else {
Packit Service 3975d1
			LOG("warning - no destructor for \"%s\"\n",
Packit Service 3975d1
				trash->supported->library_path);
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
		if (trash->token)
Packit Service 3975d1
			fpgaDestroyToken(&trash->token);
Packit Service 3975d1
Packit Service 3975d1
		free(trash);
Packit Service 3975d1
	}
Packit Service 3975d1
	monitored_device_list = NULL;
Packit Service 3975d1
Packit Service 3975d1
	if (c->supported_devices) {
Packit Service 3975d1
Packit Service 3975d1
		for (i = 0 ; c->supported_devices[i].library_path ; ++i) {
Packit Service 3975d1
			fpgad_supported_device *d = &c->supported_devices[i];
Packit Service 3975d1
Packit Service 3975d1
			if (d->flags & FPGAD_DEV_LOADED) {
Packit Service 3975d1
				dlclose(d->dl_handle);
Packit Service 3975d1
			}
Packit Service 3975d1
Packit Service 3975d1
			d->flags = 0;
Packit Service 3975d1
			d->dl_handle = NULL;
Packit Service 3975d1
		}
Packit Service 3975d1
Packit Service 3975d1
	}
Packit Service 3975d1
Packit Service 3975d1
	fpgad_mutex_unlock(err, &mon_list_lock);
Packit Service 3975d1
}