await fetch(url)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
struct pollfd
struct pollfd { int fd; // the file descriptor short events; // what you're interested in short revents; // what actually happened (filled by kernel)
}; int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd { int fd; // the file descriptor short events; // what you're interested in short revents; // what actually happened (filled by kernel)
}; int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd { int fd; // the file descriptor short events; // what you're interested in short revents; // what actually happened (filled by kernel)
}; int poll(struct pollfd *fds, nfds_t nfds, int timeout);
// Create the epoll instance
int epfd = epoll_create1(0); // Register a file descriptor with it (once, not every loop)
struct epoll_event ev = { .events = EPOLLIN, .data.fd = sockfd };
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); // Wait for events (this is the blocking call in your event loop)
int n = epoll_wait(epfd, events, MAX_EVENTS, timeout_ms);
// Create the epoll instance
int epfd = epoll_create1(0); // Register a file descriptor with it (once, not every loop)
struct epoll_event ev = { .events = EPOLLIN, .data.fd = sockfd };
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); // Wait for events (this is the blocking call in your event loop)
int n = epoll_wait(epfd, events, MAX_EVENTS, timeout_ms);
// Create the epoll instance
int epfd = epoll_create1(0); // Register a file descriptor with it (once, not every loop)
struct epoll_event ev = { .events = EPOLLIN, .data.fd = sockfd };
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev); // Wait for events (this is the blocking call in your event loop)
int n = epoll_wait(epfd, events, MAX_EVENTS, timeout_ms);
int kq = kqueue(); struct kevent change = { .ident = sockfd, .filter = EVFILT_READ, .flags = EV_ADD | EV_ENABLE,
};
kevent(kq, &change, 1, NULL, 0, NULL); // Wait for events
struct kevent events[MAX_EVENTS];
int n = kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
int kq = kqueue(); struct kevent change = { .ident = sockfd, .filter = EVFILT_READ, .flags = EV_ADD | EV_ENABLE,
};
kevent(kq, &change, 1, NULL, 0, NULL); // Wait for events
struct kevent events[MAX_EVENTS];
int n = kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
int kq = kqueue(); struct kevent change = { .ident = sockfd, .filter = EVFILT_READ, .flags = EV_ADD | EV_ENABLE,
};
kevent(kq, &change, 1, NULL, 0, NULL); // Wait for events
struct kevent events[MAX_EVENTS];
int n = kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
EWOULDBLOCK
time.sleep(1)
asyncio.sleep
requests.get
await fetch(url)
SelectorEventLoop
ProactorEventLoop
conn.Read(buf)
errno == EAGAIN
man 7 epoll
man 2 select - man 7 epoll — the Linux epoll interface, with edge-triggered vs. level-triggered details (which we glossed over — it's worth reading)
- man 2 select, man 2 poll — the originals, for historical grounding
- The C10K Problem — Dan Kegel's 2001 writeup that defined the problem and surveyed every solution available at the time. A historical artifact and still essential reading.
- libuv design overview — how Node's I/O layer works, with diagrams
- Tokio internals — the Tokio scheduler design post, remarkably readable