Blame tools/fpgad/monitor_thread.c

Packit 6639f8
// Copyright(c) 2018-2019, Intel Corporation
Packit 6639f8
//
Packit 6639f8
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 6639f8
// modification, are permitted provided that the following conditions are met:
Packit 6639f8
//
Packit 6639f8
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 6639f8
//   this list of conditions and the following disclaimer.
Packit 6639f8
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 6639f8
//   this list of conditions and the following disclaimer in the documentation
Packit 6639f8
//   and/or other materials provided with the distribution.
Packit 6639f8
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 6639f8
//   may be used to  endorse or promote  products derived  from this  software
Packit 6639f8
//   without specific prior written permission.
Packit 6639f8
//
Packit 6639f8
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 6639f8
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 6639f8
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6639f8
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 6639f8
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 6639f8
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 6639f8
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 6639f8
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 6639f8
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 6639f8
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 6639f8
// POSSIBILITY OF SUCH DAMAGE.
Packit 6639f8
Packit 6639f8
#ifdef HAVE_CONFIG_H
Packit 6639f8
#include <config.h>
Packit 6639f8
#endif // HAVE_CONFIG_H
Packit 6639f8
Packit 6639f8
#include <dlfcn.h>
Packit 6639f8
#include "monitored_device.h"
Packit 6639f8
#include "monitor_thread.h"
Packit 6639f8
#include "event_dispatcher_thread.h"
Packit 6639f8
Packit 6639f8
#ifdef LOG
Packit 6639f8
#undef LOG
Packit 6639f8
#endif
Packit 6639f8
#define LOG(format, ...) \
Packit 6639f8
log_printf("monitor_thread: " format, ##__VA_ARGS__)
Packit 6639f8
Packit 6639f8
monitor_thread_config monitor_config = {
Packit 6639f8
	.global = &global_config,
Packit 6639f8
	.sched_policy = SCHED_RR,
Packit 6639f8
	.sched_priority = 20,
Packit 6639f8
};
Packit 6639f8
Packit 6639f8
STATIC pthread_mutex_t mon_list_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
Packit 6639f8
STATIC fpgad_monitored_device *monitored_device_list;
Packit 6639f8
Packit 6639f8
STATIC void mon_queue_response(fpgad_detection_status status,
Packit 6639f8
			       fpgad_respond_event_t response,
Packit 6639f8
			       fpgad_monitored_device *d,
Packit 6639f8
			       void *response_context)
Packit 6639f8
{
Packit 6639f8
	if (status == FPGAD_STATUS_DETECTED_HIGH) {
Packit 6639f8
Packit 6639f8
		if (evt_queue_response_high(response,
Packit 6639f8
					    d,
Packit 6639f8
					    response_context)) {
Packit 6639f8
			pthread_yield();
Packit 6639f8
		} else {
Packit 6639f8
			LOG("high priority event queue is full. Dropping!\n");
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
	} else if (status == FPGAD_STATUS_DETECTED) {
Packit 6639f8
Packit 6639f8
		if (evt_queue_response(response,
Packit 6639f8
				       d,
Packit 6639f8
				       response_context)) {
Packit 6639f8
			pthread_yield();
Packit 6639f8
		} else {
Packit 6639f8
			LOG("event queue is full. Dropping!\n");
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
	}
Packit 6639f8
}
Packit 6639f8
Packit 6639f8
STATIC void mon_monitor(fpgad_monitored_device *d)
Packit 6639f8
{
Packit 6639f8
	unsigned i;
Packit 6639f8
Packit 6639f8
	if (!d->detections)
Packit 6639f8
		return;
Packit 6639f8
Packit 6639f8
	for (i = 0 ; d->detections[i] ; ++i) {
Packit 6639f8
		fpgad_detection_status result;
Packit 6639f8
		fpgad_detect_event_t detect =
Packit 6639f8
			d->detections[i];
Packit 6639f8
		void *detect_context =
Packit 6639f8
			d->detection_contexts ?
Packit 6639f8
			d->detection_contexts[i] : NULL;
Packit 6639f8
Packit 6639f8
		result = detect(d, detect_context);
Packit 6639f8
Packit 6639f8
		if (result != FPGAD_STATUS_NOT_DETECTED && d->responses) {
Packit 6639f8
			fpgad_respond_event_t response =
Packit 6639f8
				d->responses[i];
Packit 6639f8
			void *response_context =
Packit 6639f8
				d->response_contexts ?
Packit 6639f8
				d->response_contexts[i] : NULL;
Packit 6639f8
Packit 6639f8
			if (response) {
Packit 6639f8
				mon_queue_response(result,
Packit 6639f8
						   response,
Packit 6639f8
						   d,
Packit 6639f8
						   response_context);
Packit 6639f8
			}
Packit 6639f8
		}
Packit 6639f8
	}
Packit 6639f8
}
Packit 6639f8
Packit 6639f8
STATIC volatile bool mon_is_ready = false;
Packit 6639f8
Packit 6639f8
bool monitor_is_ready(void)
Packit 6639f8
{
Packit 6639f8
	return mon_is_ready;
Packit 6639f8
}
Packit 6639f8
Packit 6639f8
void *monitor_thread(void *thread_context)
Packit 6639f8
{
Packit 6639f8
	monitor_thread_config *c = (monitor_thread_config *)thread_context;
Packit 6639f8
	struct sched_param sched_param;
Packit 6639f8
	int policy = 0;
Packit 6639f8
	int res;
Packit 6639f8
	int err;
Packit 6639f8
	fpgad_monitored_device *d;
Packit 6639f8
Packit 6639f8
	LOG("starting\n");
Packit 6639f8
Packit 6639f8
	res = pthread_getschedparam(pthread_self(), &policy, &sched_param);
Packit 6639f8
	if (res) {
Packit 6639f8
		LOG("error getting scheduler params: %s\n", strerror(res));
Packit 6639f8
	} else {
Packit 6639f8
		policy = c->sched_policy;
Packit 6639f8
		sched_param.sched_priority = c->sched_priority;
Packit 6639f8
Packit 6639f8
		res = pthread_setschedparam(pthread_self(),
Packit 6639f8
					    policy,
Packit 6639f8
					    &sched_param);
Packit 6639f8
		if (res) {
Packit 6639f8
			LOG("error setting scheduler params"
Packit 6639f8
			    " (got root?): %s\n", strerror(res));
Packit 6639f8
		}
Packit 6639f8
	}
Packit 6639f8
Packit 6639f8
	mon_is_ready = true;
Packit 6639f8
Packit 6639f8
	while (c->global->running) {
Packit 6639f8
		fpgad_mutex_lock(err, &mon_list_lock);
Packit 6639f8
Packit 6639f8
		for (d = monitored_device_list ; d ; d = d->next) {
Packit 6639f8
			mon_monitor(d);
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
		fpgad_mutex_unlock(err, &mon_list_lock);
Packit 6639f8
Packit 6639f8
		usleep(c->global->poll_interval_usec);
Packit 6639f8
	}
Packit 6639f8
Packit 6639f8
	while (evt_dispatcher_is_ready()) {
Packit 6639f8
		// Wait for the event dispatcher to complete
Packit 6639f8
		// before we destroy the monitored devices.
Packit 6639f8
		usleep(c->global->poll_interval_usec);
Packit 6639f8
	}
Packit 6639f8
Packit 6639f8
	mon_destroy(c->global);
Packit 6639f8
	mon_is_ready = false;
Packit 6639f8
Packit 6639f8
	LOG("exiting\n");
Packit 6639f8
	return NULL;
Packit 6639f8
}
Packit 6639f8
Packit 6639f8
void mon_monitor_device(fpgad_monitored_device *d)
Packit 6639f8
{
Packit 6639f8
	int err;
Packit 6639f8
	fpgad_monitored_device *trav;
Packit 6639f8
Packit 6639f8
	fpgad_mutex_lock(err, &mon_list_lock);
Packit 6639f8
Packit 6639f8
	d->next = NULL;
Packit 6639f8
Packit 6639f8
	if (!monitored_device_list) {
Packit 6639f8
		monitored_device_list = d;
Packit 6639f8
		goto out_unlock;
Packit 6639f8
	}
Packit 6639f8
Packit 6639f8
	for (trav = monitored_device_list ;
Packit 6639f8
		trav->next ;
Packit 6639f8
			trav = trav->next)
Packit 6639f8
		/* find the end of the list */ ;
Packit 6639f8
Packit 6639f8
	trav->next = d;
Packit 6639f8
Packit 6639f8
out_unlock:
Packit 6639f8
	fpgad_mutex_unlock(err, &mon_list_lock);
Packit 6639f8
}
Packit 6639f8
Packit 6639f8
void mon_destroy(struct fpgad_config *c)
Packit 6639f8
{
Packit 6639f8
	unsigned i;
Packit 6639f8
	int err;
Packit 6639f8
	fpgad_monitored_device *d;
Packit 6639f8
Packit 6639f8
	fpgad_mutex_lock(err, &mon_list_lock);
Packit 6639f8
Packit 6639f8
	for (d = monitored_device_list ; d ; ) {
Packit 6639f8
		fpgad_monitored_device *trash = d;
Packit 6639f8
		fpgad_plugin_destroy_t destroy;
Packit 6639f8
Packit 6639f8
		d = d->next;
Packit 6639f8
Packit 6639f8
		if (trash->type == FPGAD_PLUGIN_TYPE_THREAD) {
Packit 6639f8
Packit 6639f8
			if (trash->thread_stop_fn) {
Packit 6639f8
				trash->thread_stop_fn();
Packit 6639f8
			} else {
Packit 6639f8
				LOG("Thread plugin \"%s\" has"
Packit 6639f8
				    " no thread_stop_fn\n",
Packit 6639f8
				    trash->supported->library_path);
Packit 6639f8
				pthread_cancel(trash->thread);
Packit 6639f8
			}
Packit 6639f8
Packit 6639f8
			pthread_join(trash->thread, NULL);
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
		destroy = (fpgad_plugin_destroy_t)
Packit 6639f8
			dlsym(trash->supported->dl_handle,
Packit 6639f8
				FPGAD_PLUGIN_DESTROY);
Packit 6639f8
Packit 6639f8
		if (destroy) {
Packit 6639f8
			destroy(trash);
Packit 6639f8
		} else {
Packit 6639f8
			LOG("warning - no destructor for \"%s\"\n",
Packit 6639f8
				trash->supported->library_path);
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
		if (trash->token)
Packit 6639f8
			fpgaDestroyToken(&trash->token);
Packit 6639f8
Packit 6639f8
		free(trash);
Packit 6639f8
	}
Packit 6639f8
	monitored_device_list = NULL;
Packit 6639f8
Packit 6639f8
	if (c->supported_devices) {
Packit 6639f8
Packit 6639f8
		for (i = 0 ; c->supported_devices[i].library_path ; ++i) {
Packit 6639f8
			fpgad_supported_device *d = &c->supported_devices[i];
Packit 6639f8
Packit 6639f8
			if (d->flags & FPGAD_DEV_LOADED) {
Packit 6639f8
				dlclose(d->dl_handle);
Packit 6639f8
			}
Packit 6639f8
Packit 6639f8
			d->flags = 0;
Packit 6639f8
			d->dl_handle = NULL;
Packit 6639f8
		}
Packit 6639f8
Packit 6639f8
	}
Packit 6639f8
Packit 6639f8
	fpgad_mutex_unlock(err, &mon_list_lock);
Packit 6639f8
}