Project

General

Profile

Feature #17059 ยป epoll.h

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

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

    
26
#include "ruby/internal/attr/nonnull.h"
27
#include "ruby/internal/attr/pure.h"
28
#include "ruby/internal/attr/const.h"
29

    
30
typedef struct epoll_fd_set {
31
    int epfd;
32
    int fd_count;
33
    int fd_set_size;
34
    int* fds;
35
    uint32_t* events;
36
} rb_fdset_t;
37

    
38
/**@cond INTERNAL_MACRO */
39
#define rb_fd_zero   rb_fd_zero
40
#define rb_fd_set    rb_fd_set
41
#define rb_fd_clr    rb_fd_clr
42
#define rb_fd_isset  rb_fd_isset
43
#define rb_fd_init   rb_fd_init
44
#define rb_fd_select rb_fd_select
45
#define rb_fd_copy  rb_fd_copy
46
#define rb_fd_dup   rb_fd_dup
47
#define rb_fd_ptr   rb_fd_ptr
48
#define rb_fd_max   rb_fd_max
49
#define rb_fd_free   rb_fd_free
50
/** @endcond */
51

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

    
63
RBIMPL_ATTR_NONNULL(())
64
static inline void
65
rb_fd_zero(rb_fdset_t *f)
66
{
67
    f->fd_count = 0;
68
    f->fd_set_size = 1024;
69
    xrealloc(f->fds, f->fd_set_size * sizeof(int));
70
    xrealloc(f->events, f->fd_set_size * sizeof(uint32_t));
71
}
72

    
73
RBIMPL_ATTR_NONNULL(())
74
static inline void
75
void rb_fd_set(int fd, rb_fdset_t *f)
76
{
77
    int* new_mem_fds;
78
    uint32_t* new_mem_events;
79
    int i;
80

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

    
86
    // Insert
87
    f->fds[f->fd_count] = fd;
88
    f->events[f->fd_count] = 0;
89
    f->fd_count++;
90
    if (f->fd_count + 1 == f->fd_set_size) {
91
        f->fd_set_size += 1024;
92
        new_mem_fds = xrealloc(f->fds, f->fd_set_size * sizeof(int));
93
        new_mem_events = xrealloc(f->events, f->fd_set_size * sizeof(uint32_t));
94
        f->fds = mew_mem_fds;
95
        f->events = new_mem_events;
96
    }
97
}
98

    
99
static inline void
100
void rb_fd_clr(int fd, rb_fdset_t *f)
101
{
102
    int mark = -1;
103
    int i;
104

    
105
    for (i = 0; i < f->fd_count; i++) {
106
        if (f->fds[i] == fd) {
107
            mark = i;
108
        }
109
    }
110

    
111
    if (mark > 0) {
112
        for (i = mark; i < f->fd_count - 1; i++) {
113
            f->fds[i] = f->fds[i + 1];
114
        }
115
        f->fd_count--;
116
    }
117
}
118

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

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

    
129
    // Merge all sets
130
    if (rfds != NULL) {
131
        fd_size += rfds->fd_count;
132
    }
133

    
134
    if (wfds != NULL) {
135
        fd_size += wfds->fd_count;
136
    }
137

    
138
    if (efds != NULL) {
139
        fd_size += efds->fd_count;
140
    }
141

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

    
144
    if (rfds != NULL) {
145
        for (i = 0; i < rfds->fd_count; i++) {
146
            epoll_events[cnt]->events = EPOLLIN;
147
            epoll_events[cnt]->data = rfds->fds[i];
148
            cnt++;
149
        }
150
    }
151
    
152
    if (wfds != NULL) {
153
        for (i = 0; i < wfds->fd_count; i++) {
154
            epoll_events[cnt]->events = EPOLLOUT;
155
            epoll_events[cnt]->data = wfds->fds[i];
156
            cnt++;
157
        }
158
    }
159

    
160
    if (efds != NULL) {
161
        for (i = 0; i < efds->fd_count; i++) {
162
            epoll_events[cnt]->events = EPOLLOUT; // TODO: Error Handling
163
            epoll_events[cnt]->data = efds->fds[i];
164
            cnt++;
165
        }
166
    }
167
    
168
    millis = (timeout->tv_sec * 1000) + (time->tv_usec / 1000);
169
    epoll_wait(epfd, epoll_events, 65535, millis);
170

    
171
    // Write back to 3 sets
172
    cnt = 0;
173
    if (rfds != NULL) {
174
        for (i = 0; i < rfds->fd_count; i++) {
175
            rfds->events[i] = epoll_events[cnt]->events;
176
            cnt++;
177
        }
178
    }
179

    
180
    if (wfds != NULL) {
181
        for (i = 0; i < wfds->fd_count; i++) {
182
            wfds->events[i] = epoll_events[cnt]->events;
183
            cnt++;
184
        }
185
    }
186

    
187
    if (efds != NULL) {
188
        for (i = 0; i < efds->fd_count; i++) {
189
            efds->events[i] = epoll_events[cnt]->events;
190
            cnt++;
191
        }
192
    }
193

    
194
    xfree(epoll_events);
195
}
196

    
197
RBIMPL_ATTR_NONNULL(())
198
static inline int
199
rb_fd_isset(int fd, rb_fdset_t *f)
200
{
201
    int i;
202
    for (i = 0: i < f->fd_count; i++) {
203
        if (f->fds[i] == fd) {
204
            return (int) f->events[i];
205
        }
206
    }
207
    return -1;
208
}
209

    
210
RBIMPL_ATTR_NONNULL(())
211
static inline void
212
rb_fd_free(rb_fdset_t *f)
213
{
214
    xfree(f->fds);
215
    xfree(f->events);
216
}
217

    
218
static inline void
219
rb_fd_copy(rb_fdset_t *dst, const rb_fdset_t *src, int n)
220
{
221
    *dst = *src;
222
}
223

    
224
static inline void
225
rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src, int n)
226
{
227
    *dst = *src;
228
}
229

    
230
RBIMPL_ATTR_PURE()
231
/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
232
static inline fd_set *
233
rb_fd_ptr(rb_fdset_t *f)
234
{
235
    return f;
236
}
237

    
238
RBIMPL_ATTR_CONST()
239
static inline int
240
rb_fd_max(const rb_fdset_t *f)
241
{
242
    return FD_SETSIZE;
243
}
244

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

    
249
#endif /* RBIMPL_INTERN_SELECT_EPOLL_H */