Home | History | Annotate | Download | only in tests
      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 (at) 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 
    265