OSDN Git Service

radeon: Wire up radeon-symbol-check to make check
[android-x86/external-libdrm.git] / tests / lock.c
1 /*
2  * Copyright © 2007 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  *    Eric Anholt <eric@anholt.net>
25  *
26  */
27
28 /** @file lock.c
29  * Tests various potential failures of the DRM locking mechanisms
30  */
31
32 #include <limits.h>
33 #include <sys/ioctl.h>
34 #include "drmtest.h"
35
36 enum auth_event {
37         SERVER_READY,
38         CLIENT_MAGIC,
39         SERVER_LOCKED,
40         CLIENT_LOCKED,
41 };
42
43 int commfd[2];
44 unsigned int lock1 = 0x00001111;
45 unsigned int lock2 = 0x00002222;
46
47 /* return time in milliseconds */
48 static unsigned int
49 get_millis()
50 {
51         struct timeval tv;
52
53         gettimeofday(&tv, NULL);
54         return tv.tv_sec * 1000 + tv.tv_usec / 1000;
55 }
56
57 static void
58 wait_event(int pipe, enum auth_event expected_event)
59 {
60         int ret;
61         enum auth_event event;
62         unsigned char in;
63
64         ret = read(commfd[pipe], &in, 1);
65         if (ret == -1)
66                 err(1, "read error");
67         event = in;
68
69         if (event != expected_event)
70                 errx(1, "unexpected event: %d\n", event);
71 }
72
73 static void
74 send_event(int pipe, enum auth_event send_event)
75 {
76         int ret;
77         unsigned char event;
78
79         event = send_event;
80         ret = write(commfd[pipe], &event, 1);
81         if (ret == -1)
82                 err(1, "failed to send event %d", event);
83 }
84
85 static void
86 client_auth(int drmfd)
87 {
88         struct drm_auth auth;
89         int ret;
90
91         /* Get a client magic number and pass it to the master for auth. */
92         ret = ioctl(drmfd, DRM_IOCTL_GET_MAGIC, &auth);
93         if (ret == -1)
94                 err(1, "Couldn't get client magic");
95         send_event(0, CLIENT_MAGIC);
96         ret = write(commfd[0], &auth.magic, sizeof(auth.magic));
97         if (ret == -1)
98                 err(1, "Couldn't write auth data");
99 }
100
101 static void
102 server_auth(int drmfd)
103 {
104         struct drm_auth auth;
105         int ret;
106
107         send_event(1, SERVER_READY);
108         wait_event(1, CLIENT_MAGIC);
109         ret = read(commfd[1], &auth.magic, sizeof(auth.magic));
110         if (ret == -1)
111                 err(1, "Failure to read client magic");
112
113         ret = ioctl(drmfd, DRM_IOCTL_AUTH_MAGIC, &auth);
114         if (ret == -1)
115                 err(1, "Failure to authenticate client magic\n");
116 }
117
118 /** Tests that locking is successful in normal conditions */
119 static void
120 test_lock_unlock(int drmfd)
121 {
122         int ret;
123
124         ret = drmGetLock(drmfd, lock1, 0);
125         if (ret != 0)
126                 err(1, "Locking failed");
127         ret = drmUnlock(drmfd, lock1);
128         if (ret != 0)
129                 err(1, "Unlocking failed");
130 }
131
132 /** Tests that unlocking the lock while it's not held works correctly */
133 static void
134 test_unlock_unlocked(int drmfd)
135 {
136         int ret;
137
138         ret = drmUnlock(drmfd, lock1);
139         if (ret == 0)
140                 err(1, "Unlocking unlocked lock succeeded");
141 }
142
143 /** Tests that unlocking a lock held by another context fails appropriately */
144 static void
145 test_unlock_unowned(int drmfd)
146 {
147         int ret;
148
149         ret = drmGetLock(drmfd, lock1, 0);
150         assert(ret == 0);
151         ret = drmUnlock(drmfd, lock2);
152         if (ret == 0)
153                 errx(1, "Unlocking other context's lock succeeded");
154         ret = drmUnlock(drmfd, lock1);
155         assert(ret == 0);
156 }
157
158 /**
159  * Tests that an open/close by the same process doesn't result in the lock
160  * being dropped.
161  */
162 static void test_open_close_locked(drmfd)
163 {
164         int ret, tempfd;
165
166         ret = drmGetLock(drmfd, lock1, 0);
167         assert(ret == 0);
168         /* XXX: Need to make sure that this is the same device as drmfd */
169         tempfd = drm_open_any();
170         close(tempfd);
171         ret = drmUnlock(drmfd, lock1);
172         if (ret != 0)
173                 errx(1, "lock lost during open/close by same pid");
174 }
175
176 static void client()
177 {
178         int drmfd, ret;
179         unsigned int time;
180
181         wait_event(0, SERVER_READY);
182
183         /* XXX: Should make sure we open the same DRM as the master */
184         drmfd = drm_open_any();
185
186         client_auth(drmfd);
187
188         /* Wait for the server to grab the lock, then grab it ourselves (to
189          * contest it).  Hopefully we hit it within the window of when the
190          * server locks.
191          */
192         wait_event(0, SERVER_LOCKED);
193         ret = drmGetLock(drmfd, lock2, 0);
194         time = get_millis();
195         if (ret != 0)
196                 err(1, "Failed to get lock on client\n");
197         drmUnlock(drmfd, lock2);
198
199         /* Tell the server that our locking completed, and when it did */
200         send_event(0, CLIENT_LOCKED);
201         ret = write(commfd[0], &time, sizeof(time));
202
203         close(drmfd);
204         exit(0);
205 }
206
207 static void server()
208 {
209         int drmfd, tempfd, ret;
210         unsigned int client_time, unlock_time;
211
212         drmfd = drm_open_any_master();
213
214         test_lock_unlock(drmfd);
215         test_unlock_unlocked(drmfd);
216         test_unlock_unowned(drmfd);
217         test_open_close_locked(drmfd);
218
219         /* Perform the authentication sequence with the client. */
220         server_auth(drmfd);
221
222         /* Now, test that the client attempting to lock while the server
223          * holds the lock works correctly.
224          */
225         ret = drmGetLock(drmfd, lock1, 0);
226         assert(ret == 0);
227         send_event(1, SERVER_LOCKED);
228         /* Wait a while for the client to do its thing */
229         sleep(1);
230         ret = drmUnlock(drmfd, lock1);
231         assert(ret == 0);
232         unlock_time = get_millis();
233
234         wait_event(1, CLIENT_LOCKED);
235         ret = read(commfd[1], &client_time, sizeof(client_time));
236         if (ret == -1)
237                 err(1, "Failure to read client magic");
238
239         if (client_time < unlock_time)
240                 errx(1, "Client took lock before server released it");
241
242         close(drmfd);
243 }
244
245 int main(int argc, char **argv)
246 {
247         int ret;
248
249
250         ret = pipe(commfd);
251         if (ret == -1)
252                 err(1, "Couldn't create pipe");
253
254         ret = fork();
255         if (ret == -1)
256                 err(1, "failure to fork client");
257         if (ret == 0)
258                 client();
259         else
260                 server();
261
262         return 0;
263 }
264