summaryrefslogtreecommitdiff
path: root/stdout.c
blob: e178fe0e180e9e687c2f3c92c65bbfdb26d7d9bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
 *
 * Licensed under the GPL v2. For licencing details see COPYING.
 */

/** \file stdout.c Functions that deal with writing to stdout. */

#include <dirent.h> /* readdir() */
#include <assert.h>

#include "para.h"
#include "string.h"
#include "list.h"
#include "sched.h"
#include "fd.h"
#include "error.h"
#include "stdout.h"

/**
 * The pre_select function of the stdout task.
 *
 * \param s The scheduler this task was registered to.
 * \param t The task structure of the stdout task.
 *
 * This function is always successful. If there is data available in the input
 * buffer, it adds \p STDOUT_FILENO to the write fd set of \a s.
 */
static void stdout_pre_select(struct sched *s, struct task *t)
{
	struct stdout_task *sot = container_of(t, struct stdout_task, task);

	t->error = 0;
	sot->check_fd = 0;
	if (!*sot->loaded) {
		if (*sot->input_error < 0) {
			t->error = *sot->input_error;
			s->timeout.tv_sec = 0;
			s->timeout.tv_usec = 1;
		}
		return;
	}
	sot->check_fd = 1;
	para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
}

/**
 * The post select function of the stdout task.
 *
 * \param s The scheduler this task was registered to.
 * \param t The task structure of the stdout task.
 *
 * This function checks if \p STDOUT_FILENO was included by in the write fd set
 * of \a s during the previous pre_select call.  If yes, and \p STDOUT_FILENO
 * appeears to be writable, the data loaded in the input buffer is written to
 * stdout.
 */
static void stdout_post_select(struct sched *s, struct task *t)
{
	struct stdout_task *sot = container_of(t, struct stdout_task, task);
	ssize_t ret;

	t->error = 0;
	if (!sot->check_fd) {
		if (!*sot->loaded && *sot->input_error < 0)
			t->error = *sot->input_error;
		return;
	}
	if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
		return;
	ret = write(STDOUT_FILENO, *sot->bufp, *sot->loaded);
	if (ret < 0) {
		t->error = -ERRNO_TO_PARA_ERROR(errno);
		return;
	}
	*sot->loaded -= ret;
	if (*sot->loaded)
		memmove(*sot->bufp, *sot->bufp + ret, *sot->loaded);
}

/**
 * Initialize a stdout task structure with default values.
 *
 * \param sot The stdout task structure.
 *
 * This fills in the pre/post select function poinzters of the task structure
 * given by \a sot.
 */
void stdout_set_defaults(struct stdout_task *sot)
{
	int ret;

	sot->task.pre_select = stdout_pre_select;
	sot->task.post_select = stdout_post_select;
	sprintf(sot->task.status, "stdout writer");
	ret = mark_fd_nonblocking(STDOUT_FILENO);
	if (ret >= 0)
		return;
	PARA_EMERG_LOG("%s\n", para_strerror(-ret));
	exit(EXIT_FAILURE);
}