blob: 9b5785a3cc964e96efc1c97897af5d3263c41165 [file] [log] [blame]
Elliott Hughes65f0df72014-12-03 14:39:20 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gtest/gtest.h>
18
19#include <pty.h>
20#include <sys/ioctl.h>
21
Elliott Hughes33697a02016-01-26 13:04:57 -080022#include "utils.h"
23
Elliott Hughes65f0df72014-12-03 14:39:20 -080024TEST(pty, openpty) {
25 int master, slave;
26 char name[32];
27 struct winsize w = { 123, 456, 9999, 999 };
28 ASSERT_EQ(0, openpty(&master, &slave, name, NULL, &w));
29 ASSERT_NE(-1, master);
30 ASSERT_NE(-1, slave);
31 ASSERT_NE(master, slave);
32
33 char tty_name[32];
34 ASSERT_EQ(0, ttyname_r(slave, tty_name, sizeof(tty_name)));
35 ASSERT_STREQ(tty_name, name);
36
37 struct winsize w_actual;
38 ASSERT_EQ(0, ioctl(slave, TIOCGWINSZ, &w_actual));
39 ASSERT_EQ(w_actual.ws_row, w.ws_row);
40 ASSERT_EQ(w_actual.ws_col, w.ws_col);
41 ASSERT_EQ(w_actual.ws_xpixel, w.ws_xpixel);
42 ASSERT_EQ(w_actual.ws_ypixel, w.ws_ypixel);
43
44 close(master);
45 close(slave);
46}
47
48TEST(pty, forkpty) {
49 pid_t sid = getsid(0);
50
51 int master;
52 pid_t pid = forkpty(&master, NULL, NULL, NULL);
53 ASSERT_NE(-1, pid);
54
55 if (pid == 0) {
56 // We're the child.
57 ASSERT_NE(sid, getsid(0));
58 _exit(0);
59 }
60
61 ASSERT_EQ(sid, getsid(0));
62
Elliott Hughes33697a02016-01-26 13:04:57 -080063 AssertChildExited(pid, 0);
Elliott Hughes65f0df72014-12-03 14:39:20 -080064
65 close(master);
66}
Alex Vakulenkoe9014472016-07-11 17:26:35 -070067
68struct PtyReader_28979140_Arg {
69 int main_cpu_id;
70 int slave_fd;
71 uint32_t data_count;
72 bool finished;
73 std::atomic<bool> matched;
74};
75
76static void PtyReader_28979140(PtyReader_28979140_Arg* arg) {
77 arg->finished = false;
78 cpu_set_t cpus;
79 ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
80 CPU_CLR(arg->main_cpu_id, &cpus);
81 ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
82
83 uint32_t counter = 0;
84 while (counter <= arg->data_count) {
85 char buf[4096]; // Use big buffer to read to hit the bug more easily.
86 size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t));
87 ASSERT_TRUE(android::base::ReadFully(arg->slave_fd, buf, to_read));
88 size_t num_of_value = to_read / sizeof(uint32_t);
89 uint32_t* p = reinterpret_cast<uint32_t*>(buf);
90 while (num_of_value-- > 0) {
91 if (*p++ != counter++) {
92 arg->matched = false;
93 }
94 }
95 }
96 close(arg->slave_fd);
97 arg->finished = true;
98}
99
100TEST(pty, bug_28979140) {
101 // This test is to test a kernel bug, which uses a lock free ring-buffer to
102 // pass data through a raw pty, but missing necessary memory barriers.
103 cpu_set_t cpus;
104 ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
105 if (CPU_COUNT(&cpus) < 2) {
106 GTEST_LOG_(INFO) << "This test tests bug happens only on multiprocessors.";
107 return;
108 }
109 constexpr uint32_t TEST_DATA_COUNT = 200000;
110
111 // 1. Open raw pty.
112 int master;
113 int slave;
114 ASSERT_EQ(0, openpty(&master, &slave, nullptr, nullptr, nullptr));
115 termios tattr;
116 ASSERT_EQ(0, tcgetattr(slave, &tattr));
117 cfmakeraw(&tattr);
118 ASSERT_EQ(0, tcsetattr(slave, TCSADRAIN, &tattr));
119
120 // 2. Make master thread and slave thread running on different cpus:
121 // master thread uses first available cpu, and slave thread uses other cpus.
122 PtyReader_28979140_Arg arg;
123 arg.main_cpu_id = -1;
124 for (int i = 0; i < CPU_SETSIZE; i++) {
125 if (CPU_ISSET(i, &cpus)) {
126 arg.main_cpu_id = i;
127 break;
128 }
129 }
130 ASSERT_GE(arg.main_cpu_id, 0);
131
132 // 3. Create thread for slave reader.
133 pthread_t thread;
134 arg.slave_fd = slave;
135 arg.data_count = TEST_DATA_COUNT;
136 arg.matched = true;
137 ASSERT_EQ(0, pthread_create(&thread, nullptr,
138 reinterpret_cast<void*(*)(void*)>(PtyReader_28979140),
139 &arg));
140
141 CPU_ZERO(&cpus);
142 CPU_SET(arg.main_cpu_id, &cpus);
143 ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));
144
145 // 4. Send data to slave.
146 uint32_t counter = 0;
147 while (counter <= TEST_DATA_COUNT) {
148 ASSERT_TRUE(android::base::WriteFully(master, &counter, sizeof(counter)));
149 ASSERT_TRUE(arg.matched) << "failed at count = " << counter;
150 counter++;
151 }
152 ASSERT_EQ(0, pthread_join(thread, nullptr));
153 ASSERT_TRUE(arg.finished);
154 ASSERT_TRUE(arg.matched);
155 close(master);
156}