Skip to content
Snippets Groups Projects
Commit a7119874 authored by Mark Brown's avatar Mark Brown Committed by Catalin Marinas
Browse files

kselftest/arm64: Handle EINTR while reading data from children


Currently we treat any error when reading from the child as a failure and
don't read any more output from that child as a result. This ignores the
fact that it is valid for read() to return EINTR as the error code if there
is a signal pending so we could stop handling the output of children,
especially during exit when we will get some SIGCHLD signals delivered to
us. Fix this by pulling the read handling out into a separate function
which returns a flag if reads should be continued and wrapping it in a
loop.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220921181345.618085-4-broonie@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent dd72dd7c
No related branches found
No related tags found
No related merge requests found
......@@ -121,55 +121,70 @@ static void child_start(struct child_data *child, const char *program)
}
}
static void child_output(struct child_data *child, uint32_t events,
bool flush)
static bool child_output_read(struct child_data *child)
{
char read_data[1024];
char work[1024];
int ret, len, cur_work, cur_read;
if (events & EPOLLIN) {
ret = read(child->stdout, read_data, sizeof(read_data));
if (ret < 0) {
ksft_print_msg("%s: read() failed: %s (%d)\n",
child->name, strerror(errno), errno);
return;
}
len = ret;
ret = read(child->stdout, read_data, sizeof(read_data));
if (ret < 0) {
if (errno == EINTR)
return true;
child->output_seen = true;
ksft_print_msg("%s: read() failed: %s (%d)\n",
child->name, strerror(errno),
errno);
return false;
}
len = ret;
/* Pick up any partial read */
if (child->output) {
strncpy(work, child->output, sizeof(work) - 1);
cur_work = strnlen(work, sizeof(work));
free(child->output);
child->output = NULL;
} else {
cur_work = 0;
}
child->output_seen = true;
cur_read = 0;
while (cur_read < len) {
work[cur_work] = read_data[cur_read++];
/* Pick up any partial read */
if (child->output) {
strncpy(work, child->output, sizeof(work) - 1);
cur_work = strnlen(work, sizeof(work));
free(child->output);
child->output = NULL;
} else {
cur_work = 0;
}
if (work[cur_work] == '\n') {
work[cur_work] = '\0';
ksft_print_msg("%s: %s\n", child->name, work);
cur_work = 0;
} else {
cur_work++;
}
}
cur_read = 0;
while (cur_read < len) {
work[cur_work] = read_data[cur_read++];
if (cur_work) {
if (work[cur_work] == '\n') {
work[cur_work] = '\0';
ret = asprintf(&child->output, "%s", work);
if (ret == -1)
ksft_exit_fail_msg("Out of memory\n");
ksft_print_msg("%s: %s\n", child->name, work);
cur_work = 0;
} else {
cur_work++;
}
}
if (cur_work) {
work[cur_work] = '\0';
ret = asprintf(&child->output, "%s", work);
if (ret == -1)
ksft_exit_fail_msg("Out of memory\n");
}
return false;
}
static void child_output(struct child_data *child, uint32_t events,
bool flush)
{
bool read_more;
if (events & EPOLLIN) {
do {
read_more = child_output_read(child);
} while (read_more);
}
if (events & EPOLLHUP) {
close(child->stdout);
child->stdout = -1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment