Skip to content

Commit

Permalink
Revert "Don't use dynamic memory allocation for libuv handles/requests"
Browse files Browse the repository at this point in the history
This reverts commit 6ebd07d.
  • Loading branch information
1st1 committed Jul 12, 2016
1 parent 2b060e1 commit 7b0b195
Show file tree
Hide file tree
Showing 24 changed files with 113 additions and 65 deletions.
16 changes: 12 additions & 4 deletions uvloop/dns.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ cdef class AddrInfo:

cdef class AddrInfoRequest(UVRequest):
cdef:
uv.uv_getaddrinfo_t _req_data
system.addrinfo hints
object callback

Expand Down Expand Up @@ -261,7 +260,12 @@ cdef class AddrInfoRequest(UVRequest):
self.hints.ai_socktype = type
self.hints.ai_protocol = proto

self.request = <uv.uv_req_t*>&self._req_data
self.request = <uv.uv_req_t*> PyMem_Malloc(
sizeof(uv.uv_getaddrinfo_t))
if self.request is NULL:
self.on_done()
raise MemoryError()

self.callback = callback
self.request.data = <void*>self

Expand All @@ -279,11 +283,15 @@ cdef class AddrInfoRequest(UVRequest):

cdef class NameInfoRequest(UVRequest):
cdef:
uv.uv_getnameinfo_t _req_data
object callback

def __cinit__(self, Loop loop, callback):
self.request = <uv.uv_req_t*>&self._req_data
self.request = <uv.uv_req_t*> PyMem_Malloc(
sizeof(uv.uv_getnameinfo_t))
if self.request is NULL:
self.on_done()
raise MemoryError()

self.callback = callback
self.request.data = <void*>self

Expand Down
1 change: 0 additions & 1 deletion uvloop/handles/async_.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
cdef class UVAsync(UVHandle):
cdef:
uv.uv_async_t _handle_data
method_t callback
object ctx

Expand Down
7 changes: 6 additions & 1 deletion uvloop/handles/async_.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ cdef class UVAsync(UVHandle):
cdef int err

self._start_init(loop)
self._handle = <uv.uv_handle_t*>&self._handle_data

self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_async_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

err = uv.uv_async_init(self._loop.uvloop,
<uv.uv_async_t*>self._handle,
Expand Down
1 change: 0 additions & 1 deletion uvloop/handles/check.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
cdef class UVCheck(UVHandle):
cdef:
uv.uv_check_t _handle_data
Handle h
bint running

Expand Down
7 changes: 6 additions & 1 deletion uvloop/handles/check.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ cdef class UVCheck(UVHandle):
cdef int err

self._start_init(loop)
self._handle = <uv.uv_handle_t*>&self._handle_data

self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_check_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

err = uv.uv_check_init(self._loop.uvloop, <uv.uv_check_t*>self._handle)
if err < 0:
Expand Down
1 change: 1 addition & 0 deletions uvloop/handles/handle.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cdef class UVHandle:
cdef _error(self, exc, throw)
cdef _fatal_error(self, exc, throw, reason=?)

cdef _free(self)
cdef _close(self)


Expand Down
36 changes: 30 additions & 6 deletions uvloop/handles/handle.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,47 @@ cdef class UVHandle:
'{} without @no_gc_clear; loop was set to None by GC'
.format(self.__class__.__name__))

if self._handle is NULL or self._closed:
if self._handle is NULL:
return

# -> When we're at this point, something is wrong <-

if self._handle.loop is NULL:
# The handle wasn't initialized with "uv_{handle}_init"
self._handle = NULL
self._closed = 1
self._free()
raise RuntimeError(
'{} is open in __dealloc__ with loop set to NULL'
.format(self.__class__.__name__))

if self._closed == 1:
# So _handle is not NULL and self._closed == 1?
raise RuntimeError(
'{}.__dealloc__: _handle is NULL, _closed == 1'.format(
self.__class__.__name__))

# The handle is dealloced while open. Let's try to close it.
# Situations when this is possible include unhandled exceptions,
# errors during Handle.__cinit__/__init__ etc.
if self._inited:
self._handle.data = <void*> __NOHANDLE__
uv.uv_close(self._handle, __uv_close_handle_cb) # void; no errors
self._handle = NULL
warnings_warn("unclosed resource {!r}".format(self),
ResourceWarning)
else:
# The handle was allocated, but not initialized
self._closed = 1
self._free()

# The handle was allocated, but not initialized
self._closed = 1

cdef _free(self):
PyMem_Free(self._handle)
self._handle = NULL

cdef inline _abort_init(self):
self._handle = NULL
if self._handle is not NULL:
self._free()

IF DEBUG:
name = self.__class__.__name__
Expand Down Expand Up @@ -278,19 +292,29 @@ cdef inline bint __ensure_handle_data(uv.uv_handle_t* handle,
cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) with gil:
cdef:
UVHandle h
Loop loop

if handle.data is NULL:
# Shouldn't happen.
raise RuntimeError('uv_handle_t.data is NULL in close callback')
loop = <Loop>handle.loop.data
loop.call_exception_handler({
'message': 'uv_handle_t.data is NULL in close callback'
})
PyMem_Free(handle)
return

if <object>handle.data is not __NOHANDLE__:
h = <UVHandle>handle.data
h._handle = NULL
IF DEBUG:
h._loop._debug_handles_closed.update([
h.__class__.__name__])
h._free()
Py_DECREF(h) # Was INCREFed in UVHandle._close
return

PyMem_Free(handle)


cdef void __close_all_handles(Loop loop):
uv.uv_walk(loop.uvloop, __uv_walk_close_all_handles_cb, <void*>loop) # void
Expand Down
1 change: 0 additions & 1 deletion uvloop/handles/idle.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
cdef class UVIdle(UVHandle):
cdef:
uv.uv_idle_t _handle_data
Handle h
bint running

Expand Down
7 changes: 6 additions & 1 deletion uvloop/handles/idle.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ cdef class UVIdle(UVHandle):
cdef int err

self._start_init(loop)
self._handle = <uv.uv_handle_t*>&self._handle_data

self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_idle_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

err = uv.uv_idle_init(self._loop.uvloop, <uv.uv_idle_t*>self._handle)
if err < 0:
Expand Down
12 changes: 0 additions & 12 deletions uvloop/handles/pipe.pxd
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
cdef class UnixServer(UVStreamServer):

cdef:
uv.uv_pipe_t _handle_data

cdef bind(self, str path)
cdef open(self, int sockfd)

Expand All @@ -13,9 +10,6 @@ cdef class UnixServer(UVStreamServer):

cdef class UnixTransport(UVStream):

cdef:
uv.uv_pipe_t _handle_data

@staticmethod
cdef UnixTransport new(Loop loop, object protocol, Server server,
object waiter)
Expand All @@ -26,9 +20,6 @@ cdef class UnixTransport(UVStream):

cdef class ReadUnixTransport(UVStream):

cdef:
uv.uv_pipe_t _handle_data

@staticmethod
cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
object waiter)
Expand All @@ -38,9 +29,6 @@ cdef class ReadUnixTransport(UVStream):

cdef class WriteUnixTransport(UVStream):

cdef:
uv.uv_pipe_t _handle_data

@staticmethod
cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
object waiter)
Expand Down
24 changes: 10 additions & 14 deletions uvloop/handles/pipe.pyx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
cdef __pipe_init_uv_handle(UVStream handle, Loop loop):
cdef int err

handle._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_pipe_t))
if handle._handle is NULL:
handle._abort_init()
raise MemoryError()

# Initialize pipe handle with ipc=0.
# ipc=1 means that libuv will use recvmsg/sendmsg
# instead of recv/send.
Expand Down Expand Up @@ -38,10 +44,7 @@ cdef class UnixServer(UVStreamServer):
cdef UnixServer handle
handle = UnixServer.__new__(UnixServer)
handle._init(loop, protocol_factory, server, ssl)

handle._handle = <uv.uv_handle_t*>&handle._handle_data
__pipe_init_uv_handle(<UVStream>handle, loop)

return handle

cdef _new_socket(self):
Expand Down Expand Up @@ -80,10 +83,7 @@ cdef class UnixTransport(UVStream):
cdef UnixTransport handle
handle = UnixTransport.__new__(UnixTransport)
handle._init(loop, protocol, server, waiter)

handle._handle = <uv.uv_handle_t*>&handle._handle_data
__pipe_init_uv_handle(<UVStream>handle, loop)

return handle

cdef _new_socket(self):
Expand All @@ -107,10 +107,7 @@ cdef class ReadUnixTransport(UVStream):
cdef ReadUnixTransport handle
handle = ReadUnixTransport.__new__(ReadUnixTransport)
handle._init(loop, protocol, server, waiter)

handle._handle = <uv.uv_handle_t*>&handle._handle_data
__pipe_init_uv_handle(<UVStream>handle, loop)

return handle

cdef _new_socket(self):
Expand Down Expand Up @@ -160,10 +157,7 @@ cdef class WriteUnixTransport(UVStream):
handle._close_on_read_error()

handle._init(loop, protocol, server, waiter)

handle._handle = <uv.uv_handle_t*>&handle._handle_data
__pipe_init_uv_handle(<UVStream>handle, loop)

return handle

cdef _new_socket(self):
Expand All @@ -181,11 +175,13 @@ cdef class WriteUnixTransport(UVStream):

cdef class _PipeConnectRequest(UVRequest):
cdef:
uv.uv_connect_t _req_data
UnixTransport transport

def __cinit__(self, loop, transport):
self.request = <uv.uv_req_t*>&self._req_data
self.request = <uv.uv_req_t*> PyMem_Malloc(sizeof(uv.uv_connect_t))
if self.request is NULL:
self.on_done()
raise MemoryError()
self.request.data = <void*>self
self.transport = transport

Expand Down
1 change: 0 additions & 1 deletion uvloop/handles/poll.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
cdef class UVPoll(UVHandle):
cdef:
uv.uv_poll_t _handle_data
int fd
Handle reading_handle
Handle writing_handle
Expand Down
7 changes: 6 additions & 1 deletion uvloop/handles/poll.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ cdef class UVPoll(UVHandle):

self._start_init(loop)

self._handle = <uv.uv_handle_t*>&self._handle_data
self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_poll_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

err = uv.uv_poll_init(self._loop.uvloop,
<uv.uv_poll_t *>self._handle, fd)
if err < 0:
Expand Down
2 changes: 0 additions & 2 deletions uvloop/handles/process.pxd
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cdef class UVProcess(UVHandle):
cdef:
uv.uv_process_t _handle_data

object _returncode
object _pid

Expand Down
10 changes: 8 additions & 2 deletions uvloop/handles/process.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ cdef class UVProcess(UVHandle):

self._start_init(loop)

self._handle = <uv.uv_handle_t*>&self._handle_data
self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_process_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

# Too early to call _finish_init, but still a lot of work to do.
# Let's set handle.data to NULL, so in case something goes wrong,
Expand Down Expand Up @@ -173,7 +177,7 @@ cdef class UVProcess(UVHandle):
'UVProcess._close_after_spawn called after uv_spawn')
self._fds_to_close.add(fd)

def __dealloc__(self):
cdef _free(self):
if self.uv_opt_env is not NULL:
PyMem_Free(self.uv_opt_env)
self.uv_opt_env = NULL
Expand All @@ -182,6 +186,8 @@ cdef class UVProcess(UVHandle):
PyMem_Free(self.uv_opt_args)
self.uv_opt_args = NULL

UVHandle._free(self)

cdef char** __to_cstring_array(self, list arr):
cdef:
int i
Expand Down
1 change: 0 additions & 1 deletion uvloop/handles/signal.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
cdef class UVSignal(UVHandle):
cdef:
uv.uv_signal_t _handle_data
Handle h
bint running
int signum
Expand Down
7 changes: 6 additions & 1 deletion uvloop/handles/signal.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ cdef class UVSignal(UVHandle):

self._start_init(loop)

self._handle = <uv.uv_handle_t*>&self._handle_data
self._handle = <uv.uv_handle_t*> \
PyMem_Malloc(sizeof(uv.uv_signal_t))
if self._handle is NULL:
self._abort_init()
raise MemoryError()

err = uv.uv_signal_init(self._loop.uvloop,
<uv.uv_signal_t *>self._handle)
if err < 0:
Expand Down
Loading

0 comments on commit 7b0b195

Please sign in to comment.