• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Chris Wilson <chris@chris-wilson.co.uk>
25  *
26  */
27 
28 /*
29  * Testcase: boundary testing of read(drm_fd)
30  */
31 
32 #include "igt.h"
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <fcntl.h>
40 #include <inttypes.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #include <sys/time.h>
45 #include <sys/poll.h>
46 #include <pthread.h>
47 #include "drm.h"
48 
49 IGT_TEST_DESCRIPTION("Call read(drm) and see if it behaves.");
50 
sighandler(int sig)51 static void sighandler(int sig)
52 {
53 }
54 
assert_empty(int fd)55 static void assert_empty(int fd)
56 {
57 	struct pollfd pfd = {fd, POLLIN};
58 	do_or_die(poll(&pfd, 1, 0));
59 }
60 
generate_event(int fd,enum pipe pipe)61 static void generate_event(int fd, enum pipe pipe)
62 {
63 	igt_assert(kmstest_get_vblank(fd, pipe, DRM_VBLANK_EVENT));
64 }
65 
wait_for_event(int fd)66 static void wait_for_event(int fd)
67 {
68 	struct pollfd pfd = {fd, POLLIN};
69 	igt_assert(poll(&pfd, 1, -1) == 1);
70 }
71 
setup(int in,int nonblock)72 static int setup(int in, int nonblock)
73 {
74 	int fd;
75 	int ret = -1;
76 
77 	alarm(0);
78 
79 	fd = dup(in);
80 	if (fd != -1)
81 		ret = fcntl(fd, F_GETFL);
82 	if (ret != -1) {
83 		if (nonblock)
84 			ret |= O_NONBLOCK;
85 		else
86 			ret &= ~O_NONBLOCK;
87 		ret = fcntl(fd, F_SETFL, ret);
88 	}
89 	igt_require(ret != -1);
90 
91 	assert_empty(fd);
92 	return fd;
93 }
94 
teardown(int fd)95 static void teardown(int fd)
96 {
97 	alarm(0);
98 	assert_empty(fd);
99 	close(fd);
100 	errno = 0;
101 }
102 
test_invalid_buffer(int in)103 static void test_invalid_buffer(int in)
104 {
105 	int fd = setup(in, 0);
106 
107 	alarm(1);
108 
109 	igt_assert_eq(read(fd, (void *)-1, 4096), -1);
110 	igt_assert_eq(errno, EFAULT);
111 
112 	teardown(fd);
113 }
114 
test_fault_buffer(int in,enum pipe pipe)115 static void test_fault_buffer(int in, enum pipe pipe)
116 {
117 	int fd = setup(in, 0);
118 	struct drm_mode_map_dumb arg;
119 	char *buf;
120 
121 	memset(&arg, 0, sizeof(arg));
122 	arg.handle = kmstest_dumb_create(fd, 32, 32, 32, NULL, NULL);
123 
124 	do_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
125 
126 	buf = mmap(0, 4096, PROT_WRITE, MAP_SHARED, fd, arg.offset);
127 	igt_assert(buf != MAP_FAILED);
128 
129 	generate_event(fd, pipe);
130 
131 	alarm(1);
132 
133 	igt_assert(read(fd, buf, 4096) > 0);
134 
135 	munmap(buf, 4096);
136 	teardown(fd);
137 }
138 
test_empty(int in,int nonblock,int expected)139 static void test_empty(int in, int nonblock, int expected)
140 {
141 	char buffer[1024];
142 	int fd = setup(in, nonblock);
143 
144 	alarm(1);
145 	igt_assert_eq(read(fd, buffer, sizeof(buffer)), -1);
146 	igt_assert_eq(errno, expected);
147 
148 	teardown(fd);
149 }
150 
test_short_buffer(int in,int nonblock,enum pipe pipe)151 static void test_short_buffer(int in, int nonblock, enum pipe pipe)
152 {
153 	char buffer[1024]; /* events are typically 32 bytes */
154 	int fd = setup(in, nonblock);
155 
156 	generate_event(fd, pipe);
157 	generate_event(fd, pipe);
158 
159 	wait_for_event(fd);
160 
161 	alarm(3);
162 
163 	igt_assert_eq(read(fd, buffer, 4), 0);
164 	igt_assert(read(fd, buffer, 40) > 0);
165 	igt_assert(read(fd, buffer, 40) > 0);
166 
167 	teardown(fd);
168 }
169 
170 struct short_buffer_wakeup {
171 	pthread_mutex_t mutex;
172 	pthread_cond_t send, recv;
173 	int counter;
174 	int done;
175 	int fd;
176 };
177 
thread_short_buffer_wakeup(void * arg)178 static void *thread_short_buffer_wakeup(void *arg)
179 {
180 	struct short_buffer_wakeup *w = arg;
181 	char buffer; /* events are typically 32 bytes */
182 
183 	while (!w->done) {
184 		/* Short read, does not consume the event. */
185 		igt_assert_eq(read(w->fd, &buffer, sizeof(buffer)), 0);
186 
187 		pthread_mutex_lock(&w->mutex);
188 		if (!--w->counter)
189 			pthread_cond_signal(&w->send);
190 		pthread_cond_wait(&w->recv, &w->mutex);
191 		pthread_mutex_unlock(&w->mutex);
192 	}
193 
194 	return NULL;
195 }
196 
test_short_buffer_wakeup(int in,enum pipe pipe)197 static void test_short_buffer_wakeup(int in, enum pipe pipe)
198 {
199 	const int nt = sysconf(_SC_NPROCESSORS_ONLN) + 1;
200 	struct short_buffer_wakeup w = {
201 		.fd = setup(in, 0),
202 	};
203 	pthread_t t[nt];
204 	char buffer[1024]; /* events are typically 32 bytes */
205 
206 	pthread_mutex_init(&w.mutex, NULL);
207 	pthread_cond_init(&w.send, NULL);
208 	pthread_cond_init(&w.recv, NULL);
209 
210 	for (int n = 0; n < nt; n++)
211 		pthread_create(&t[n], NULL, thread_short_buffer_wakeup, &w);
212 
213 	igt_until_timeout(30) {
214 		struct timespec tv;
215 		int err = 0;
216 
217 		pthread_mutex_lock(&w.mutex);
218 		w.counter = nt;
219 		pthread_cond_broadcast(&w.recv);
220 		pthread_mutex_unlock(&w.mutex);
221 
222 		/* Give each thread a chance to sleep in drm_read() */
223 		pthread_yield();
224 
225 		/* One event should wake all threads as none consume */
226 		generate_event(w.fd, pipe);
227 
228 		clock_gettime(CLOCK_REALTIME, &tv);
229 		tv.tv_sec += 5; /* Let's be very generous to the scheduler */
230 
231 		pthread_mutex_lock(&w.mutex);
232 		while (w.counter && !err)
233 			err = pthread_cond_timedwait(&w.send, &w.mutex, &tv);
234 		pthread_mutex_unlock(&w.mutex);
235 
236 		igt_assert_f(err == 0,
237 			     "Timed out waiting for drm_read() to wakeup on an event\n");
238 
239 		/* No thread should consume the event */
240 		igt_assert(read(w.fd, buffer, sizeof(buffer)) > 0);
241 	}
242 	pthread_mutex_lock(&w.mutex);
243 	w.done = true;
244 	pthread_cond_broadcast(&w.recv);
245 	pthread_mutex_unlock(&w.mutex);
246 
247 	for (int n = 0; n < nt; n++)
248 		pthread_join(t[n], NULL);
249 
250 	close(w.fd);
251 }
252 
253 igt_main
254 {
255 	int fd;
256 	igt_display_t display;
257 	struct igt_fb fb;
258 	enum pipe pipe;
259 
260 	signal(SIGALRM, sighandler);
261 	siginterrupt(SIGALRM, 1);
262 
263 	igt_fixture {
264 		igt_output_t *output;
265 
266 		fd = drm_open_driver_master(DRIVER_ANY);
267 		kmstest_set_vt_graphics_mode();
268 
269 		igt_display_require(&display, fd);
270 		igt_display_require_output(&display);
271 
272 		for_each_pipe_with_valid_output(&display, pipe, output) {
273 			drmModeModeInfo *mode = igt_output_get_mode(output);
274 
275 			igt_create_pattern_fb(fd, mode->hdisplay, mode->vdisplay,
276 					      DRM_FORMAT_XRGB8888,
277 					      LOCAL_DRM_FORMAT_MOD_NONE, &fb);
278 
279 			igt_output_set_pipe(output, pipe);
280 			igt_plane_set_fb(igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY), &fb);
281 			break;
282 		}
283 
284 		igt_display_commit2(&display, display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
285 		igt_require(kmstest_get_vblank(fd, pipe, 0));
286 	}
287 
288 	igt_subtest("invalid-buffer")
289 		test_invalid_buffer(fd);
290 
291 	igt_subtest("fault-buffer")
292 		test_fault_buffer(fd, pipe);
293 
294 	igt_subtest("empty-block")
295 		test_empty(fd, 0, EINTR);
296 
297 	igt_subtest("empty-nonblock")
298 		test_empty(fd, 1, EAGAIN);
299 
300 	igt_subtest("short-buffer-block")
301 		test_short_buffer(fd, 0, pipe);
302 
303 	igt_subtest("short-buffer-nonblock")
304 		test_short_buffer(fd, 1, pipe);
305 
306 	igt_subtest("short-buffer-wakeup")
307 		test_short_buffer_wakeup(fd, pipe);
308 }
309