summaryrefslogtreecommitdiff
path: root/stdin.c
blob: 14201a9a6ccc757a26fd437ea2fa7ca24c95c8de (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
102
103
104
/*
 * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
 *
 * Licensed under the GPL v2. For licencing details see COPYING.
 */

/** \file stdin.c Functions that deal with reading from stdin. */

#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 "stdin.h"

/**
 * The pre_select function of the stdin task.
 *
 * \param s The scheduler this task was registered to.
 * \param t The task structure of the stdin task.
 *
 * This function is always successful. If there is space left in the
 * buffer of the stdin task, it adds \p STDIN_FILENO to the read fd set
 * of \a s.
 */
static void stdin_pre_select(struct sched *s, struct task *t)
{
	struct stdin_task *sit = container_of(t, struct stdin_task, task);

	if (sit->output_error && *sit->output_error < 0) {
		t->error = *sit->output_error;
		return;
	}
	t->error = 0;
	sit->check_fd = 0;
	if (sit->loaded >= sit->bufsize)
		return;
	sit->check_fd = 1;
	para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
}

/**
 * The post select function of the stdin task.
 *
 * \param s The scheduler this task was registered to.
 * \param t The task structure of the stdin task.
 *
 * This function checks if \p STDIN_FILENO was included by in the read fd set
 * of \a s during the previous pre_select call.  If yes, and \p STDIN_FILENO
 * appears to be readable, data is read from stdin into the buffer of the
 * stdin task.
 */
static void stdin_post_select(struct sched *s, struct task *t)
{
	struct stdin_task *sit = container_of(t, struct stdin_task, task);
	ssize_t ret;

	if (sit->output_error && *sit->output_error < 0) {
		t->error = *sit->output_error;
		return;
	}
	t->error = 0;
	if (!sit->check_fd)
		return;
	if (!FD_ISSET(STDIN_FILENO, &s->rfds))
		return;
	ret = read(STDIN_FILENO, sit->buf + sit->loaded, sit->bufsize - sit->loaded);
	if (ret < 0)
		t->error = -ERRNO_TO_PARA_ERROR(errno);
	else if (ret > 0)
		sit->loaded += ret;
	else
		t->error = -E_STDIN_EOF;
}

/**
 * Initialize a stdin task structure with default values.
 *
 * \param sit The stdin task structure.
 *
 * This fills in the pre/post select function pointers of the task structure
 * given by \a sit. Moreover, the stdin file desctiptor is set to nonblocking
 * mode and \a bufsize is initialized to 16 KB (but no buffer is allocated).
 */
void stdin_set_defaults(struct stdin_task *sit)
{
	int ret;

	sit->bufsize = 32 * 1024,
	sit->task.pre_select = stdin_pre_select;
	sit->task.post_select = stdin_post_select;
	sprintf(sit->task.status, "stdin reader");
	ret = mark_fd_nonblocking(STDIN_FILENO);
	if (ret >= 0)
		return;
	sit->output_error = NULL;
	PARA_EMERG_LOG("%s\n", para_strerror(-ret));
	exit(EXIT_FAILURE);
}