File: interp_epoll.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (240 lines) | stat: -rw-r--r-- 8,427 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
from __future__ import with_statement

import errno

from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.error import exception_from_saved_errno
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.time import timeutils
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.tool import rffi_platform
from rpython.rlib._rsocket_rffi import socketclose, FD_SETSIZE
from rpython.rlib.rposix import get_saved_errno
from rpython.rlib.rarithmetic import intmask, widen
from rpython.translator.tool.cbuild import ExternalCompilationInfo


eci = ExternalCompilationInfo(
    includes = ['sys/epoll.h', 'stddef.h', 'stdlib.h', 'stdio.h'],
    post_include_bits = [
        "RPY_EXTERN\n"
        "int pypy_epoll_ctl(int, int, int, uint32_t);"
        "RPY_EXTERN\n"
        "int pypy_epoll_wait(int, uint32_t*, int*, int, int);"
        ],
    separate_module_sources = ['''
        int pypy_epoll_ctl(int epfd, int op, int fd, uint32_t events){
            struct epoll_event evt = {events, (epoll_data_t)fd};
            return epoll_ctl(epfd, op, fd, &evt);
        };
        int pypy_epoll_wait(int epfd, uint32_t *fds, int *evnts, int maxevents, int timeout){
            struct epoll_event *events = malloc(sizeof(struct epoll_event) * maxevents);
            if (events == NULL) {
                return -1;
            }
            int ret = epoll_wait(epfd, events, maxevents, timeout);
            if (ret < 0) {
                free(events);
                return ret;
            }
            for (int i=0; i<ret; i++) {
                fds[i] = events[i].data.fd;
                evnts[i] = events[i].events;
            }
            free(events);
            return ret;
        };
        '''],
)

class CConfig:
    _compilation_info_ = eci


CConfig.epoll_data = rffi_platform.Struct("union epoll_data", [
    ("fd", rffi.INT),
])
CConfig.epoll_event = rffi_platform.Struct("struct epoll_event", [
    ("events", rffi.UINT),
    ("data", CConfig.epoll_data)
])

public_symbols = dict.fromkeys([
    "EPOLLIN", "EPOLLOUT", "EPOLLPRI", "EPOLLERR", "EPOLLHUP",
    "EPOLLET", "EPOLLONESHOT", "EPOLLRDNORM", "EPOLLRDBAND",
    "EPOLLWRNORM", "EPOLLWRBAND", "EPOLLMSG"
    ])
for symbol in public_symbols:
    setattr(CConfig, symbol, rffi_platform.DefinedConstantInteger(symbol))

for symbol in ["EPOLL_CTL_ADD", "EPOLL_CTL_MOD", "EPOLL_CTL_DEL",
               "EPOLL_CLOEXEC"]:
    setattr(CConfig, symbol, rffi_platform.ConstantInteger(symbol))

cconfig = rffi_platform.configure(CConfig)

for symbol in public_symbols:
    public_symbols[symbol] = intmask(cconfig[symbol])


EPOLL_CTL_ADD = cconfig["EPOLL_CTL_ADD"]
EPOLL_CTL_MOD = cconfig["EPOLL_CTL_MOD"]
EPOLL_CTL_DEL = cconfig["EPOLL_CTL_DEL"]
EPOLL_CLOEXEC = cconfig["EPOLL_CLOEXEC"]

DEF_REGISTER_EVENTMASK = (public_symbols["EPOLLIN"] |
                          public_symbols["EPOLLOUT"] |
                          public_symbols["EPOLLPRI"])

epoll_create1 = rffi.llexternal(
    "epoll_create1", [rffi.INT], rffi.INT, compilation_info=eci,
    save_err=rffi.RFFI_SAVE_ERRNO
)
pypy_epoll_ctl = rffi.llexternal(
    "pypy_epoll_ctl",
    [rffi.INT, rffi.INT, rffi.INT, rffi.UINT],
    rffi.INT,
    compilation_info=eci,
    save_err=rffi.RFFI_SAVE_ERRNO
)
pypy_epoll_wait = rffi.llexternal(
    "pypy_epoll_wait",
    [rffi.INT_real, rffi.CArrayPtr(rffi.UINT_real), rffi.CArrayPtr(rffi.INT_real),
     rffi.INT, rffi.INT],
    rffi.INT,
    compilation_info=eci,
    save_err=rffi.RFFI_SAVE_ERRNO
)

class W_Epoll(W_Root):
    def __init__(self, space, epfd):
        self.space = space
        self.epfd = epfd
        self.register_finalizer(space)

    @unwrap_spec(sizehint=int, flags=int)
    def descr__new__(space, w_subtype, sizehint=-1, flags=0):
        if sizehint == -1:
            sizehint = FD_SETSIZE - 1
        elif sizehint <= 0:     # 'sizehint' is otherwise ignored
            raise oefmt(space.w_ValueError,
                        "sizehint must be positive or -1")
        epfd = epoll_create1(flags | EPOLL_CLOEXEC)
        if epfd < 0:
            raise exception_from_saved_errno(space, space.w_IOError)

        return W_Epoll(space, epfd)

    @unwrap_spec(fd=int)
    def descr_fromfd(space, w_cls, fd):
        return W_Epoll(space, fd)

    def _finalize_(self):
        self.close()

    def check_closed(self, space):
        if self.get_closed():
            raise oefmt(space.w_ValueError, "I/O operation on closed epoll fd")

    def get_closed(self):
        return self.epfd < 0

    def close(self):
        if not self.get_closed():
            socketclose(self.epfd)
            self.epfd = -1
            self.may_unregister_rpython_finalizer(self.space)

    def epoll_ctl(self, space, ctl, w_fd, eventmask):
        fd = space.c_filedescriptor_w(w_fd)
        result = pypy_epoll_ctl(self.epfd, ctl, fd, rffi.cast(rffi.UINT, eventmask))
        if result < 0:
            raise exception_from_saved_errno(space, space.w_IOError)

    def descr_get_closed(self, space):
        return space.newbool(self.get_closed())

    def descr_fileno(self, space):
        self.check_closed(space)
        return space.newint(self.epfd)

    def descr_close(self, space):
        self.close()

    @unwrap_spec(eventmask=int)
    def descr_register(self, space, w_fd, eventmask=DEF_REGISTER_EVENTMASK):
        self.check_closed(space)
        self.epoll_ctl(space, EPOLL_CTL_ADD, w_fd, eventmask)

    def descr_unregister(self, space, w_fd):
        self.check_closed(space)
        self.epoll_ctl(space, EPOLL_CTL_DEL, w_fd, 0)

    @unwrap_spec(eventmask=int)
    def descr_modify(self, space, w_fd, eventmask):
        self.check_closed(space)
        self.epoll_ctl(space, EPOLL_CTL_MOD, w_fd, eventmask)

    @unwrap_spec(timeout=float, maxevents=int)
    def descr_poll(self, space, timeout=-1.0, maxevents=-1):
        self.check_closed(space)
        if timeout < 0:
            end_time = 0.0
            itimeout = -1
        else:
            end_time = timeutils.monotonic(space) + timeout
            itimeout = int(timeout * 1000.0 + 0.999)

        if maxevents == -1:
            maxevents = FD_SETSIZE - 1
        elif maxevents < 1:
            raise oefmt(space.w_ValueError,
                        "maxevents must be greater than 0, not %d", maxevents)

        with lltype.scoped_alloc(rffi.CArray(rffi.UINT_real), maxevents) as fids:
            with lltype.scoped_alloc(rffi.CArray(rffi.INT_real), maxevents) as events:
                while True:
                    nfds = pypy_epoll_wait(self.epfd, fids, events, maxevents, itimeout)
                    if nfds < 0:
                        if get_saved_errno() == errno.EINTR:
                            space.getexecutioncontext().checksignals()
                            if itimeout >= 0:
                                timeout = end_time - timeutils.monotonic(space)
                                timeout = max(timeout, 0.0)
                                itimeout = int(timeout * 1000.0 + 0.999)
                            continue
                        raise exception_from_saved_errno(space, space.w_IOError)
                    break

                elist_w = [None] * nfds
                for i in xrange(nfds):
                    elist_w[i] = space.newtuple2(
                        space.newint(intmask(fids[i])), space.newint(intmask(events[i]))
                    )
                return space.newlist(elist_w)

    def descr_enter(self, space):
        self.check_closed(space)
        return self

    def descr_exit(self, space, __args__):
        self.close()


W_Epoll.typedef = TypeDef("select.epoll",
    __new__ = interp2app(W_Epoll.descr__new__.im_func),
    fromfd = interp2app(W_Epoll.descr_fromfd.im_func, as_classmethod=True),

    closed = GetSetProperty(W_Epoll.descr_get_closed),
    fileno = interp2app(W_Epoll.descr_fileno),
    close = interp2app(W_Epoll.descr_close),
    register = interp2app(W_Epoll.descr_register),
    unregister = interp2app(W_Epoll.descr_unregister),
    modify = interp2app(W_Epoll.descr_modify),
    poll = interp2app(W_Epoll.descr_poll),
    __enter__ = interp2app(W_Epoll.descr_enter),
    __exit__ = interp2app(W_Epoll.descr_exit),
)
W_Epoll.typedef.acceptable_as_base_class = False