mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 17:33:23 +00:00
Correct the blocking behavior
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
67065835ef
commit
fe6b78058c
129
test/apps/pty/pty_blocking.c
Normal file
129
test/apps/pty/pty_blocking.c
Normal file
@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include "../network/test.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <pty.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
static int master, slave;
|
||||
|
||||
FN_SETUP(openpty)
|
||||
{
|
||||
CHECK(openpty(&master, &slave, NULL, NULL, NULL));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
static int write_repeat(int fd, char c, size_t n)
|
||||
{
|
||||
while (n--)
|
||||
if (write(fd, &c, 1) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_repeat(int fd, char c, size_t n)
|
||||
{
|
||||
char c2;
|
||||
|
||||
while (n--)
|
||||
if (read(fd, &c2, 1) != 1 || c2 != c)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_all(int fd, char c)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (;;) {
|
||||
if (ioctl(fd, FIONREAD, &n) < 0)
|
||||
return -1;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
if (read_repeat(fd, c, n) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#define PTR_VOID_FALSE ((void *)0)
|
||||
#define PTR_VOID_TRUE ((void *)1)
|
||||
|
||||
// Tests that `block` will block the thread until `unblock` is called.
|
||||
#define DECLARE_BLOCKING_TEST(name, block, unblock) \
|
||||
void *blocking_##name(void *is_child) \
|
||||
{ \
|
||||
static _Atomic int started = 0; \
|
||||
static _Atomic int ended = 0; \
|
||||
\
|
||||
if (!is_child) { \
|
||||
started = 1; \
|
||||
block; \
|
||||
\
|
||||
if (ended != 1) \
|
||||
return PTR_VOID_FALSE; \
|
||||
} else { \
|
||||
usleep(100 * 1000); \
|
||||
if (started != 1) \
|
||||
return PTR_VOID_FALSE; \
|
||||
\
|
||||
ended = 1; \
|
||||
unblock; \
|
||||
} \
|
||||
\
|
||||
return PTR_VOID_TRUE; \
|
||||
}
|
||||
#define RUN_BLOCKING_TEST(name) \
|
||||
{ \
|
||||
pthread_t __thd; \
|
||||
void *__res; \
|
||||
TEST_SUCC(pthread_create(&__thd, NULL, blocking_##name, \
|
||||
PTR_VOID_TRUE)); \
|
||||
TEST_SUCC(blocking_##name(PTR_VOID_FALSE) == PTR_VOID_TRUE ? \
|
||||
0 : \
|
||||
-1); \
|
||||
TEST_RES(pthread_join(__thd, &__res), __res == PTR_VOID_TRUE); \
|
||||
}
|
||||
|
||||
DECLARE_BLOCKING_TEST(write_slave, write_repeat(slave, 'a', 1),
|
||||
read_all(master, 'a'));
|
||||
DECLARE_BLOCKING_TEST(read_master, read_repeat(master, 'a', 1),
|
||||
write_repeat(slave, 'a', 1));
|
||||
DECLARE_BLOCKING_TEST(read_slave, read_repeat(slave, 'a', 1),
|
||||
write_repeat(master, '\n', 1));
|
||||
|
||||
FN_TEST(pty_blocking)
|
||||
{
|
||||
// Write many characters to overflow the line buffer. As documented in the man pages, the
|
||||
// line buffer can hold a maximum of 4095 characters, not including the line terminator.
|
||||
// Additional characters will not be queued, but signals and echoes will still work.
|
||||
// Therefore, the echoed characters will cause the output buffer to overflow.
|
||||
TEST_SUCC(write_repeat(master, 'a', 128 * 1024));
|
||||
|
||||
// Since the output buffer is overflowing, writing characters to it should block. In Linux,
|
||||
// reading one character from the buffer does not unblock the writer, which is rather odd.
|
||||
// So here we test that reading all characters from the buffer should unblock the printer.
|
||||
RUN_BLOCKING_TEST(write_slave);
|
||||
TEST_SUCC(read_all(master, 'a'));
|
||||
|
||||
// Now that the output buffer is empty, reading characters from it should block. Writing a
|
||||
// character to the buffer should unblock the reader.
|
||||
RUN_BLOCKING_TEST(read_master);
|
||||
|
||||
// The input buffer is empty because all characters are in the line buffer until a line
|
||||
// terminator is seen. So reading characters from the input buffer should block. Writing a
|
||||
// line character should move all characters in the line buffer into the input buffer and
|
||||
// unblock the reader.
|
||||
RUN_BLOCKING_TEST(read_slave);
|
||||
TEST_SUCC(read_repeat(slave, 'a', 4094));
|
||||
TEST_SUCC(read_repeat(slave, '\n', 1));
|
||||
|
||||
// TODO: This test does not cover cases in which the input buffer overflows. Reliably
|
||||
// constructing that state is difficult without first knowing the size of the input buffer.
|
||||
}
|
||||
END_TEST()
|
@ -35,6 +35,7 @@ process/group_session
|
||||
process/job_control
|
||||
pthread/pthread_test
|
||||
pty/open_pty
|
||||
pty/pty_blocking
|
||||
sched/sched_attr
|
||||
shm/posix_shm
|
||||
signal_c/parent_death_signal
|
||||
|
Reference in New Issue
Block a user