diff options
Diffstat (limited to 'tools/testing/selftests/epoll/test_epoll.c')
| -rw-r--r-- | tools/testing/selftests/epoll/test_epoll.c | 344 | 
1 files changed, 0 insertions, 344 deletions
diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c deleted file mode 100644 index e0fcff1e833..00000000000 --- a/tools/testing/selftests/epoll/test_epoll.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - *  tools/testing/selftests/epoll/test_epoll.c - * - *  Copyright 2012 Adobe Systems Incorporated - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or - *  (at your option) any later version. - * - *  Paton J. Lewis <palewis@adobe.com> - * - */ - -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/epoll.h> -#include <sys/socket.h> - -/* - * A pointer to an epoll_item_private structure will be stored in the epoll - * item's event structure so that we can get access to the epoll_item_private - * data after calling epoll_wait: - */ -struct epoll_item_private { -	int index;  /* Position of this struct within the epoll_items array. */ -	int fd; -	uint32_t events; -	pthread_mutex_t mutex;  /* Guards the following variables... */ -	int stop; -	int status;  /* Stores any error encountered while handling item. */ -	/* The following variable allows us to test whether we have encountered -	   a problem while attempting to cancel and delete the associated -	   event. When the test program exits, 'deleted' should be exactly -	   one. If it is greater than one, then the failed test reflects a real -	   world situation where we would have tried to access the epoll item's -	   private data after deleting it: */ -	int deleted; -}; - -struct epoll_item_private *epoll_items; - -/* - * Delete the specified item from the epoll set. In a real-world secneario this - * is where we would free the associated data structure, but in this testing - * environment we retain the structure so that we can test for double-deletion: - */ -void delete_item(int index) -{ -	__sync_fetch_and_add(&epoll_items[index].deleted, 1); -} - -/* - * A pointer to a read_thread_data structure will be passed as the argument to - * each read thread: - */ -struct read_thread_data { -	int stop; -	int status;  /* Indicates any error encountered by the read thread. */ -	int epoll_set; -}; - -/* - * The function executed by the read threads: - */ -void *read_thread_function(void *function_data) -{ -	struct read_thread_data *thread_data = -		(struct read_thread_data *)function_data; -	struct epoll_event event_data; -	struct epoll_item_private *item_data; -	char socket_data; - -	/* Handle events until we encounter an error or this thread's 'stop' -	   condition is set: */ -	while (1) { -		int result = epoll_wait(thread_data->epoll_set, -					&event_data, -					1,	/* Number of desired events */ -					1000);  /* Timeout in ms */ -		if (result < 0) { -			/* Breakpoints signal all threads. Ignore that while -			   debugging: */ -			if (errno == EINTR) -				continue; -			thread_data->status = errno; -			return 0; -		} else if (thread_data->stop) -			return 0; -		else if (result == 0)  /* Timeout */ -			continue; - -		/* We need the mutex here because checking for the stop -		   condition and re-enabling the epoll item need to be done -		   together as one atomic operation when EPOLL_CTL_DISABLE is -		   available: */ -		item_data = (struct epoll_item_private *)event_data.data.ptr; -		pthread_mutex_lock(&item_data->mutex); - -		/* Remove the item from the epoll set if we want to stop -		   handling that event: */ -		if (item_data->stop) -			delete_item(item_data->index); -		else { -			/* Clear the data that was written to the other end of -			   our non-blocking socket: */ -			do { -				if (read(item_data->fd, &socket_data, 1) < 1) { -					if ((errno == EAGAIN) || -					    (errno == EWOULDBLOCK)) -						break; -					else -						goto error_unlock; -				} -			} while (item_data->events & EPOLLET); - -			/* The item was one-shot, so re-enable it: */ -			event_data.events = item_data->events; -			if (epoll_ctl(thread_data->epoll_set, -						  EPOLL_CTL_MOD, -						  item_data->fd, -						  &event_data) < 0) -				goto error_unlock; -		} - -		pthread_mutex_unlock(&item_data->mutex); -	} - -error_unlock: -	thread_data->status = item_data->status = errno; -	pthread_mutex_unlock(&item_data->mutex); -	return 0; -} - -/* - * A pointer to a write_thread_data structure will be passed as the argument to - * the write thread: - */ -struct write_thread_data { -	int stop; -	int status;  /* Indicates any error encountered by the write thread. */ -	int n_fds; -	int *fds; -}; - -/* - * The function executed by the write thread. It writes a single byte to each - * socket in turn until the stop condition for this thread is set. If writing to - * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for - * the moment and just move on to the next socket in the list. We don't care - * about the order in which we deliver events to the epoll set. In fact we don't - * care about the data we're writing to the pipes at all; we just want to - * trigger epoll events: - */ -void *write_thread_function(void *function_data) -{ -	const char data = 'X'; -	int index; -	struct write_thread_data *thread_data = -		(struct write_thread_data *)function_data; -	while (!write_thread_data->stop) -		for (index = 0; -		     !thread_data->stop && (index < thread_data->n_fds); -		     ++index) -			if ((write(thread_data->fds[index], &data, 1) < 1) && -				(errno != EAGAIN) && -				(errno != EWOULDBLOCK)) { -				write_thread_data->status = errno; -				return; -			} -} - -/* - * Arguments are currently ignored: - */ -int main(int argc, char **argv) -{ -	const int n_read_threads = 100; -	const int n_epoll_items = 500; -	int index; -	int epoll_set = epoll_create1(0); -	struct write_thread_data write_thread_data = { -		0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int)) -	}; -	struct read_thread_data *read_thread_data = -		malloc(n_read_threads * sizeof(struct read_thread_data)); -	pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t)); -	pthread_t write_thread; - -	printf("-----------------\n"); -	printf("Runing test_epoll\n"); -	printf("-----------------\n"); - -	epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private)); - -	if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 || -		read_thread_data == 0 || read_threads == 0) -		goto error; - -	if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { -		printf("Error: please run this test on a multi-core system.\n"); -		goto error; -	} - -	/* Create the socket pairs and epoll items: */ -	for (index = 0; index < n_epoll_items; ++index) { -		int socket_pair[2]; -		struct epoll_event event_data; -		if (socketpair(AF_UNIX, -			       SOCK_STREAM | SOCK_NONBLOCK, -			       0, -			       socket_pair) < 0) -			goto error; -		write_thread_data.fds[index] = socket_pair[0]; -		epoll_items[index].index = index; -		epoll_items[index].fd = socket_pair[1]; -		if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0) -			goto error; -		/* We always use EPOLLONESHOT because this test is currently -		   structured to demonstrate the need for EPOLL_CTL_DISABLE, -		   which only produces useful information in the EPOLLONESHOT -		   case (without EPOLLONESHOT, calling epoll_ctl with -		   EPOLL_CTL_DISABLE will never return EBUSY). If support for -		   testing events without EPOLLONESHOT is desired, it should -		   probably be implemented in a separate unit test. */ -		epoll_items[index].events = EPOLLIN | EPOLLONESHOT; -		if (index < n_epoll_items / 2) -			epoll_items[index].events |= EPOLLET; -		epoll_items[index].stop = 0; -		epoll_items[index].status = 0; -		epoll_items[index].deleted = 0; -		event_data.events = epoll_items[index].events; -		event_data.data.ptr = &epoll_items[index]; -		if (epoll_ctl(epoll_set, -			      EPOLL_CTL_ADD, -			      epoll_items[index].fd, -			      &event_data) < 0) -			goto error; -	} - -	/* Create and start the read threads: */ -	for (index = 0; index < n_read_threads; ++index) { -		read_thread_data[index].stop = 0; -		read_thread_data[index].status = 0; -		read_thread_data[index].epoll_set = epoll_set; -		if (pthread_create(&read_threads[index], -				   NULL, -				   read_thread_function, -				   &read_thread_data[index]) != 0) -			goto error; -	} - -	if (pthread_create(&write_thread, -			   NULL, -			   write_thread_function, -			   &write_thread_data) != 0) -		goto error; - -	/* Cancel all event pollers: */ -#ifdef EPOLL_CTL_DISABLE -	for (index = 0; index < n_epoll_items; ++index) { -		pthread_mutex_lock(&epoll_items[index].mutex); -		++epoll_items[index].stop; -		if (epoll_ctl(epoll_set, -			      EPOLL_CTL_DISABLE, -			      epoll_items[index].fd, -			      NULL) == 0) -			delete_item(index); -		else if (errno != EBUSY) { -			pthread_mutex_unlock(&epoll_items[index].mutex); -			goto error; -		} -		/* EBUSY means events were being handled; allow the other thread -		   to delete the item. */ -		pthread_mutex_unlock(&epoll_items[index].mutex); -	} -#else -	for (index = 0; index < n_epoll_items; ++index) { -		pthread_mutex_lock(&epoll_items[index].mutex); -		++epoll_items[index].stop; -		pthread_mutex_unlock(&epoll_items[index].mutex); -		/* Wait in case a thread running read_thread_function is -		   currently executing code between epoll_wait and -		   pthread_mutex_lock with this item. Note that a longer delay -		   would make double-deletion less likely (at the expense of -		   performance), but there is no guarantee that any delay would -		   ever be sufficient. Note also that we delete all event -		   pollers at once for testing purposes, but in a real-world -		   environment we are likely to want to be able to cancel event -		   pollers at arbitrary times. Therefore we can't improve this -		   situation by just splitting this loop into two loops -		   (i.e. signal 'stop' for all items, sleep, and then delete all -		   items). We also can't fix the problem via EPOLL_CTL_DEL -		   because that command can't prevent the case where some other -		   thread is executing read_thread_function within the region -		   mentioned above: */ -		usleep(1); -		pthread_mutex_lock(&epoll_items[index].mutex); -		if (!epoll_items[index].deleted) -			delete_item(index); -		pthread_mutex_unlock(&epoll_items[index].mutex); -	} -#endif - -	/* Shut down the read threads: */ -	for (index = 0; index < n_read_threads; ++index) -		__sync_fetch_and_add(&read_thread_data[index].stop, 1); -	for (index = 0; index < n_read_threads; ++index) { -		if (pthread_join(read_threads[index], NULL) != 0) -			goto error; -		if (read_thread_data[index].status) -			goto error; -	} - -	/* Shut down the write thread: */ -	__sync_fetch_and_add(&write_thread_data.stop, 1); -	if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status) -		goto error; - -	/* Check for final error conditions: */ -	for (index = 0; index < n_epoll_items; ++index) { -		if (epoll_items[index].status != 0) -			goto error; -		if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0) -			goto error; -	} -	for (index = 0; index < n_epoll_items; ++index) -		if (epoll_items[index].deleted != 1) { -			printf("Error: item data deleted %1d times.\n", -				   epoll_items[index].deleted); -			goto error; -		} - -	printf("[PASS]\n"); -	return 0; - - error: -	printf("[FAIL]\n"); -	return errno; -}  |