Project

General

Profile

Feature #17059 » epoll.h

Updated on Aug.16 - dsh0416 (Delton Ding), 08/16/2020 09:08 PM

 
#ifndef RBIMPL_INTERN_SELECT_EPOLL_H /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_SELECT_EPOLL_H
/**
* @file
* @author Ruby developers <ruby-core@ruby-lang.org>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
* implementation details. Don't take them as canon. They could
* rapidly appear then vanish. The name (path) of this header file
* is also an implementation detail. Do not expect it to persist
* at the place it is now. Developers are free to move it anywhere
* anytime at will.
* @note To ruby-core: remember that this header can be possibly
* recursively included from extension libraries written in C++.
* Do not expect for instance `__VA_ARGS__` is always available.
* We assume C99 for ruby itself but we don't assume languages of
* extension libraries. They could be written in C++98.
* @brief Public APIs to provide ::rb_fd_select().
*/
#include "ruby/internal/config.h"
#include "sys/epoll.h"

#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/const.h"

typedef struct epoll_fd_set {
int epfd;
int fd_count;
int fd_set_size;
int* fds;
uint32_t* events;
} rb_fdset_t;

/**@cond INTERNAL_MACRO */
#define rb_fd_zero rb_fd_zero
#define rb_fd_set rb_fd_set
#define rb_fd_clr rb_fd_clr
#define rb_fd_isset rb_fd_isset
#define rb_fd_init rb_fd_init
#define rb_fd_select rb_fd_select
#define rb_fd_copy rb_fd_copy
#define rb_fd_dup rb_fd_dup
#define rb_fd_ptr rb_fd_ptr
#define rb_fd_max rb_fd_max
#define rb_fd_free rb_fd_free
/** @endcond */

RBIMPL_ATTR_NONNULL(())
static inline void
rb_fd_init(rb_fdset_t *f)
{
f->epfd = epoll_create(65535); // Since Linux 2.6.8, the size argument is ignored, but must be greater than zero
f->fd_count = 0;
f->fd_set_size = 1024;
f->fds = (int *)xmalloc(f->fd_set_size * sizeof(int));
f->events = (uint32_t *)xmalloc(f->fd_set_size * sizeof(uint32_t));
}

RBIMPL_ATTR_NONNULL(())
static inline void
rb_fd_zero(rb_fdset_t *f)
{
f->fd_count = 0;
f->fd_set_size = 1024;
xrealloc(f->fds, f->fd_set_size * sizeof(int));
xrealloc(f->events, f->fd_set_size * sizeof(uint32_t));
}

RBIMPL_ATTR_NONNULL(())
static inline void
void rb_fd_set(int fd, rb_fdset_t *f)
{
int* new_mem_fds;
uint32_t* new_mem_events;
int i;

// Check if fd is in set first
for (i = 0; i < f->fd_count; i++) {
if (f->fds[i] == fd) return;
}

// Insert
f->fds[f->fd_count] = fd;
f->events[f->fd_count] = 0;
f->fd_count++;
if (f->fd_count + 1 == f->fd_set_size) {
f->fd_set_size += 1024;
new_mem_fds = xrealloc(f->fds, f->fd_set_size * sizeof(int));
new_mem_events = xrealloc(f->events, f->fd_set_size * sizeof(uint32_t));
f->fds = mew_mem_fds;
f->events = new_mem_events;
}
}

static inline void
void rb_fd_clr(int fd, rb_fdset_t *f)
{
int mark = -1;
int i;

for (i = 0; i < f->fd_count; i++) {
if (f->fds[i] == fd) {
mark = i;
}
}

if (mark > 0) {
for (i = mark; i < f->fd_count - 1; i++) {
f->fds[i] = f->fds[i + 1];
}
f->fd_count--;
}
}

static inline void
rb_fd_select(int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
{
int epfd, i, cnt, fd_size, millis;
epoll_event* epoll_events;

cnt = 0;
fd_size = 0;
epfd = rfds->epfd; // Pick epfd from any of the set

// Merge all sets
if (rfds != NULL) {
fd_size += rfds->fd_count;
}

if (wfds != NULL) {
fd_size += wfds->fd_count;
}

if (efds != NULL) {
fd_size += efds->fd_count;
}

epoll_events = xmalloc((fd_size) * sizeof(epoll_event));

if (rfds != NULL) {
for (i = 0; i < rfds->fd_count; i++) {
epoll_events[cnt]->events = EPOLLIN;
epoll_events[cnt]->data = rfds->fds[i];
cnt++;
}
}
if (wfds != NULL) {
for (i = 0; i < wfds->fd_count; i++) {
epoll_events[cnt]->events = EPOLLOUT;
epoll_events[cnt]->data = wfds->fds[i];
cnt++;
}
}

if (efds != NULL) {
for (i = 0; i < efds->fd_count; i++) {
epoll_events[cnt]->events = EPOLLOUT; // TODO: Error Handling
epoll_events[cnt]->data = efds->fds[i];
cnt++;
}
}
millis = (timeout->tv_sec * 1000) + (time->tv_usec / 1000);
epoll_wait(epfd, epoll_events, 65535, millis);

// Write back to 3 sets
cnt = 0;
if (rfds != NULL) {
for (i = 0; i < rfds->fd_count; i++) {
rfds->events[i] = epoll_events[cnt]->events;
cnt++;
}
}

if (wfds != NULL) {
for (i = 0; i < wfds->fd_count; i++) {
wfds->events[i] = epoll_events[cnt]->events;
cnt++;
}
}

if (efds != NULL) {
for (i = 0; i < efds->fd_count; i++) {
efds->events[i] = epoll_events[cnt]->events;
cnt++;
}
}

xfree(epoll_events);
}

RBIMPL_ATTR_NONNULL(())
static inline int
rb_fd_isset(int fd, rb_fdset_t *f)
{
int i;
for (i = 0: i < f->fd_count; i++) {
if (f->fds[i] == fd) {
return (int) f->events[i];
}
}
return -1;
}

RBIMPL_ATTR_NONNULL(())
static inline void
rb_fd_free(rb_fdset_t *f)
{
xfree(f->fds);
xfree(f->events);
}

static inline void
rb_fd_copy(rb_fdset_t *dst, const rb_fdset_t *src, int n)
{
*dst = *src;
}

static inline void
rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src, int n)
{
*dst = *src;
}

RBIMPL_ATTR_PURE()
/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
static inline fd_set *
rb_fd_ptr(rb_fdset_t *f)
{
return f;
}

RBIMPL_ATTR_CONST()
static inline int
rb_fd_max(const rb_fdset_t *f)
{
return FD_SETSIZE;
}

/* :FIXME: What are these? They don't exist for shibling implementations. */
#define rb_fd_init_copy(d, s) (*(d) = *(s))
#define rb_fd_term(f) ((void)(f))

#endif /* RBIMPL_INTERN_SELECT_EPOLL_H */
(2-2/2)