Skip to content

Commit 6a4742b

Browse files
mstetsyukvadimskipin
authored andcommitted
Add FiberScheduler::connect
keep SOCK_NONBLOCK accept and tests bb fmt
1 parent 3ac994a commit 6a4742b

4 files changed

Lines changed: 133 additions & 47 deletions

File tree

include/silk/fibers/fiber.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <memory>
1010
#include <utility>
1111

12+
#include <sys/socket.h>
1213
#include <sys/uio.h>
1314

1415
namespace silk
@@ -412,6 +413,62 @@ class FiberScheduler
412413
*/
413414
static void poll(int fd, uint32_t events, uint64_t * triggeredEvents, IoFuture * future) noexcept;
414415

416+
/**
417+
* Blocking connect: connect @p fd to @p addr.
418+
*
419+
* @param fd File descriptor to connect.
420+
* @param addr Destination address.
421+
* @param addrlen Length of @p addr.
422+
* @return 0 on success, or a errno on failure.
423+
*/
424+
static int connect(int fd, const sockaddr * addr, socklen_t addrlen) noexcept
425+
{
426+
IoFuture future;
427+
connect(fd, addr, addrlen, &future);
428+
return future.wait();
429+
}
430+
431+
/**
432+
* Async connect. Returns immediately; the caller must wait on @p future
433+
* for the result.
434+
*
435+
* @param fd File descriptor to connect.
436+
* @param addr Destination address; must remain valid until @p future completes.
437+
* @param addrlen Length of @p addr.
438+
* @param future Completion handle; wait() returns 0 on success or a errno on failure.
439+
*/
440+
static void connect(int fd, const sockaddr * addr, socklen_t addrlen, IoFuture * future) noexcept;
441+
442+
/**
443+
* Blocking accept: accept a connection on the listening socket @p fd.
444+
*
445+
* @param fd Listening socket to accept on.
446+
* @param addr If not null, receives the peer address.
447+
* @param addrlen In/out length of @p addr; ignored if @p addr is null.
448+
* @param flags accept4() flags applied to the accepted socket (e.g. SOCK_CLOEXEC).
449+
* @param acceptedFd If not null, receives the accepted socket fd on success.
450+
* @return 0 on success, or a errno on failure.
451+
*/
452+
static int accept(int fd, sockaddr * addr, socklen_t * addrlen, int flags, uint64_t * acceptedFd = nullptr) noexcept
453+
{
454+
IoFuture future;
455+
accept(fd, addr, addrlen, flags, acceptedFd, &future);
456+
return future.wait();
457+
}
458+
459+
/**
460+
* Async accept. Returns immediately; the caller must wait on @p future
461+
* for the result.
462+
*
463+
* @param fd Listening socket to accept on.
464+
* @param addr If not null, receives the peer address; must remain valid until @p future completes.
465+
* @param addrlen In/out length of @p addr; must remain valid until @p future completes; ignored if @p addr is null.
466+
* @param flags accept4() flags applied to the accepted socket (e.g. SOCK_CLOEXEC).
467+
* @param acceptedFd If not null, receives the accepted socket fd on success.
468+
* @param future Completion handle; wait() returns 0 on success or a errno on failure.
469+
*/
470+
static void accept(int fd, sockaddr * addr, socklen_t * addrlen, int flags, uint64_t * acceptedFd, IoFuture * future) noexcept;
471+
415472
/**
416473
* Completion handle for an async sleep submitted via sleep().
417474
*/

src/fibers/fiber.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,18 @@ void FiberScheduler::poll(int fd, uint32_t events, uint64_t * triggeredEvents, I
14361436
enqueueIo(future, [=](io_uring_sqe * sqe) noexcept { ::io_uring_prep_poll_add(sqe, fd, events); });
14371437
}
14381438

1439+
void FiberScheduler::connect(int fd, const sockaddr * addr, socklen_t addrlen, IoFuture * future) noexcept
1440+
{
1441+
future->result = nullptr;
1442+
enqueueIo(future, [=](io_uring_sqe * sqe) noexcept { ::io_uring_prep_connect(sqe, fd, addr, addrlen); });
1443+
}
1444+
1445+
void FiberScheduler::accept(int fd, sockaddr * addr, socklen_t * addrlen, int flags, uint64_t * acceptedFd, IoFuture * future) noexcept
1446+
{
1447+
future->result = acceptedFd;
1448+
enqueueIo(future, [=](io_uring_sqe * sqe) noexcept { ::io_uring_prep_accept(sqe, fd, addr, addrlen, flags); });
1449+
}
1450+
14391451
void FiberScheduler::cancelIo(IoFuture * future) noexcept
14401452
{
14411453
future->result = nullptr;

src/fibers/tests/fiber-test.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#include <sched.h>
1414
#include <unistd.h>
1515

16+
#include <arpa/inet.h>
17+
#include <netinet/in.h>
18+
#include <sys/socket.h>
19+
1620
namespace silk
1721
{
1822

@@ -408,6 +412,60 @@ TEST(Fiber, cancelRead)
408412
::close(fds[1]);
409413
}
410414

415+
// connect + accept: client connect and listener accepts on loopback.
416+
TEST(Fiber, connectAccept)
417+
{
418+
int listenFd = ::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
419+
ASSERT_GE(listenFd, 0);
420+
421+
sockaddr_in addr{};
422+
addr.sin_family = AF_INET;
423+
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
424+
425+
int r = ::bind(listenFd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
426+
ASSERT_EQ(r, 0);
427+
r = ::listen(listenFd, 1);
428+
ASSERT_EQ(r, 0);
429+
430+
socklen_t len = sizeof(addr);
431+
r = ::getsockname(listenFd, reinterpret_cast<sockaddr *>(&addr), &len);
432+
ASSERT_EQ(r, 0);
433+
434+
int clientFd = ::socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
435+
ASSERT_GE(clientFd, 0);
436+
437+
struct Params
438+
{
439+
int listenFd;
440+
int clientFd;
441+
sockaddr_in addr;
442+
443+
static int fiberMain(Params * p) noexcept
444+
{
445+
FiberScheduler::IoFuture connectFuture;
446+
FiberScheduler::connect(p->clientFd, reinterpret_cast<const sockaddr *>(&p->addr), sizeof(p->addr), &connectFuture);
447+
448+
uint64_t acceptedFd = 0;
449+
int a = FiberScheduler::accept(p->listenFd, nullptr, nullptr, SOCK_CLOEXEC, &acceptedFd);
450+
EXPECT_EQ(a, 0);
451+
EXPECT_GE(static_cast<int>(acceptedFd), 0);
452+
453+
EXPECT_EQ(connectFuture.wait(), 0);
454+
455+
::close(static_cast<int>(acceptedFd));
456+
457+
return 0;
458+
}
459+
};
460+
461+
r = FiberScheduler::run(Params::fiberMain, {listenFd, clientFd, addr});
462+
ASSERT_EQ(r, 0);
463+
464+
::close(clientFd);
465+
::close(listenFd);
466+
}
467+
468+
411469
// Stress: many fibers each doing a write+read through their own pipe.
412470
TEST(Fiber, concurrentReadWrite)
413471
{

src/perf/net-perf.cpp

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -134,38 +134,10 @@ int TcpConnection::connect(const char * host, uint16_t port, TcpConnection * out
134134
return r;
135135
}
136136

137-
int r = ::connect(fd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
138-
if (r < 0)
139-
{
140-
r = errno;
141-
if (r != EINPROGRESS)
142-
{
143-
SILK_ERROR("connect failed: %s", std::strerror(r));
144-
::close(fd);
145-
return r;
146-
}
147-
148-
r = silk::FiberScheduler::poll(fd, POLLOUT);
149-
if (r)
150-
{
151-
SILK_ERROR("poll failed: %s", std::strerror(r));
152-
::close(fd);
153-
return r;
154-
}
155-
}
156-
157-
r = 0;
158-
socklen_t len = sizeof(r);
159-
if (::getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &len))
160-
{
161-
r = errno;
162-
SILK_ERROR("getsockopt SO_ERROR failed: %s", std::strerror(r));
163-
::close(fd);
164-
return r;
165-
}
137+
int r = silk::FiberScheduler::connect(fd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
166138
if (r)
167139
{
168-
SILK_ERROR("connect error: %s", std::strerror(r));
140+
SILK_ERROR("connect failed: %s", std::strerror(r));
169141
::close(fd);
170142
return r;
171143
}
@@ -237,26 +209,13 @@ int TcpConnection::listen(const char * host, uint16_t port, int backlog, TcpConn
237209

238210
int TcpConnection::accept(TcpConnection * out) noexcept
239211
{
240-
int fd;
241-
for (;;)
212+
uint64_t acceptedFd = 0;
213+
int r = silk::FiberScheduler::accept(connFd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC, &acceptedFd);
214+
if (r)
242215
{
243-
fd = ::accept4(connFd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
244-
if (fd >= 0)
245-
{
246-
break;
247-
}
248-
249-
int r = errno;
250-
if (r == EAGAIN)
251-
{
252-
r = silk::FiberScheduler::poll(connFd, POLLIN);
253-
if (!r)
254-
{
255-
continue;
256-
}
257-
}
258216
return r;
259217
}
218+
int fd = static_cast<int>(acceptedFd);
260219

261220
int value = 1;
262221
if (::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)))

0 commit comments

Comments
 (0)