Changeset View
Changeset View
Standalone View
Standalone View
tests/sys/kqueue/kevent_exclusive.c
- This file was added.
/*- | |||||
* Copyright 2022 Dmitry Chagin <dchagin@FreeBSD.org> | |||||
* | |||||
* SPDX-License-Identifier: BSD-2-Clause | |||||
*/ | |||||
#include <sys/cdefs.h> | |||||
#include <sys/event.h> | |||||
#include <sys/socket.h> | |||||
#include <sys/un.h> | |||||
#include <errno.h> | |||||
#include <pthread.h> | |||||
#include <atf-c.h> | |||||
static int kq; | |||||
static int evagain; | |||||
static int evfired; | |||||
static int evwblock; | |||||
static int evaccpt; | |||||
#define SERVER_PATH "server_kevexcl" | |||||
#ifndef EV_EXCLUSIVE | |||||
#define EV_EXCLUSIVE 0x0400 | |||||
#endif | |||||
static inline struct timespec | |||||
make_timespec(time_t s, long int ns) | |||||
{ | |||||
struct timespec rts; | |||||
rts.tv_sec = s; | |||||
rts.tv_nsec = ns; | |||||
return (rts); | |||||
} | |||||
static void * | |||||
waiter(void *arg) | |||||
{ | |||||
struct kevent tevent; | |||||
struct timespec timeout; | |||||
int afd; | |||||
ssize_t ec; | |||||
timeout = make_timespec(0, 5000000); | |||||
ec = kevent(kq, NULL, 0, &tevent, 1, &timeout); | |||||
if (ec == 0) { | |||||
evwblock++; | |||||
return (NULL); | |||||
} | |||||
ATF_REQUIRE_EQ(1, ec); | |||||
evfired++; | |||||
afd = accept((int)tevent.ident, NULL, NULL); | |||||
if (afd == -1 && errno == EAGAIN) | |||||
evagain++; | |||||
else if (afd > 0) { | |||||
evaccpt++; | |||||
ATF_REQUIRE_EQ(0, close(afd)); | |||||
} | |||||
return (NULL); | |||||
} | |||||
static void * | |||||
waiter2(void *arg) | |||||
{ | |||||
struct kevent tevent; | |||||
int afd; | |||||
ssize_t ec; | |||||
ec = kevent(kq, NULL, 0, &tevent, 1, NULL); | |||||
ATF_REQUIRE_EQ(1, ec); | |||||
evfired++; | |||||
afd = accept((int)tevent.ident, NULL, NULL); | |||||
ATF_REQUIRE(afd > 0); | |||||
evaccpt++; | |||||
ATF_REQUIRE_EQ(0, close(afd)); | |||||
return (NULL); | |||||
} | |||||
ATF_TC_WITH_CLEANUP(exclusiveon); | |||||
ATF_TC_BODY(exclusiveon, tc) | |||||
{ | |||||
struct sockaddr_un server; | |||||
socklen_t len; | |||||
struct kevent event; | |||||
pthread_t w0, w1; | |||||
int srvfd, clfd; | |||||
evagain = evfired = evwblock = evaccpt = 0; | |||||
/* server */ | |||||
len = sizeof(struct sockaddr_un); | |||||
memset(&server, 0, len); | |||||
server.sun_family = AF_UNIX; | |||||
strcpy(server.sun_path, SERVER_PATH); | |||||
srvfd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); | |||||
ATF_REQUIRE(srvfd > 0); | |||||
ATF_REQUIRE_EQ(0, bind(srvfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, listen(srvfd, 5)); | |||||
kq = kqueue(); | |||||
ATF_REQUIRE(kq >= 0); | |||||
EV_SET(&event, srvfd, EVFILT_READ, EV_ADD | EV_EXCLUSIVE, | |||||
0, 0, NULL); | |||||
ATF_REQUIRE_EQ(0, kevent(kq, &event, 1, NULL, 0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w0, NULL, waiter, | |||||
(void *) (uintptr_t) 1)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w1, NULL, waiter, | |||||
(void *) (uintptr_t) 2)); | |||||
clfd = socket(PF_UNIX, SOCK_STREAM, 0); | |||||
ATF_REQUIRE(clfd > 0); | |||||
ATF_REQUIRE_EQ(0, connect(clfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w1, NULL)); | |||||
ATF_REQUIRE_EQ(0, evagain); | |||||
ATF_REQUIRE_EQ(1, evfired); | |||||
ATF_REQUIRE_EQ(1, evwblock); | |||||
ATF_REQUIRE_EQ(1, evaccpt); | |||||
ATF_REQUIRE_EQ(0, close(clfd)); | |||||
ATF_REQUIRE_EQ(0, close(srvfd)); | |||||
ATF_REQUIRE_EQ(0, close(kq)); | |||||
ATF_REQUIRE_EQ(0, unlink(SERVER_PATH)); | |||||
} | |||||
ATF_TC_HEAD(exclusiveon, tc) | |||||
{ | |||||
atf_tc_set_md_var(tc, "descr", "Check waleups if EV_EXCLUSIVE is set"); | |||||
} | |||||
ATF_TC_CLEANUP(exclusiveon, tc) | |||||
{ | |||||
unlink(SERVER_PATH); | |||||
} | |||||
ATF_TC_WITH_CLEANUP(exclusiveoff); | |||||
ATF_TC_BODY(exclusiveoff, tc) | |||||
{ | |||||
struct sockaddr_un server; | |||||
socklen_t len; | |||||
struct kevent event; | |||||
pthread_t w0, w1; | |||||
int srvfd, clfd; | |||||
evagain = evfired = evwblock = evaccpt = 0; | |||||
/* server */ | |||||
len = sizeof(struct sockaddr_un); | |||||
memset(&server, 0, len); | |||||
server.sun_family = AF_UNIX; | |||||
strcpy(server.sun_path, SERVER_PATH); | |||||
srvfd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); | |||||
ATF_REQUIRE(srvfd > 0); | |||||
ATF_REQUIRE_EQ(0, bind(srvfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, listen(srvfd, 5)); | |||||
kq = kqueue(); | |||||
ATF_REQUIRE(kq >= 0); | |||||
EV_SET(&event, srvfd, EVFILT_READ, EV_ADD, 0, 0, NULL); | |||||
ATF_REQUIRE_EQ(0, kevent(kq, &event, 1, NULL, 0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w0, NULL, waiter, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w1, NULL, waiter, NULL)); | |||||
clfd = socket(PF_UNIX, SOCK_STREAM, 0); | |||||
ATF_REQUIRE(clfd > 0); | |||||
ATF_REQUIRE_EQ(0, connect(clfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w1, NULL)); | |||||
ATF_REQUIRE_EQ(1, evagain); | |||||
ATF_REQUIRE_EQ(2, evfired); | |||||
ATF_REQUIRE_EQ(0, evwblock); | |||||
ATF_REQUIRE_EQ(1, evaccpt); | |||||
ATF_REQUIRE_EQ(0, close(clfd)); | |||||
ATF_REQUIRE_EQ(0, close(srvfd)); | |||||
ATF_REQUIRE_EQ(0, close(kq)); | |||||
ATF_REQUIRE_EQ(0, unlink(SERVER_PATH)); | |||||
} | |||||
ATF_TC_HEAD(exclusiveoff, tc) | |||||
{ | |||||
atf_tc_set_md_var(tc, "descr", "Check waleups if EV_EXCLUSIVE is not set"); | |||||
} | |||||
ATF_TC_CLEANUP(exclusiveoff, tc) | |||||
{ | |||||
unlink(SERVER_PATH); | |||||
} | |||||
ATF_TC_WITH_CLEANUP(exclusiveon2); | |||||
ATF_TC_BODY(exclusiveon2, tc) | |||||
{ | |||||
struct sockaddr_un server; | |||||
socklen_t len; | |||||
struct kevent event; | |||||
pthread_t w0, w1; | |||||
int srvfd, clfd; | |||||
evagain = evfired = evwblock = evaccpt = 0; | |||||
/* server */ | |||||
len = sizeof(struct sockaddr_un); | |||||
memset(&server, 0, len); | |||||
server.sun_family = AF_UNIX; | |||||
strcpy(server.sun_path, SERVER_PATH); | |||||
srvfd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); | |||||
ATF_REQUIRE(srvfd > 0); | |||||
ATF_REQUIRE_EQ(0, bind(srvfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, listen(srvfd, 5)); | |||||
kq = kqueue(); | |||||
ATF_REQUIRE(kq >= 0); | |||||
EV_SET(&event, srvfd, EVFILT_READ, EV_ADD | EV_EXCLUSIVE, | |||||
0, 0, NULL); | |||||
ATF_REQUIRE_EQ(0, kevent(kq, &event, 1, NULL, 0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w0, NULL, waiter2, | |||||
(void *) (uintptr_t) 1)); | |||||
ATF_REQUIRE_EQ(0, pthread_create(&w1, NULL, waiter2, | |||||
(void *) (uintptr_t) 2)); | |||||
clfd = socket(PF_UNIX, SOCK_STREAM, 0); | |||||
ATF_REQUIRE(clfd > 0); | |||||
ATF_REQUIRE_EQ(0, connect(clfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, close(clfd)); | |||||
clfd = socket(PF_UNIX, SOCK_STREAM, 0); | |||||
ATF_REQUIRE(clfd > 0); | |||||
ATF_REQUIRE_EQ(0, connect(clfd, (struct sockaddr *)&server, len)); | |||||
ATF_REQUIRE_EQ(0, close(clfd)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w0, NULL)); | |||||
ATF_REQUIRE_EQ(0, pthread_join(w1, NULL)); | |||||
ATF_REQUIRE_EQ(0, evagain); | |||||
ATF_REQUIRE_EQ(2, evfired); | |||||
ATF_REQUIRE_EQ(0, evwblock); | |||||
ATF_REQUIRE_EQ(2, evaccpt); | |||||
ATF_REQUIRE_EQ(0, close(srvfd)); | |||||
ATF_REQUIRE_EQ(0, close(kq)); | |||||
ATF_REQUIRE_EQ(0, unlink(SERVER_PATH)); | |||||
} | |||||
ATF_TC_HEAD(exclusiveon2, tc) | |||||
{ | |||||
atf_tc_set_md_var(tc, "descr", "Check waleups if EV_EXCLUSIVE is set"); | |||||
} | |||||
ATF_TC_CLEANUP(exclusiveon2, tc) | |||||
{ | |||||
unlink(SERVER_PATH); | |||||
} | |||||
ATF_TP_ADD_TCS(tp) | |||||
{ | |||||
/* | |||||
* Thundering herd & EV_EXCLUSIVE | |||||
*/ | |||||
ATF_TP_ADD_TC(tp, exclusiveon); | |||||
ATF_TP_ADD_TC(tp, exclusiveoff); | |||||
ATF_TP_ADD_TC(tp, exclusiveon2); | |||||
return (atf_no_error()); | |||||
} |