Blame usr/event_poll.c

Packit Service 646995
/*
Packit Service 646995
 * iSCSI daemon event handler 
Packit Service 646995
 *
Packit Service 646995
 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
Packit Service 646995
 * Copyright (C) 2006 Mike Christie
Packit Service 646995
 * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
Packit Service 646995
 * maintained by open-iscsi@googlegroups.com
Packit Service 646995
 *
Packit Service 646995
 * Originally based on:
Packit Service 646995
 * (C) 2004 FUJITA Tomonori <tomof@acm.org>
Packit Service 646995
 *
Packit Service 646995
 * This program is free software; you can redistribute it and/or modify
Packit Service 646995
 * it under the terms of the GNU General Public License as published
Packit Service 646995
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service 646995
 * (at your option) any later version.
Packit Service 646995
 *
Packit Service 646995
 * This program is distributed in the hope that it will be useful, but
Packit Service 646995
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 646995
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit Service 646995
 * General Public License for more details.
Packit Service 646995
 *
Packit Service 646995
 * See the file COPYING included with this distribution for more details.
Packit Service 646995
 */
Packit Service 646995
#include <stdlib.h>
Packit Service 646995
#include <errno.h>
Packit Service 646995
#include <poll.h>
Packit Service 646995
#include <sys/types.h>
Packit Service 646995
#include <sys/wait.h>
Packit Service 646995
#include <sys/signalfd.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
Packit Service 646995
#include "mgmt_ipc.h"
Packit Service 646995
#include "iscsi_ipc.h"
Packit Service 646995
#include "sysfs.h"
Packit Service 646995
#include "iscsid.h"
Packit Service 646995
#include "log.h"
Packit Service 646995
#include "iscsi_ipc.h"
Packit Service 646995
#include "actor.h"
Packit Service 646995
#include "initiator.h"
Packit Service 646995
#include "iscsi_err.h"
Packit Service 646995
Packit Service 646995
static unsigned int reap_count;
Packit Service 646995
Packit Service 646995
/* track pid of reload fork, while running */
Packit Service 646995
static pid_t reload_pid = 0;
Packit Service 646995
static void (*reload_callback)(void);
Packit Service 646995
Packit Service 646995
#define REAP_WAKEUP 1000 /* in millisecs */
Packit Service 646995
Packit Service 646995
void reap_inc(void)
Packit Service 646995
{
Packit Service 646995
	reap_count++;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
/* track the reload process to be reaped, when done */
Packit Service 646995
void reap_track_reload_process(pid_t reload_proc_pid, void (*reload_done_callback)(void))
Packit Service 646995
{
Packit Service 646995
	reload_pid = reload_proc_pid;
Packit Service 646995
	reload_callback = reload_done_callback;
Packit Service 646995
	reap_inc();
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void reap_proc(void)
Packit Service 646995
{
Packit Service 646995
	int i, max_reaps;
Packit Service 646995
	pid_t rc;
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * We don't really need reap_count, but calling wait() all the
Packit Service 646995
	 * time seems excessive.
Packit Service 646995
	 */
Packit Service 646995
	max_reaps = reap_count;
Packit Service 646995
	for (i = 0; i < max_reaps; i++) {
Packit Service 646995
		rc = waitpid(0, NULL, WNOHANG);
Packit Service 646995
		if (rc > 0) {
Packit Service 646995
			if (rc == reload_pid) {
Packit Service 646995
				log_debug(6, "reaped reload process");
Packit Service 646995
				reload_callback();
Packit Service 646995
			}
Packit Service 646995
			reap_count--;
Packit Service 646995
			log_debug(6, "reaped pid %d, reap_count now %d",
Packit Service 646995
				  (int)rc, reap_count);
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static LIST_HEAD(shutdown_callbacks);
Packit Service 646995
Packit Service 646995
struct shutdown_callback {
Packit Service 646995
	struct list_head list;
Packit Service 646995
	pid_t pid;
Packit Service 646995
};
Packit Service 646995
Packit Service 646995
int shutdown_callback(pid_t pid)
Packit Service 646995
{
Packit Service 646995
	struct shutdown_callback *cb;
Packit Service 646995
Packit Service 646995
	cb = calloc(1, sizeof(*cb));
Packit Service 646995
	if (!cb)
Packit Service 646995
		return ENOMEM;
Packit Service 646995
Packit Service 646995
	INIT_LIST_HEAD(&cb->list);
Packit Service 646995
	cb->pid = pid;
Packit Service 646995
	log_debug(1, "adding %d for shutdown cb", pid);
Packit Service 646995
	list_add_tail(&cb->list, &shutdown_callbacks);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static void shutdown_notify_pids(void)
Packit Service 646995
{
Packit Service 646995
	struct shutdown_callback *cb;
Packit Service 646995
Packit Service 646995
	list_for_each_entry(cb, &shutdown_callbacks, list) {
Packit Service 646995
		log_debug(1, "Killing %d", cb->pid);
Packit Service 646995
		kill(cb->pid, SIGTERM);
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int shutdown_wait_pids(void)
Packit Service 646995
{
Packit Service 646995
	struct shutdown_callback *cb, *tmp;
Packit Service 646995
Packit Service 646995
	list_for_each_entry_safe(cb, tmp, &shutdown_callbacks, list) {
Packit Service 646995
		/*
Packit Service 646995
		 * the proc reaper could clean it up, so wait for any
Packit Service 646995
		 * sign that it is gone.
Packit Service 646995
		 */
Packit Service 646995
		if (waitpid(cb->pid, NULL, WNOHANG)) {
Packit Service 646995
			log_debug(1, "%d done", cb->pid);
Packit Service 646995
			list_del(&cb->list);
Packit Service 646995
			free(cb);
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return list_empty(&shutdown_callbacks);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#define POLL_CTRL	0
Packit Service 646995
#define POLL_IPC	1
Packit Service 646995
#define POLL_ALARM	2
Packit Service 646995
#define POLL_MAX	3
Packit Service 646995
Packit Service 646995
static volatile int event_loop_stop;
Packit Service 646995
static queue_task_t *shutdown_qtask; 
Packit Service 646995
Packit Service 646995
void event_loop_exit(queue_task_t *qtask)
Packit Service 646995
{
Packit Service 646995
	shutdown_qtask = qtask;
Packit Service 646995
	event_loop_stop = 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
Packit Service 646995
{
Packit Service 646995
	struct pollfd poll_array[POLL_MAX];
Packit Service 646995
	int res, has_shutdown_children = 0;
Packit Service 646995
	sigset_t sigset;
Packit Service 646995
	int sig_fd;
Packit Service 646995
Packit Service 646995
	/* Mask off SIGALRM so we can recv it via signalfd */
Packit Service 646995
	sigemptyset(&sigset);
Packit Service 646995
	sigaddset(&sigset, SIGALRM);
Packit Service 646995
	sigprocmask(SIG_SETMASK, &sigset, NULL);
Packit Service 646995
Packit Service 646995
	sig_fd = signalfd(-1, &sigset, SFD_NONBLOCK);
Packit Service 646995
	if (sig_fd == -1) {
Packit Service 646995
		log_error("signalfd failed: %m");
Packit Service 646995
		return;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	poll_array[POLL_CTRL].fd = control_fd;
Packit Service 646995
	poll_array[POLL_CTRL].events = POLLIN;
Packit Service 646995
	poll_array[POLL_IPC].fd = mgmt_ipc_fd;
Packit Service 646995
	poll_array[POLL_IPC].events = POLLIN;
Packit Service 646995
	poll_array[POLL_ALARM].fd = sig_fd;
Packit Service 646995
	poll_array[POLL_ALARM].events = POLLIN;
Packit Service 646995
Packit Service 646995
	event_loop_stop = 0;
Packit Service 646995
	while (1) {
Packit Service 646995
		if (event_loop_stop) {
Packit Service 646995
			if (!has_shutdown_children) {
Packit Service 646995
				has_shutdown_children = 1;
Packit Service 646995
				shutdown_notify_pids();
Packit Service 646995
			}
Packit Service 646995
			if (shutdown_wait_pids())
Packit Service 646995
				break;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		/* Runs actors and may set alarm for future actors */
Packit Service 646995
		actor_poll();
Packit Service 646995
Packit Service 646995
		res = poll(poll_array, POLL_MAX, reap_count ? REAP_WAKEUP : -1);
Packit Service 646995
Packit Service 646995
		if (res > 0) {
Packit Service 646995
			log_debug(6, "poll result %d", res);
Packit Service 646995
			if (poll_array[POLL_CTRL].revents)
Packit Service 646995
				ipc->ctldev_handle();
Packit Service 646995
Packit Service 646995
			if (poll_array[POLL_IPC].revents)
Packit Service 646995
				mgmt_ipc_handle(mgmt_ipc_fd);
Packit Service 646995
Packit Service 646995
			if (poll_array[POLL_ALARM].revents) {
Packit Service 646995
				struct signalfd_siginfo si;
Packit Service 646995
Packit Service 646995
				if (read(sig_fd, &si, sizeof(si)) == -1) {
Packit Service 646995
					log_error("got sigfd read() error, errno (%d), "
Packit Service 646995
						  "exiting", errno);
Packit Service 646995
					break;
Packit Service 646995
				} else {
Packit Service 646995
					log_debug(1, "Poll was woken by an alarm");
Packit Service 646995
				}
Packit Service 646995
			}
Packit Service 646995
		} else if (res < 0) {
Packit Service 646995
			if (errno == EINTR) {
Packit Service 646995
				log_debug(1, "event_loop interrupted");
Packit Service 646995
			} else {
Packit Service 646995
				log_error("got poll() error (%d), errno (%d), "
Packit Service 646995
					  "exiting", res, errno);
Packit Service 646995
				break;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		reap_proc();
Packit Service 646995
Packit Service 646995
		/*
Packit Service 646995
		 * flush sysfs cache since kernel objs may
Packit Service 646995
		 * have changed as a result of handling op
Packit Service 646995
		 */
Packit Service 646995
		sysfs_cleanup();
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (shutdown_qtask)
Packit Service 646995
		mgmt_ipc_write_rsp(shutdown_qtask, ISCSI_SUCCESS);
Packit Service 646995
Packit Service 646995
	close(sig_fd);
Packit Service 646995
	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
Packit Service 646995
}