Blame teamd/teamd_workq.c

Packit cac203
/*
Packit cac203
 *   teamd_workq.c - Teamd work queue
Packit cac203
 *   Copyright (C) 2013-2015 Jiri Pirko <jiri@resnulli.us>
Packit cac203
 *
Packit cac203
 *   This library is free software; you can redistribute it and/or
Packit cac203
 *   modify it under the terms of the GNU Lesser General Public
Packit cac203
 *   License as published by the Free Software Foundation; either
Packit cac203
 *   version 2.1 of the License, or (at your option) any later version.
Packit cac203
 *
Packit cac203
 *   This library is distributed in the hope that it will be useful,
Packit cac203
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cac203
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit cac203
 *   Lesser General Public License for more details.
Packit cac203
 *
Packit cac203
 *   You should have received a copy of the GNU Lesser General Public
Packit cac203
 *   License along with this library; if not, write to the Free Software
Packit cac203
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit cac203
 */
Packit cac203
Packit cac203
#include <stdlib.h>
Packit cac203
#include <unistd.h>
Packit cac203
#include <fcntl.h>
Packit cac203
#include <errno.h>
Packit cac203
#include <private/misc.h>
Packit cac203
Packit cac203
#include "teamd_workq.h"
Packit cac203
Packit cac203
#define WORKQ_CB_NAME "workq"
Packit cac203
Packit cac203
static int teamd_workq_callback_socket(struct teamd_context *ctx, int events,
Packit cac203
				       void *priv)
Packit cac203
{
Packit cac203
	struct teamd_workq *workq;
Packit cac203
	struct teamd_workq *tmp;
Packit cac203
	char bytes[16];
Packit cac203
	int ret;
Packit cac203
	int err;
Packit cac203
Packit cac203
again:
Packit cac203
	ret = read(ctx->workq.pipe_r, bytes, sizeof(bytes));
Packit cac203
	if (ret == -1) {
Packit cac203
		if (errno == EINTR)
Packit cac203
			goto again;
Packit cac203
		else if (errno != EAGAIN)
Packit cac203
			return -errno;
Packit cac203
	}
Packit cac203
Packit cac203
	teamd_loop_callback_disable(ctx, WORKQ_CB_NAME, ctx);
Packit cac203
Packit cac203
	list_for_each_node_entry_safe(workq, tmp, &ctx->workq.work_list, list) {
Packit cac203
		list_del(&workq->list);
Packit cac203
		list_init(&workq->list);
Packit cac203
		err = workq->func(ctx, workq);
Packit cac203
		if (err)
Packit cac203
			return err;
Packit cac203
	}
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
int teamd_workq_init(struct teamd_context *ctx)
Packit cac203
{
Packit cac203
	int fds[2];
Packit cac203
	int err;
Packit cac203
Packit cac203
	list_init(&ctx->workq.work_list);
Packit cac203
	err = pipe2(fds, O_NONBLOCK);
Packit cac203
	if (err)
Packit cac203
		return -errno;
Packit cac203
	ctx->workq.pipe_r = fds[0];
Packit cac203
	ctx->workq.pipe_w = fds[1];
Packit cac203
Packit cac203
	err = teamd_loop_callback_fd_add_tail(ctx, WORKQ_CB_NAME, ctx,
Packit cac203
					      teamd_workq_callback_socket,
Packit cac203
					      ctx->workq.pipe_r,
Packit cac203
					      TEAMD_LOOP_FD_EVENT_READ);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed add workq callback.");
Packit cac203
		goto close_pipe;
Packit cac203
	}
Packit cac203
	return 0;
Packit cac203
Packit cac203
close_pipe:
Packit cac203
	close(ctx->workq.pipe_r);
Packit cac203
	close(ctx->workq.pipe_w);
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
void teamd_workq_fini(struct teamd_context *ctx)
Packit cac203
{
Packit cac203
	struct teamd_workq *workq;
Packit cac203
	struct teamd_workq *tmp;
Packit cac203
Packit cac203
	teamd_loop_callback_del(ctx, WORKQ_CB_NAME, ctx);
Packit cac203
	close(ctx->workq.pipe_r);
Packit cac203
	close(ctx->workq.pipe_w);
Packit cac203
	list_for_each_node_entry_safe(workq, tmp, &ctx->workq.work_list, list) {
Packit cac203
		list_del(&workq->list);
Packit cac203
		list_init(&workq->list);
Packit cac203
	}
Packit cac203
}
Packit cac203
Packit cac203
static void teamd_workq_set_for_process(struct teamd_context *ctx)
Packit cac203
{
Packit cac203
	int err;
Packit cac203
	const char byte = 0;
Packit cac203
Packit cac203
retry:
Packit cac203
	err = write(ctx->workq.pipe_w, &byte, 1);
Packit cac203
	if (err == -1 && errno == EINTR)
Packit cac203
		goto retry;
Packit cac203
	teamd_loop_callback_enable(ctx, WORKQ_CB_NAME, ctx);
Packit cac203
}
Packit cac203
Packit cac203
void teamd_workq_schedule_work(struct teamd_context *ctx,
Packit cac203
			       struct teamd_workq *workq)
Packit cac203
{
Packit cac203
	if (!list_empty(&workq->list))
Packit cac203
		return;
Packit cac203
	list_add_tail(&ctx->workq.work_list, &workq->list);
Packit cac203
	teamd_workq_set_for_process(ctx);
Packit cac203
}
Packit cac203
Packit cac203
void teamd_workq_init_work(struct teamd_workq *workq, teamd_workq_func_t func)
Packit cac203
{
Packit cac203
	workq->func = func;
Packit cac203
	list_init(&workq->list);
Packit cac203
}