Re: [PATCH] tty: fix stall caused by missing memory barrier indrivers/tty/n_tty.c

From: Kosuke Tatsukawa
Date: Wed Sep 30 2015 - 21:56:23 EST


This is a reproducer for the stall problem in drivers/tty/n_tty.c

To reproduce the problem, save the program below as pty.c, compile it,
and run it in parallel.

# cc -o pty pty.c
# for i in {1..16}; do ./pty& done; wait

The problem can be reproduced on a multi-socket server with recent CPUs.
The program always stalled during the first run when I used a server
with the following CPU.
Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz
2-sockets x 16-cores x 2-threads

Best regards.
---
Kosuke TATSUKAWA | 3rd IT Platform Department
| IT Platform Division, NEC Corporation
| tatsu@xxxxxxxxxxxxx

--------------------------------< pty.c >--------------------------------
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/wait.h>
#include <sys/time.h>

#define COUNT 300000
#define SIZE 1

char data[SIZE];

int
main(
int argc,
char **argv)
{
int i, fdp, fdt, status;
char *slavename;
struct termios t;
pid_t pid;
struct timeval tv1, tv2;

if ((fdp = open("/dev/ptmx", 2)) < 0) {
perror("ptmx open");
exit(1);
}
grantpt(fdp);
unlockpt(fdp);
slavename = ptsname(fdp);
if ((fdt = open(slavename, 2)) < 0) {
perror("pty open");
close(fdp);
exit(1);
}
tcgetattr(fdt, &t);
t.c_lflag &= ~ECHO;
t.c_oflag &= ~OPOST;
t.c_lflag &= ~ICANON;
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
tcsetattr(fdt, TCSANOW, &t);

tcgetattr(fdp, &t);
t.c_lflag &= ~ECHO;
t.c_oflag &= ~OPOST;
t.c_lflag &= ~ICANON;
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
tcsetattr(fdp, TCSANOW, &t);

memset(data, 'A', SIZE);

if ((pid = fork()) < 0) {
perror("fork");
close(fdt);
close(fdp);
exit(1);
}
if (pid == 0) { /* Child */
sleep(1);
for (i = 0; i < COUNT; i++) {
if (write(fdt, data, SIZE) != SIZE) {
perror("write fdt");
exit(1);
}
if (read(fdt, data, SIZE) != SIZE) {
perror("read fdt");
exit(1);
}
}
exit(0);
} else { /* Parent */
for (i = 0; i < COUNT; i++) {
if (i == 1)
gettimeofday(&tv1, NULL);
if (read(fdp, data, SIZE) != SIZE) {
perror("read fdp");
exit(1);
}
if (write(fdp, data, SIZE) != SIZE) {
perror("write fdp");
exit(1);
}
}
}
gettimeofday(&tv2, NULL);
#if 0
printf("%d\n", (tv2.tv_sec - tv1.tv_sec) * 1000000 +
tv2.tv_usec - tv1.tv_usec);
#endif
wait(&status);
exit(0);
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/