testing/epoll: add epoll test case
This commid add an epoll testcase to test the epoll Test case 1: epoll_wait timeout test. Test case 2: epoll_wait with driver call poll_notify() many times simultaneously. Test case 3: epoll_wait with some driver/socket need call poll_setup() again when it's internal state changed. Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
parent
647db6393d
commit
d6522be9b5
23
testing/epoll/Kconfig
Normal file
23
testing/epoll/Kconfig
Normal file
@ -0,0 +1,23 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config TESTING_EPOLL
|
||||
tristate "cmocka epoll test"
|
||||
default n
|
||||
depends on TESTING_CMOCKA && TIMER_FD && NET_LOCAL
|
||||
---help---
|
||||
Enable the cmocka driver test
|
||||
|
||||
if TESTING_EPOLL
|
||||
|
||||
config TESTING_EPOLL_PRIORITY
|
||||
int "Task priority"
|
||||
default 100
|
||||
|
||||
config TESTING_EPOLL_STACKSIZE
|
||||
int "Stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
endif
|
23
testing/epoll/Make.defs
Normal file
23
testing/epoll/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/testing/epoll/Make.defs
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_TESTING_EPOLL),)
|
||||
CONFIGURED_APPS += $(APPDIR)/testing/epoll
|
||||
endif
|
29
testing/epoll/Makefile
Normal file
29
testing/epoll/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
############################################################################
|
||||
# apps/testing/epoll/Makefile
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
PRIORITY = $(CONFIG_TESTING_EPOLL_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_TESTING_EPOLL_STACKSIZE)
|
||||
MODULE = $(CONFIG_TESTING_EPOLL)
|
||||
MAINSRC += epoll.c
|
||||
PROGNAME += cmocka_epoll
|
||||
|
||||
include $(APPDIR)/Application.mk
|
488
testing/epoll/epoll.c
Normal file
488
testing/epoll/epoll.c
Normal file
@ -0,0 +1,488 @@
|
||||
/****************************************************************************
|
||||
* apps/testing/epoll/epoll.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <cmocka.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define TIME_ERROR_MS (MSEC_PER_TICK * 2)
|
||||
#define TIME_ASSERT_RANGE(e,t) \
|
||||
assert_in_range(e, (t) - TIME_ERROR_MS, (t) + TIME_ERROR_MS)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct epoll_args_s
|
||||
{
|
||||
int efd;
|
||||
struct epoll_event ev;
|
||||
int fd[2];
|
||||
unsigned long start;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct sockaddr_un g_epoll03_addr =
|
||||
{
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = "epoll_test03"
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: show_usage
|
||||
****************************************************************************/
|
||||
|
||||
static void show_usage(FAR const char *progname, int exitcode)
|
||||
{
|
||||
printf("Usage: %s ?\n", progname);
|
||||
printf(" This is an epoll testcase to test the epoll.\n");
|
||||
printf(" Test case 1: epoll_wait timeout test.\n");
|
||||
printf(" Test case 2: epoll_wait with driver call poll_notify()\n");
|
||||
printf(" many times simultaneously.\n");
|
||||
printf(" Test case 3: epoll_wait with some driver/socket need call\n");
|
||||
printf(" poll_setup() again when it's internal state\n");
|
||||
printf(" changed.\n");
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: get_time_ms
|
||||
****************************************************************************/
|
||||
|
||||
static unsigned long get_time_ms(void)
|
||||
{
|
||||
struct timespec tm;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &tm);
|
||||
return tm.tv_sec * MSEC_PER_SEC + tm.tv_nsec / NSEC_PER_MSEC;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: get_elapse
|
||||
****************************************************************************/
|
||||
|
||||
static unsigned long get_elapse(unsigned long start)
|
||||
{
|
||||
return get_time_ms() - start;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: timerfd_stop
|
||||
****************************************************************************/
|
||||
|
||||
static int timerfd_stop(int fd)
|
||||
{
|
||||
struct itimerspec tms;
|
||||
|
||||
tms.it_value.tv_sec = 0;
|
||||
tms.it_value.tv_nsec = 0;
|
||||
return timerfd_settime(fd, 0, &tms, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll01_setup
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll01_setup(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
struct itimerspec tms;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
/* Create timer fd */
|
||||
|
||||
fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
assert_true(fd >= 0);
|
||||
args->fd[0] = fd;
|
||||
|
||||
/* Create epoll fd */
|
||||
|
||||
fd = epoll_create(1);
|
||||
assert_true(fd >= 0);
|
||||
args->efd = fd;
|
||||
|
||||
args->ev.events = EPOLLIN;
|
||||
args->ev.data.fd = args->fd[0];
|
||||
ret = epoll_ctl(fd, EPOLL_CTL_ADD, args->fd[0], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
/* Start the timer */
|
||||
|
||||
tms.it_value.tv_sec = 1;
|
||||
tms.it_value.tv_nsec = 0;
|
||||
tms.it_interval.tv_sec = 0;
|
||||
tms.it_interval.tv_nsec = 0;
|
||||
args->start = get_time_ms();
|
||||
ret = timerfd_settime(args->fd[0], 0, &tms, NULL);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll01
|
||||
****************************************************************************/
|
||||
|
||||
static void epoll01(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
struct epoll_event evs;
|
||||
int ret;
|
||||
|
||||
/* 1st wait should timeout, timer is 1s */
|
||||
|
||||
ret = epoll_wait(args->efd, &evs, 1, 700);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 700);
|
||||
assert_true(ret == 0);
|
||||
|
||||
/* 2nd wait should success and return 1 at 1s */
|
||||
|
||||
ret = epoll_wait(args->efd, &evs, 1, 700);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 1000);
|
||||
assert_true(ret == 1);
|
||||
assert_true(evs.data.fd = args->fd[0]);
|
||||
|
||||
ret = timerfd_stop(args->fd[0]);
|
||||
assert_true(ret == 0);
|
||||
|
||||
/* 3rd wait should directly return 0, timer has stoped */
|
||||
|
||||
ret = epoll_wait(args->efd, &evs, 1, 0);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 1000);
|
||||
assert_true(ret == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll01_teardown
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll01_teardown(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
int ret;
|
||||
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_DEL, args->fd[0], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
close(args->efd);
|
||||
close(args->fd[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll02_setup
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll02_setup(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
struct itimerspec tms;
|
||||
int ret;
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
/* Create epoll fd */
|
||||
|
||||
fd = epoll_create(2);
|
||||
assert_true(fd >= 0);
|
||||
args->efd = fd;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
assert_true(fd >= 0);
|
||||
args->fd[i] = fd;
|
||||
|
||||
args->ev.events = EPOLLIN;
|
||||
args->ev.data.fd = fd;
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_ADD, fd, &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
}
|
||||
|
||||
/* Start timer */
|
||||
|
||||
tms.it_value.tv_sec = 1;
|
||||
tms.it_value.tv_nsec = 0;
|
||||
tms.it_interval.tv_sec = 0;
|
||||
tms.it_interval.tv_nsec = 0;
|
||||
args->start = get_time_ms();
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
ret = timerfd_settime(args->fd[i], 0, &tms, NULL);
|
||||
assert_true(ret >= 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll02
|
||||
****************************************************************************/
|
||||
|
||||
static void epoll02(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
struct epoll_event evs[2];
|
||||
int ret;
|
||||
|
||||
/* 1st wait, shoud return after 1000ms */
|
||||
|
||||
ret = epoll_wait(args->efd, evs, 2, 1100);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 1000);
|
||||
assert_true(ret == 2);
|
||||
assert_true((evs[0].data.fd == args->fd[0] &&
|
||||
evs[1].data.fd == args->fd[1]) ||
|
||||
(evs[0].data.fd == args->fd[1] &&
|
||||
evs[1].data.fd == args->fd[0]));
|
||||
|
||||
/* Stop the timers */
|
||||
|
||||
ret = timerfd_stop(args->fd[0]);
|
||||
assert_true(ret >= 0);
|
||||
ret = timerfd_stop(args->fd[1]);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
/* 2nd wait, should timeout until 200ms */
|
||||
|
||||
args->start = get_time_ms();
|
||||
ret = epoll_wait(args->efd, evs, 2, 200);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 200);
|
||||
assert_true(ret == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll02_teardown
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll02_teardown(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
int ret;
|
||||
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_DEL, args->fd[0], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_DEL, args->fd[1], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
close(args->efd);
|
||||
close(args->fd[0]);
|
||||
close(args->fd[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll03_setup
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll03_setup(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
assert_true(fd >= 0);
|
||||
args->fd[0] = fd;
|
||||
|
||||
fd = epoll_create(1);
|
||||
assert_true(fd >= 0);
|
||||
args->efd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll03_server
|
||||
****************************************************************************/
|
||||
|
||||
static void *epoll03_server(FAR void *arg)
|
||||
{
|
||||
int ret;
|
||||
int new;
|
||||
int fd;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
assert_true(fd >= 0);
|
||||
|
||||
ret = bind(fd, (const struct sockaddr *)&g_epoll03_addr,
|
||||
sizeof(g_epoll03_addr));
|
||||
assert_true(ret >= 0);
|
||||
|
||||
ret = listen(fd, SOMAXCONN);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
new = accept(fd, NULL, NULL);
|
||||
assert_true(new >= 0);
|
||||
usleep(500 * USEC_PER_MSEC);
|
||||
|
||||
ret = write(new, "1234567890", 10);
|
||||
assert_true(ret == 10);
|
||||
usleep(500 * USEC_PER_MSEC);
|
||||
|
||||
close(new);
|
||||
close(fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll03
|
||||
****************************************************************************/
|
||||
|
||||
static void epoll03(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
struct epoll_event evs;
|
||||
pthread_t thread;
|
||||
char buf[10];
|
||||
int ret;
|
||||
|
||||
ret = pthread_create(&thread, NULL, epoll03_server, args);
|
||||
assert_true(ret == 0);
|
||||
|
||||
/* Sleep to make server run */
|
||||
|
||||
usleep(100 * USEC_PER_MSEC);
|
||||
|
||||
ret = connect(args->fd[0], (const struct sockaddr *)&g_epoll03_addr,
|
||||
sizeof(g_epoll03_addr));
|
||||
assert_true(ret == -1 && errno == EINPROGRESS);
|
||||
|
||||
/* Add socket fd to epoll */
|
||||
|
||||
args->ev.events = EPOLLIN;
|
||||
args->ev.data.fd = args->fd[0];
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_ADD, args->fd[0], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
/* 1st wait should timeout, because server accept will trigger
|
||||
* EPOLLOUT event, but we do not set EPOLLOUT in ev.events.
|
||||
* Even the server has writen the data, but to check the EPOLLIN event,
|
||||
* client need call epoll_wait again, because local socket internal state
|
||||
* changed, we need setup it again to get the EPOLLIN event.
|
||||
*/
|
||||
|
||||
args->start = get_time_ms();
|
||||
ret = epoll_wait(args->efd, &evs, 1, 1000);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 1000);
|
||||
assert_true(ret == 0);
|
||||
|
||||
/* 2nd wait shoud return immediately, because server has send
|
||||
* data to client.
|
||||
*/
|
||||
|
||||
ret = epoll_wait(args->efd, &evs, 1, 1000);
|
||||
TIME_ASSERT_RANGE(get_elapse(args->start), 1000);
|
||||
assert_true(ret == 1);
|
||||
assert_true(args->fd[0] == evs.data.fd);
|
||||
|
||||
ret = read(args->fd[0], buf, 10);
|
||||
assert_true(ret == 10);
|
||||
assert_true(memcmp(buf, "1234567890", 10) == 0);
|
||||
|
||||
ret = pthread_join(thread, NULL);
|
||||
assert_true(ret == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll03_teardown
|
||||
****************************************************************************/
|
||||
|
||||
static int epoll03_teardown(FAR void **state)
|
||||
{
|
||||
FAR struct epoll_args_s *args = *state;
|
||||
int ret;
|
||||
|
||||
ret = epoll_ctl(args->efd, EPOLL_CTL_DEL, args->fd[0], &args->ev);
|
||||
assert_true(ret >= 0);
|
||||
|
||||
close(args->efd);
|
||||
close(args->fd[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: main
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
struct epoll_args_s epoll_args;
|
||||
|
||||
memset(&epoll_args, 0, sizeof(epoll_args));
|
||||
|
||||
if (argc >= 2 && *argv[1] == '?')
|
||||
{
|
||||
show_usage(argv[0], 0);
|
||||
}
|
||||
|
||||
const struct CMUnitTest tests[] =
|
||||
{
|
||||
cmocka_unit_test_prestate_setup_teardown(epoll01,
|
||||
epoll01_setup,
|
||||
epoll01_teardown,
|
||||
&epoll_args),
|
||||
cmocka_unit_test_prestate_setup_teardown(epoll02,
|
||||
epoll02_setup,
|
||||
epoll02_teardown,
|
||||
&epoll_args),
|
||||
cmocka_unit_test_prestate_setup_teardown(epoll03,
|
||||
epoll03_setup,
|
||||
epoll03_teardown,
|
||||
&epoll_args),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user