Skip to content

Commit

Permalink
Epoll fix ref #6
Browse files Browse the repository at this point in the history
Rather than creating a new socket on every instance of epoll.wait(),
store the PyType in a std::map and return the original object.
  • Loading branch information
cjhanks committed May 29, 2013
1 parent 05289a7 commit 949df56
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 52 deletions.
2 changes: 1 addition & 1 deletion lib/udt4/pyudt.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

__author__ = 'Christopher J. Hanks <[email protected]>'
__date__ = '12/15/2012'
__version__ = (0, 5)
__version__ = (0, 6)

# assert py-udt4 version is in sync with udt4.pyudt version
# please read __init__.py for explanation of versiong schema
Expand Down
18 changes: 7 additions & 11 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,17 @@
# -----------------------------------------------------------------------
#

VERSION = {
'major' : 0,
'minor' : 5,
'patch' : 1,
}
VERSION = { 'major' : 0
, 'minor' : 6
, 'patch' : 0 }

from distutils.core import setup, Extension
from setuptools import setup, Extension

udt4 = Extension(
'_udt4',
sources = [
'src/py-udt4.cc',
'src/py-udt4-epoll.cc',
'src/py-udt4-socket.cc'
],
sources = [ 'src/py-udt4.cc',
'src/py-udt4-epoll.cc',
'src/py-udt4-socket.cc' ],
include_dirs = ['/usr/local/include', '/usr/include/'],
libraries = ['udt', 'pthread'],
library_dirs = ['/usr/local/lib', '/usr/lib64/', '/usr/lib/'],
Expand Down
48 changes: 13 additions & 35 deletions src/py-udt4-epoll.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
12/18/2012 Initial stub
12/23/2012 Verified and cleaned for release 1.0
05/28/2013 Attempt to fix bad implementation of EPOLL which has
memory leak due to counting.
*/

#include "py-udt4-epoll.hh"
Expand Down Expand Up @@ -52,7 +54,8 @@ pyudt4_epoll_add_usock(pyudt4_epoll_obj *self, PyObject *args)
return 0x0;
}

self->socks.push_back(sock->sock);
Py_INCREF(sock);
self->obj_map[sock->sock] = sock;

if (UDT::ERROR == UDT::epoll_add_usock(self->eid, sock->sock, &flag))
RETURN_UDT_RUNTIME_ERROR;
Expand Down Expand Up @@ -97,6 +100,9 @@ pyudt4_epoll_remove_usock(pyudt4_epoll_obj *self, PyObject *args)
return 0x0;
}

self->obj_map.erase(self->obj_map.find(sock->sock));
Py_DECREF(sock);

if (UDT::ERROR == UDT::epoll_remove_usock(self->eid, sock->sock))
RETURN_UDT_RUNTIME_ERROR;

Expand Down Expand Up @@ -191,24 +197,19 @@ pyudt4_epoll_wait(pyudt4_epoll_obj *self, PyObject *args)
/* UDTSOCKET sets */
for (std::set<UDTSOCKET>::iterator i = usock.read.begin();
i != usock.read.end(); ++i) {
pyudt4_socket_obj *sock =
(pyudt4_socket_obj*)_PyObject_New(pyudt4_socket_type);

sock->sock = *i;
sock->valid = 1;

pyudt4_socket_obj *sock = self->obj_map[*i];

PySet_Add(uset.read, (PyObject*) sock);
Py_INCREF(sock);
}

for (std::set<UDTSOCKET>::iterator i = usock.write.begin();
i != usock.write.end(); ++i) {
pyudt4_socket_obj *sock =
(pyudt4_socket_obj*)_PyObject_New(pyudt4_socket_type);

sock->sock = *i;
sock->valid = 1;

pyudt4_socket_obj *sock = self->obj_map[*i];

PySet_Add(uset.write, (PyObject*) sock);
Py_INCREF(sock);
}

/* SYSSOCKET sets */
Expand All @@ -227,19 +228,6 @@ pyudt4_epoll_wait(pyudt4_epoll_obj *self, PyObject *args)
sset.read, sset.write);
}

static PyObject*
pyudt4_epoll_garbage_collect(pyudt4_epoll_obj *self)
{
for (std::vector<UDTSOCKET>::iterator i = self->socks.begin();
i != self->socks.end(); ++i) {
if (UDT::getsockstate(*i) >= BROKEN)
UDT::epoll_remove_usock(self->eid, *i);
}

self->socks.clear();

Py_RETURN_NONE;
}

static PyMethodDef pyudt4_epoll_methods[] = {
{
Expand Down Expand Up @@ -327,16 +315,6 @@ static PyMethodDef pyudt4_epoll_methods[] = {
" frozenset(write_sys_sockets),\n"
" frozenset(write_sys_sockets))\n"
},
{
"garbage_collect",
(PyCFunction)pyudt4_epoll_garbage_collect,
METH_NOARGS,
"The UDT epoll doesn't track closed UDP sockets (afaik) \n"
"to alleviate the potential resource leak, all UDTSOCKET's\n"
"are tracked. When you execute the garbage_collect, it \n"
"will iterate the sockets and remove the UDTSOCKETS from \n"
"the epoll which are known dead."
},
{ 0x0 }
};

Expand Down
8 changes: 4 additions & 4 deletions src/py-udt4-epoll.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define __PY_UDT_EPOLL_H_

#include <Python.h>
#include <vector>
#include <map>

#include "py-udt4-socket.hh"

Expand All @@ -21,9 +21,9 @@ typedef struct __pyudt4_epoll_obj{

/** epoll id */
int eid;

/** UDTSOCKET eid sets */
std::vector<UDTSOCKET> socks;
/** UDTSOCKET --> PyUDT socket map */
std::map<UDTSOCKET, pyudt4_socket_obj*> obj_map;

} pyudt4_epoll_obj;

Expand Down
2 changes: 2 additions & 0 deletions src/py-udt4-socket.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@author Christopher J. Hanks <[email protected]>
@license py-udt4: GPLv3
libudt4: BSD
05/28/2013 Support udt4.11 new bind:: function for binding to UDP
*/


Expand Down
3 changes: 2 additions & 1 deletion src/py-udt4.cc
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ static PyTypeObject pyudt4_perfmon_type = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
"UDT::TRACEINFO", /* tp_doc */
"UDT::TRACEINFO", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
Expand Down Expand Up @@ -484,6 +484,7 @@ pyudt4_bind(PyObject *py_self, PyObject *args)
if (!PyArg_ParseTuple(args, "Osi", &sock, &address, &port)) {
/* try bind_to_udp */
PyObject *tret = pyudt4_bind_to_udp(py_self, args);

if (0x0 != tret)
return tret;

Expand Down
Empty file added test/__init__.py
Empty file.

0 comments on commit 949df56

Please sign in to comment.